I’m working on a project that’s written in C# and uses a C++ dll to communicate with a robot. Originally the software was written in C# VS 2003 and was converted to VS 2008 (no change to the code) using .Net 2.0. Now, I started seeing the “Attempted to read or write protected memory…” on some computers. The Access violation error is always thrown when the code calls a particular method from the dll, however, that very same method is called over and over throughout the task and executes fine, just sometimes it throws the error. Also, the robot seems to execute the command fine which tells me that the values passed into the dll exist and thus are accessible.
The software with the .Net 1.1 has been used for years and worked fine without ever throwing any memory errors. Now that it has been using .Net 2.0 it throws errors on some computers only.
I’m not sure what’s causing the issue. I ruled out inappropriate calling (incorrect marshalling …) of the dll methods as it has been working fine with .Net 1.1 for years and thus should work fine in .Net 2.0 as well. I’ve seen some posts suggesting that it could be the GC, but then again why would it only happen on this one computer and only sometimes. Also, the values passed in are all global variables in the C# code and thus they should exist until the application is shut down and GC has no business moving any of those around or deleting them. Another observation, as I mentioned above, the robot executes the command normally which means that it gets all its necessary values. Not sure what the C++ dll’s method would do at the end where the GC could mess up stuff. It shouldn’t try to delete the global variables passed in and the method is not modifying those variables either (I’m not expecting any return values through the passed in values, the only return value is the method return which again shouldn’t have anything to do with GC.)
One important piece of information I should add is that I have no access to the C++ code and thus cannot make any changes there.
The fix has to come through the C# code or some settings on the computer or something else that I am in control of.
Any help greatly appreciated.
Thanks.
Code snippet:
Original method call in VS 2003
[DllImport("TOOLB32.dll",EntryPoint="TbxMoveWash")]
public static extern int TbxMoveWash(int tArmId, string lpszCarrierRackId,
int eZSelect, int[] lpTipSet, int tVol, bool bFastW);
which I modified after seeing the error to the following (but the error still occurs):
[DllImport("TOOLB32.dll",EntryPoint="TbxMoveWash")]
public static extern int TbxMoveWash(int tArmId, string lpszCarrierRackId,
int eZSelect, [MarshalAs(UnmanagedType.LPArray, SizeConst = 8)] int[] lpTipSet, int tVol, bool bFastW);
It's possible that the C++ DLL is actually throwing an access violation, so the problem is not in .NET at all. Can you stop when the exception occurs, capture the input and try to reproduce the problem from unmanaged code?
If you're sure it's in the marshalling: the ints are pretty safe, so there are two suspects - the string and the array parameters. If you don't want to receive any data back I'd mark both of those with the [In] attribute, so .NET doesn't even try to marshal the data back. The SizeConst then becomes irrelevant.
If that doesn't fix it try specifying [MarshalAs] for the string, once you (somehow) find out what kind of string the C++ DLL expects. Also, is it ANSI or Unicode? You may want to specify the CharSet in the [DllImport].
It's also possible that this is a bug in the .NET CLR (that was introduced in version 2.0). Does the problem occur with optimisation disabled (Debug build)?
Related
I am working on a rather large codebase in which C++ functionality is P/Invoked from C#.
There are many calls in our codebase such as...
C++:
extern "C" int __stdcall InvokedFunction(int);
With a corresponding C#:
[DllImport("CPlusPlus.dll", ExactSpelling = true, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
private static extern int InvokedFunction(IntPtr intArg);
I have scoured the net (insofar as I am capable) for the reasoning as to why this apparent mismatch exists. For example, why is there a Cdecl within the C#, and __stdcall within the C++? Apparently, this results in the stack being cleared twice, but, in both cases, variables are pushed onto the stack in the same reverse order, such that I do not see any errors, albeit the possibility that return information is cleared in the event of attempting a trace during debugging?
From MSDN: http://msdn.microsoft.com/en-us/library/2x8kf7zx%28v=vs.100%29.aspx
// explicit DLLImport needed here to use P/Invoke marshalling
[DllImport("msvcrt.dll", EntryPoint = "printf", CallingConvention = CallingConvention::Cdecl, CharSet = CharSet::Ansi)]
// Implicit DLLImport specifying calling convention
extern "C" int __stdcall MessageBeep(int);
Once again, there is both extern "C" in the C++ code, and CallingConvention.Cdecl in the C#. Why is it not CallingConvention.Stdcall? Or, moreover, why is there __stdcall in the C++?
Thanks in advance!
This comes up repeatedly in SO questions, I'll try to turn this into a (long) reference answer. 32-bit code is saddled with a long history of incompatible calling conventions. Choices on how to make a function call that made sense a long time ago but are mostly a giant pain in the rear end today. 64-bit code has only one calling convention, whomever is going to add another one is going to get sent to small island in the South Atlantic.
I'll try to annotate that history and relevance of them beyond what's in the Wikipedia article. Starting point is that the choices to be made in how to make a function call are the order in which to pass the arguments, where to store the arguments and how to cleanup after the call.
__stdcall found its way into Windows programming through the olden 16-bit pascal calling convention, used in 16-bit Windows and OS/2. It is the convention used by all Windows api functions as well as COM. Since most pinvoke was intended to make OS calls, Stdcall is the default if you don't specify it explicitly in the [DllImport] attribute. Its one and only reason for existence is that it specifies that the callee cleans up. Which produces more compact code, very important back in the days when they had to squeeze a GUI operating system in 640 kilobytes of RAM. Its biggest disadvantage is that it is dangerous. A mismatch between what the caller assumes are the arguments for a function and what the callee implemented causes the stack to get imbalanced. Which in turn can cause extremely hard to diagnose crashes.
__cdecl is the standard calling convention for code written in the C language. Its prime reason for existence is that it supports making function calls with a variable number of arguments. Common in C code with functions like printf() and scanf(). With the side effect that since it is the caller that knows how many arguments were actually passed, it is the caller that cleans up. Forgetting CallingConvention = CallingConvention.Cdecl in the [DllImport] declaration is a very common bug.
__fastcall is a fairly poorly defined calling convention with mutually incompatible choices. It was common in Borland compilers, a company once very influential in compiler technology until they disintegrated. Also the former employer of many Microsoft employees, including Anders Hejlsberg of C# fame. It was invented to make argument passing cheaper by passing some of them through CPU registers instead of the stack. It is not supported in managed code due to the poor standardization.
__thiscall is a calling convention invented for C++ code. Very similar to __cdecl but it also specifies how the hidden this pointer for a class object is passed to instance methods of a class. An extra detail in C++ beyond C. While it looks simple to implement, the .NET pinvoke marshaller does not support it. A major reason that you cannot pinvoke C++ code. The complication is not the calling convention, it is the proper value of the this pointer. Which can get very convoluted due to C++'s support for multiple inheritance. Only a C++ compiler can ever figure out what exactly needs to be passed. And only the exact same C++ compiler that generated the code for the C++ class, different compilers have made different choices on how to implement MI and how to optimize it.
__clrcall is the calling convention for managed code. It is a blend of the other ones, this pointer passing like __thiscall, optimized argument passing like __fastcall, argument order like __cdecl and caller cleanup like __stdcall. The great advantage of managed code is the verifier built into the jitter. Which makes sure that there can never be an incompatibility between caller and callee. Thus allowing the designers to take the advantages of all of these conventions but without the baggage of trouble. An example of how managed code could stay competitive with native code in spite of the overhead of making code safe.
You mention extern "C", understanding the significance of that is important as well to survive interop. Language compilers often decorate the names of exported function with extra characters. Also called "name mangling". It is a pretty crappy trick that never stops causing trouble. And you need to understand it to determine the proper values of the CharSet, EntryPoint and ExactSpelling properties of a [DllImport] attribute. There are many conventions:
Windows api decoration. Windows was originally a non-Unicode operating system, using 8-bit encoding for strings. Windows NT was the first one that became Unicode at its core. That caused a rather major compatibility problem, old code would not have been able to run on new operating systems since it would pass 8-bit encoded strings to winapi functions that expect a utf-16 encoded Unicode string. They solved this by writing two versions of every winapi function. One that takes 8-bit strings, another that takes Unicode strings. And distinguished between the two by gluing the letter A at the end of the name of the legacy version (A = Ansi) and a W at the end of the new version (W = wide). Nothing is added if the function doesn't take a string. The pinvoke marshaller handles this automatically without your help, it will simply try to find all 3 possible versions. You should however always specify CharSet.Auto (or Unicode), the overhead of the legacy function translating the string from Ansi to Unicode is unnecessary and lossy.
The standard decoration for __stdcall functions is _foo#4. Leading underscore and a #n postfix that indicates the combined size of the arguments. This postfix was designed to help solve the nasty stack imbalance problem if the caller and callee don't agree about the number of arguments. Works well, although the error message isn't great, the pinvoke marshaller will tell you that it cannot find the entrypoint. Notable is that Windows, while using __stdcall, does not use this decoration. That was intentional, giving programmers a shot at getting the GetProcAddress() argument right. The pinvoke marshaller also takes care of this automatically, first trying to find the entrypoint with the #n postfix, next trying the one without.
The standard decoration for __cdecl function is _foo. A single leading underscore. The pinvoke marshaller sorts this out automatically. Sadly, the optional #n postfix for __stdcall does not allow it to tell you that your CallingConvention property is wrong, great loss.
C++ compilers use name mangling, producing truly bizarre looking names like "??2#YAPAXI#Z", the exported name for "operator new". This was a necessary evil due to its support for function overloading. And it originally having been designed as a preprocessor that used legacy C language tooling to get the program built. Which made it necessary to distinguish between, say, a void foo(char) and a void foo(int) overload by giving them different names. This is where the extern "C" syntax comes into play, it tells the C++ compiler to not apply the name mangling to the function name. Most programmer that write interop code intentionally use it to make the declaration in the other language easier to write. Which is actually a mistake, the decoration is very useful to catch mismatches. You'd use the linker's .map file or the Dumpbin.exe /exports utility to see the decorated names. The undname.exe SDK utility is very handy to convert a mangled name back to its original C++ declaration.
So this should clear up the properties. You use EntryPoint to give the exact name of the exported function, one that might not be a good match for what you want to call it in your own code, especially for C++ mangled names. And you use ExactSpelling to tell the pinvoke marshaller to not try to find the alternative names because you already gave the correct name.
I'll nurse my writing cramp for a while now. The answer to your question title should be clear, Stdcall is the default but is a mismatch for code written in C or C++. And your [DllImport] declaration is not compatible. This should produce a warning in the debugger from the PInvokeStackImbalance Managed Debugger Assistant, a debugger extension that was designed to detect bad declarations. And can rather randomly crash your code, particularly in the Release build. Make sure you didn't turn the MDA off.
cdecl and stdcall are both valid and usable between C++ and .NET, but they should consistent between the two unmanaged and managed worlds. So your C# declaration for InvokedFunction is invalid. Should be stdcall. The MSDN sample just gives two different examples, one with stdcall (MessageBeep), and one with cdecl (printf). They are unrelated.
I've asked a question here before, about protecting an application from being stolen and I've got an answer.
I decided to use confuserEX which is free and works fine with WPF. But when I checked the documentation, I noticed that it renames all the strings in the code with other meaningless strings.
My question is that, if any string is replaced with another meaningless string how can I used my own dll to access public members or functions of a class inside it?
Public types and members are generally not obfuscated, so if there is code in your DLL that your app can call into from the outside, chances are that anyone else can call into it. There's not much you can do about that. If you have code that you don't want someone reverse engineering, then have that code run on a server that you control, as #Habib suggests.
I have a (C#) function similar to the following.
private static bool SpecialCase = false;
public void Foo()
{
if (SpecialCase)
{
InternalMethod();
return;
}
Console.WriteLine();
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void InternalMethod();
When I execute this with the .NET Framework 4 inside the debugger, the method successfully prints blank line to the console and returns. When I execute it outside the debugger, it throws an exception with the following message:
System.Security.SecurityException: ECall methods must be packaged into a system module.
It appears the exception is thrown when the JIT compiler compiles the method as opposed to when (if) InternalMethod is called. Is there anything I can do (e.g. attributes) to tell the CLI to either not throw the SecurityException, or delay the exception until the method is actually called?
Side note on the use case: The SpecialCase field is effectively false when running with Microsoft .NET Framework, and true when running under a different (specific) implementation of the CLI. When running under the Microsoft .NET Framework, the call to InternalMethod is effectively unreachable.
Add attribute [ComImport] to your class declaration
You may want to check the compiler directives as a possible option.
Unlike using a run-time "if", this will determine whether the call is included in the compiled code at all, rather than always compiling it into the code and trying to determine whether to call it at run-time (which is too late, based on your analysis).
Your use-case seems like a testing/validation scenario, which means that you don't need it compiled into the code except when the internal call will actually be made.
Note that if your use-case involves a non-.NET runtime, you should provide more information since that could drastically change the correct answer.
What does this error mean in VB6?
Function or interface marked as restricted, or the function uses an Automation type not supported in Visual Basic.
I keep getting it when i call a particular method of a dll that comes with windows xp and beyond (in system32 called upnp.dll)
This is the declaration for FindByType() as retrieved from the type library:
HRESULT FindByType(
[in] BSTR bstrTypeURI,
[in] unsigned long dwFlags,
[out, retval] IUPnPDevices** pDevices);
Note the 2nd argument, unsigned long. VB6 doesn't support unsigned types. It is not a problem in VB.NET or C#, they do support them.
This problem is fixable if you have the Windows SDK installed. You should have it if you have a recent version of Visual Studio. Use the Visual Studio Command Prompt, then:
run oleview.exe c:\windows\system32\upnp.dll
type Ctrl+A, Ctrl+C to copy the type library content
run notepad.exe, Ctrl+V. Search for "unsigned" and delete it. There are two.
save the file to a temporary directory with the name upnp.idl
run midl upnp.idl /tlb upnp.tlb
copy the generated upnp.tlb to your project directory
You can now add upnp.tlb instead of upnp.dll, you should no longer get the error.
-
Well, the error message means that you're calling a function that can't be bound by VB6, possibly due to it have parameters or a return value of a data type that VB6 doesn't support. I sometimes worked around issues like this by writing a simple C++ COM object that called the function and "translated" it to be VB6 compatible.
You can sometimes also get this error message due to various typos, but I think you've already discovered that with your search on google so I'm assuming you've already checked for that.
If you post your code (or at least the name of the function that you're having problems with) it's possible that you could get a better answer.
I got the same error but when I changed my array name the error went away.
"Map" apparently isn't an acceptable array name.
error code: map(day, min) = Trim(Str(Int(r / 1000)))
no error code: mapsymbol(day, min) = Trim(Str(Int(r / 1000)))
Since my game, which I'd really like to be Mono-usable, does not seem to run under Linux because LuaInterface is being a jerk (see the the relevant SO thread for more on that), I've decided to do what's suggested there. I wrote my own Lua511.LuaDLL class to reflect the one used by LuaInterface, replacing every single public function with its respective DllImport from lua51:
//For example, like this:
[DllImport("lua51")]
public static extern IntPtr luaL_newstate();
With the edited LuaInterface.dll (which now hosts its own Lua511.LuaDLL) and a pure, native Win32 lua51.dll in my game's startup folder, I somehow get a DllNotFoundException when LuaInterface tries initialize:
public Lua()
{
luaState = LuaDLL.luaL_newstate(); //right there, right then.
...
Ofcourse, with the DLL right there it shouldn't do that, right? Strangely, putting back the messed-up .Net version of lua51.dll gives an EntryPointNotFoundException instead. The mind boggles.
So what's up with that?
Relevant source code: Lua511.cs, dropped it in the LuaInterface project, then removed the reference so it'd be replaced.
Edit: Screw this, I'm gonna look for alternatives. Or roll my own. Or just stop caring about Linux compatibility.
You referenced my question. I took the other way to solve the problem and started to develop a new Lua .NET interface. I called it Lua4Net.
You can find the sources on Google hosting. And here the unit tests.
Currently implemented features: Execute code with exception handling and provide the return values; register global functions with parameter handling.
Features that will follow: Get/set global variables; debugging support, ...
You can find the used native windows DLL here (it is the renamed VC++ 9.0 DLL from here).
AND: Today I ran my first Linux/Mono tests, and all my unit tests worked!!!
AFAIK mono uses .so extension for native libraries under Linux by default.
Try to rename your lua51.dll to lua51.so or change dllname in DllImport attribute. Or use dllmap.