views:

495

answers:

4

When calling an unmanaged Dll from a c# application I get an AccessViolationException. The strange thing is that the exported function has no arguments, so the problem is not in the Marshalling of data. The function gets no argument and just returns an integer. Also note that calling convention is not an issue. An identical function with the same zero arguments and integer return value (but different name) works just fine. What are the remaining candidate reasons that such a call could cause this exception considering the fact that marshalling and calling convention is ruled out?

UPDATE: The dll function is correct because if called from other unmanaged code through plain linking, then it works perfectly.

UPDATE 2: Everything is compiled and run on 32 bit. I tried Win XP SP2 and Vista. Here is an interesting fact: On Vista Systems it works like a charm. On XP it fails.

UPDATE 3: I didnt get the source code but I learned what essentially this dll does, so i tried to reproduce the problem with my own dll. Here is the story: The original dll is some kind of a wrapper to ei.lib (Erlang's c interface library). It exports some helper funcs. So to reproduce the problem I have made a wrapper dll around ei.lib which exports only one function, namely "test()". I did that so I wouldnt mess with marshalling and stuff. I wanted just to test an initialization, connecting and sending a message. So this test() func of my dll just calls ei_connect_init(), then ei_connect() and finaly ei_reg_send(), with arguments hardcoded inside. The problem is that if I call this dll and use the test() function from another unmanaged code, it works ok. Message is sent. But when I call it from c# through DllImport then it works only on Vista. Not on XP. On XP it fails with a AccessViolationException on the .net layer. I ve tried to trace down the problem and I see that from inside my dll, any call to ei_connect(), or any attempt to read erl_errno (these are defined in ei.lib) when running on XP and being called by managed code result in trying to read or write protected memory so the app crashes. It cant be something trivial since it works on Vista and it works when called by unmanaged code.

A: 

This exception occurs when the unmanaged code causes a memory access violation. Check to see that the unmanaged function is correct. If you have the source for the unmanaged code you can also enable the debugger to step into the unmanaged code and see where the problem is.

David Lynch
no, this is not the problem... See my update :(
Paralife
also, i dont have access to source code, i ll try to get at least the object with debug info and give the debugger a shot.
Paralife
Does the unmanaged library have some sort of static initialization function that should be called before use? Also make sure that there is no 32 <-> 64 bit mismatch. If the unmanaged code is 32 bit and the managed is running as 64 you might also get this exception.
David Lynch
I used the unmanaged dll in the c# by calling it exaclty the same way as called by an unmanaged test app. 1 call of the offending function. How could c# call affect a static initialization in a way different than the call from the unmanaged test app?
Paralife
Some libraries require you to call a static init function before use, it sounds like yours does not.Did you investigate the other suggestion? I have had issues in the past calling unmanaged 32 bit code when the managed assembly is built with the platform target equal to AnyCPU and then run on a 64 bit OS.
David Lynch
I checked for 32-64 issue but it doesnt have to do with it. See my 2nd update...
Paralife
A: 

I have the same problem.

It's fine to run my application with an unmanaged dll on my computer(Vista sp1 .net 3.5). This AccessViolationException exists often when I try on others computers(Vista sp2 .net 3.5). Any ideas? How can I fix it?

thx

Lert Pianapitham
you have this problem specifically with ei interface or generally with any unmannaged dll?
Paralife
I think I found the problem. Check my answer...
Paralife
A: 

OK I think i know the problem: the ei.lib uses TLS (Thread Local Storage). In the file ei_pthreads.c of the ei interface source code there is this snippet:

#ifdef __WIN32__
#ifdef USE_DECLSPEC_THREAD
/* Define (and initialize) the variable __erl_errno */
volatile __declspec(thread) int __erl_errno = 0;
#else
static volatile DWORD errno_tls_index = TLS_OUT_OF_INDEXES;
static LONG volatile tls_init_mutex = 0;
#endif
#endif

If USE_DECLSPEC_THREAD is not defined then, lower in the source file, TLS Api is used instead. Now, from msdn i found that:

On Windows operating systems before Windows Vista, __declspec( thread ) has some limitations. If a DLL declares any nonlocal data or object as __declspec( thread ), it can cause a protection fault if dynamically loaded. After the DLL is loaded with LoadLibrary, it causes system failure whenever the code references the nonlocal __declspec( thread ) data. Because the global variable space for a thread is allocated at run time, the size of this space is based on a calculation of the requirements of the application plus the requirements of all the DLLs that are statically linked. When you use LoadLibrary, you cannot extend this space to allow for the thread local variables declared with __declspec( thread ). Use the TLS APIs, such as TlsAlloc, in your DLL to allocate TLS if the DLL might be loaded with LoadLibrary.

So , since I use the erl interface libs provided with the precompiled binary distribution of erlang for windows, I wonder if they defined USE_DECLSPEC_THREAD when compiling those binaries. If not then I am in dead end and I will try something else to do my job with. If they did define it then I must install cygwin and recompile the sources without defining it. (Yikes...).

FINAL UPDATE: Indeed this was the problem. I had to install cygwin and compile the erl_interface code again without defining USE_DECLSPEC_TRHEAD. Also there is another little catch when recompiling, a tiny change is needed so that definition of _WIN32_WINNT happens before inclusion of winbase.h because after the omission of USE_DECLSPEC_THREAD the code uses SwitchToThread which is defined in winbase.h only if _WIN32_WINNT is defined and with a value greater than 0x400.

Paralife
A: 

sorry, i didn't explane all details.

I am trying to use an old unmanaged dll in my VBE2008 Project. This dll was programmed by Fortran to calculate some important values and it's impossible to see the code or reproduce.

My application works fine on my computers (3 Vista sp1 and 2 XP sp3 / all with .net framwork 3.5), but after the sp2 update for 2 of Vista machines, it throws often (not every time) an AccessViolationException on those 2 machines. The error message is: "Attempt to read or write protected memory. This is often an indication that other memory is corrupt."

I have checked and found that the exception was thrown by the dll calling function. My code looks like this:

<DllImport("abc.dll", EntryPoint:="abc", _
SetLastError:=True, CharSet:=CharSet.Ansi, _
ExactSpelling:=True, llingConvention:=CallingConvention.StdCall)> _
Private Shared Sub abc(ByVal input as integer)
End Sub

The dll is in the same directory with my app and I have tried with the absolute reference like "c:\abc.dll".

So, I cannot understand your solution in C#. Could you please explane me the solution in VB?

thx.

Lert Pianapitham
The exception that is thrown from managed code does not mean that the managed code is the source of the problem. If you have debug version of the unmanaged dll you should try to trace the source of the problem. And even if you do trace it , sometimes it is misleading because there can be a misuse of memory in some point of the code but the bug manifests itself in another seemingly irrelevant point. You should check the basics first: Correct calling convention, marshalling etc.. But since you say that the bug does not happen everytime, first thing I would do is try to reproduce it.
Paralife
I would also try do make the same use of the dll from unmanaged code at least to see if the problem has anything to do with PInvoke in some way. My problem seems to be different from yours because mine worked on Vista only and nowhere else . This, along with the fact that it manifested only when calling from managed code led me to the article on msdn which was a perfect fit. I wish I could help you more. Keep ruling out cases and hopefully you will nail it.
Paralife
If you post the code and the dll somewhere i ll give it a try if I can
Paralife
Hi Paralife,thank for your answer.Sorry ... I cannot give you the dll due to the Program's licence. But i think you can have one from internet if you want to do a search. It's name RefProp.dll. I will try to uninstall the updates in this month and see my program running.thanks againLert
Lert Pianapitham