Mapping IntPtr into Struct via Marshal.PtrToStructure causing "Access Violation Exception" - c#

I'm trying to use a C++ DLL (3rd party library implementing EMI protocol, having source code available) in .NET. I've succesfully done marshalling, calling the functions and getting everything work fine.
The problem occurs when I want to do marshalling from IntPtr back into the .NET Struct , here's the code (modified as suggested - removed "ref" and changed the AllocHGlobal to allocate just size of emiStruct) :
private EMI emiStruct;
private IntPtr emiIntPtr;
emiIntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(emiStruct));
Marshal.StructureToPtr(emiStruct, emiIntPtr, false);
EMIStruct.Error result = emi_init(emiIntPtr, hostname, portNumber, password, shortNumber, windowSize, throughput);
Marshal.PtrToStructure(emiIntPtr, emiStruct);
The last line (PtrToStructure) causes an exception "Attempted to read or write protected memory. This is often an indication that other memory is corrupt".
Also, I can see a debug output:
A first chance exception of type 'System.AccessViolationException' occurred in mscorlib.dll
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0xc3fffff8.
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0x01fffff7.
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0x00001f1d.
I assume the problem is somewhere in allocation of memory for the pointer emiIntPtr. Althought, when I run the code, and there is a problem with connecting to the server (e.g. server not found), the followed marshalling to the Struct emiStruct is done correctly (no exception). The problem only occurs when the connection is succesfully established and server send a respond.
Also, I wrote a C++ sample app using the same DLL library I'm trying to use in .NET, and this application (when I compile it) runs just fine - it means, the C++ DLL should be ok and not causing crashing.
Furthermore, I've found some hints to check/uncheck several properties for the project compilator (using JIT, compile it for x86 cpu, etc.), unfortunately, none of this helped.
Do you have any suggestion where the problem might be or how to do a correct IntPtr inicialization in .NET and mapping between IntPtr and Struct?
Thanks all for your replies:
Here I'm adding the C++ header of the emi_init func:
FUNC( init)( EMI* emi, /* out */
const char* hostname, /* in */
unsigned short port, /* in */
const char* password, /* in */
const char* origin_addr, /* in */
int window_sz, /* in */
int throughput); /* in */
And here is the C# emi_init declaration (I've removed the "ref" attribute for emiPtr as was suggested):
[System.Runtime.InteropServices.DllImport("emi.dll", EntryPoint = "_emi_init")]
public static extern EMIStruct.Error emi_init(
System.IntPtr emiPtr,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string hostname,
ushort port,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string password,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string origin_addr,
int window_sz, int throughput);
However, still getting the same exception.

You are using Marshal.PtrToStructure incorrectly.
The second argument requires a type, iow typeof(EMI).
The return value contains the resulting struct.
So the solution should be:
var s = (EMI) Marshal.PtrToStructure(emiIntPtr, typeof(EMI));

My guess is that you have declared the first parameter incorrectly in the C#. You have declared it as ref IntPtr which is equivalent to EMI** in C++. But I bet the C++ declaration, which you unfortunately did not include, reads EMI*. So simply remove the ref and all should be well.
I expect that emi_init does not read from the EMI parameter, i.e. it has out semantics. In which case you don't need the StructureToPtr call before you call emi_init.

Related

How to safely pass string reference from c# to c++?

I am developing a C# dll project with C++ dll project.
Let's say that C++ dll logins to a certain web site, and do some query on the web server.
And C++ dll has to return that html code of a web site.
In the same time, C++ dll must save the cookie data from the web site.
So, I passed StringBuilder object to C++ function.
I already know how to get html code from a web site using HttpWebRequest and HttpWebResponse classed in C#, but unfortunately I have to do it in C++ dll project.
So bear in mind, I don't need any C# codes.
I have tried Passing a string variable as a ref between a c# dll and c++ dll.
Passing StringBuilder from C# and get it as LPTSTR.
It works fine, but some strings were missing from the result.
I couldn't find out the reason.
Anyway, here is my code.
C++
extern "C" __declspec(dllexport) BSTR LoginQuery(const char* UserID, const char* UserPW, char Cookies[])
{
std::string html;
try
{
std::map<std::string, std::string> cookies;
MyClass *myclass = new MyClass();
html = myclass->LoginQuery(UserID, UserPW, cookies);
// Response cookies
std::string cookieData;
for (std::map<std::string, std::string>::iterator iterator = cookies.begin(); iterator != cookies.end(); iterator++)
{
cookieData += iterator->first;
cookieData += "=";
cookieData += iterator->second;
cookieData += ";";
}
sprintf(Cookies, cookieData.c_str(), 0);
delete myclass;
}
catch (...)
{
}
return ::SysAllocString(CComBSTR(html.c_str()).Detach());
}
C#
[DllImport(#"MyDll.dll", EntryPoint="LoginQuery", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern void LoginQuery(string UserID, string UserPW, StringBuilder Cookies);
void SomeThing()
{
StringBuilder _cookies = new StringBuilder(1024);
string result = LoginQuery("test", "1234", _cookies);
}
It works fine.
With the StringBuilder as cookie, I can carry on the next url of the web site.
(I am using libcurl in C++ project.)
But the problem is that I have about 100 ids.
When it runs about 3~40, it returns heap error.
Debug Assertion Failed!
Program: ~~~~mics\dbgheap.c
Line: 1424
Expression: _pFirstBlock == pHead
I cannot click the abort, retry or ignore button.
It looks like C# application hangs.
I read so many articles about debug assertion failed with dbgheap.
Mostly like free memory object from another heap.
I am newbie to C++.
I read Edson's question on http://bytes.com/topic/c-sharp/answers/812465-best-way-interop-c-system-string-c-std-string.
But the error does not always comes out in certain time.
So I came across with a guess, that it happens when .NET runs garbage collector.
.NET garbage collector tries to free some memory which created from C++ dll and I get the heap error.
Am I right?
I think he's suffering same problem as mine.
What is the best way to avoid heap error and return correct string from C++ dll to C# dll?
P/S: And the heap error occurs only when I run it debug mode. I don't get the error when I run release mode.
EDIT
According to WhozCraig answer, I changed my code as below.
//return ::SysAllocString(CComBSTR(html.c_str()).Detach());
CComBSTR res(html.c_str());
return res.Detach();
But no luck, I still get the heap error.
Your question is title asks about passing a string reference from c# to c++, but later in the text you ask how to return a string from C++ to C#. Also, you tell you are new to C++. With this in mind, I'll tell how I did this sort of interaction last time I had to do that. I just made C++ side allocate and free all the memory, passing out to C# only IntPtrs to be Marshal.PtrToStringAnsi(p)ed. In my case, storing recerences thread-local in C++ and freeing them on each function call was enough, but you can make a C++ function that frees whatever ref it is given. Not very intellectual and not necessarily the most efficient way, but it works.
upd:
It does just what they say it does. Some quick googling comes up with this article. I think it's pretty good, so you can refer to it instead of my suggestion. Passing raw IntPtrs is good if the pointer is not okay to be freed by itself (like old Delphi/C++Builder style strings, for example) and you prefer to be bothered more on the managed side than on the native side.
As an example, piece of code doing Delphi interaction (good for C++ Builder as well):
// function Get_TI_TC(AuraFileName:PAnsiChar; var TI,TC:PAnsiChar):Boolean; stdcall; external 'AuraToIec104.dll' name 'Get_TI_TC';
[DllImport("AuraToIec104")]
[return: MarshalAs(UnmanagedType.I1)]
private static extern bool Get_TI_TC(string AuraFileName, out IntPtr TI, out IntPtr TC);
public static bool Get_TI_TC(string AuraFileName, out string TI, out string TC)
{
IntPtr pTI, pTC;
bool result = Get_TI_TC(AuraFileName, out pTI, out pTC);
TI = Marshal.PtrToStringAnsi(pTI);
TC = Marshal.PtrToStringAnsi(pTC);
return result;
}
It looks like your problem is rather simple. You are creating a StringBuilder that can hold as much as 1024 chars. If your C++ function returns more than that, your application will crash (sooner or later).
So to fix your problem, increase the StringBuilder's size to the maximum possible output length. More details: Passing StringBuilder to PInvoke function which quotes:
The only
caveat is that the StringBuilder must
be allocated enough space for the
return value, or the text will
overflow, causing an exception to be
thrown by P/Invoke.
It might actually be better in your case with dynamic string lengths to use a BSTR parameter in the C++ function. You can then use [MarshalAs(UnmanagedType.AnsiBStr), Out] ref string ... in C# and BSTR* in C++.

Getting Ptr Value of a Function

I have an API function in my application:
<Runtime.InteropServices.DllImport("kernel32.dll", SetLastError:=True, CharSet:=Runtime.InteropServices.CharSet.Ansi, ExactSpelling:=True)>
Private Shared Function GetProcAddress(ByVal hModule As IntPtr, ByVal procName As String) As IntPtr
End Function
I just want to learn the pointer 'IntPtr' value of this function. How can I do it?
Note: I will show you the exact thing that I want in C++
void* fnGetProcAddress;
fnGetProcAddress = GetProcAddress;
Well, you can continue using P/Invoke...
(Note, this is in C#, but easily convertible)
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string moduleName);
var hModule = GetModuleHandle("kernel32.dll");
var procAddress = GetProcAddress(hModule, "GetProcAddress");
I want to get this address and write it in a BinaryStream as UInt32
This is a very troublesome plan. Short from the wrong data type, you have no guarantees whatsoever that the address you write is still valid when you read the stream:
The DLL might simply not be loaded when you read the stream. It does require making the LoadLibrary() call to get it in the process. So at a very minimum you'd also have to serialize the DLL path.
DLLs do not promise to get loaded at the exact same address again. The load address embedded in the DLL header is merely a request, it is very common that the requested address is already in use by another DLL, forcing Windows to relocate the DLL. That relocated address is not predictable. A far bigger problem is that relocation is intentionally done on modern Windows versions. A feature called Address Space Layout Randomization, enabled when the DLL was linked with the /DYNAMICBASE linker option. It is an anti-malware feature, making it intentionally hard for malware to patch code.
Surely there's a better way to do what you want to do. You however made the common mistake of not explaining your reasons, it is impossible to guess at.

COM interface modifications have suddenly started causing exceptions

A couple of years ago I inherited a C# app that uses COM objects defined in an unmanaged C++ DLL. I've been successfully tweaking the object interfaces ever since, but following a (possibly irrelevant) VS2012 upgrade, function signature additions and changes are suddenly being punished by random exceptions such as ExecutionEngineException and SEHException.
My understanding was that the app uses registration-free COM. There's no DLLRegisterServer implementation, and I see no mention of the interface guids in the registry, just one in C#...
[ComImport,
Guid("C2427CB1-D6AE-49e8-B266-114F981C3353"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
SuppressUnmanagedCodeSecurity()]
public interface IDC
{
and one in a C++ header.
interface __declspec(uuid("C2427CB1-D6AE-49e8-B266-114F981C3353"))
IDC : IUnknown
{
To be sure though, I decided to swap a new guid into these two places, and discovered that it stopped C# from recognizing the class at all:
System.InvalidCastException
Unable to cast COM object of type 'System.__ComObject' to interface type 'Apx.IDC'.
This operation failed because the QueryInterface call on the COM component for the
interface with IID '{the new guid}' failed due to the following error:
No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
(The above error is apparently often caused by mixing appartment states, but swapping a guid doesn't cause that). So I deduce there must be additional relevant detail somewhere that's conflicting with my changes. But where might that somewhere be? Thanks for reading...
Edit:
An example exception is...
First-chance exception at 0x000007feec748be4 (clr.dll) in Apex.exe: 0xC0000005:
Access violation reading location 0xffffffffffffffff.
The Common Language Runtime cannot stop at this exception. Common causes include:
incorrect COM interop marshalling, and memory corruption. To investigate further,
using native-only debugging.
An unhandled exception of type 'System.ExecutionEngineException' occurred in Apex.exe
for
[PreserveSig] [return: MarshalAs(UnmanagedType.I1)]
bool LoadDisplayList(IntPtr fileHandle, IntPtr pDisplayList,
UInt16 version, IntPtr pComparison);
and
virtual bool __stdcall LoadDisplayList(HANDLE fileHandle, class CDisplayList * pDisplayList,
WORD version, CDisplayList * pComparison) = 0;
with a stack trace ending
[Native to Managed Transition]
Apex.Graphics64.dll!CDisplayList::LoadRenderRecs(void * f=0x000000000000056c, CDisplayList * pComparison=0x0000000023ad2cf0) Line 1772 C++
Apex.Graphics64.dll!CDisplayList::Load(void * f=0x000000000000056c, unsigned short version=0x0002, CDisplayList * pComparison=0x0000000023ad2cf0) Line 1845 + 0x26 bytes C++
Apex.Graphics64.dll!CBaseDC::LoadDisplayList(void * f=0x000000000000056c, CDisplayList * pList=0x0000000023ad2cf0, unsigned short version=0x0002, CDisplayList * pComparison=0x0000000023ad2cf0) Line 1896 + 0x33 bytes C++
[Managed to Native Transition]
Apex.exe!Apex.DDC.LoadDisplayList(System.IO.FileStream file = {System.IO.FileStream}, Apex.DisplayList displayList = {Apex.DisplayList}, ushort version = 0x0002, Apex.DisplayList comparison = null) Line 1124 + 0xaf bytes C#
Apex.exe!Apex.DisplayList.Load(System.IO.FileStream f = {System.IO.FileStream}, ushort loadVersion = 0x0002, Apex.INode stubsRoot = {Apex.ViewPort3D}, Apex.DisplayList comparison = null) Line 166 + 0x53 bytes C#
The exact crash point varies somewhat - here it actually managed to get inside LoadDisplayList(), which is better than usual. As the crash suggests heap damage, I've tried stripping the function's signature down to a parameterless void return, reduced its contents to a trace, and called it right after the object's creation - still to get a crash. The same function doesn't crash if I move it to the top of the definitions, in which case some other interface function crashes out instead, leading me to think it's more likely to be a COM problem than algorithm-level memory corruption.
I think I've fixed the problem. Once I was able to step into the DLL a little, a popup saying that the source didn't match the executable led me to investigate another longstanding but previously unproblematic quirk, that the DLL's Linker / General / Output File wasn't inside the project's General / Output Directory (warning MSB8012). After cleaning up this anomaly I was able change the guid successfully, so it seems VS2012 uses these settings slightly differently to older versions. The moral...don't let warnings hang around.

"Win32Exception: The operation completed successfully" after WTSQueryUserToken on 32bit Windows (64bit works)

I'm developing a small Windows Service in C# that needs to do interop with Win32 API at some point. I'm getting the following exception which does not make sense to me:
System.ComponentModel.Win32Exception: The operation completed successfully
Right after the last line in this C# snippet:
var sessionId = Kernel32.WTSGetActiveConsoleSessionId();
var userTokenPtr = new IntPtr();
if (!WtsApi32.WTSQueryUserToken(sessionId, out userTokenPtr))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
Here's how I'm declaring WTSQueryUserToken in WtsApi32:
[DllImport("Wtsapi32.dll", EntryPoint="WTSQueryUserToken")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool WTSQueryUserToken
(
[In, MarshalAs(UnmanagedType.U8)] ulong sessionId,
[Out] out IntPtr phToken
);
Some facts:
This works perfectly on 64bit Win7, but fails on a 32bit Win7.
There's no way the 10,000 handle limit has been reached when this is executed, it's the first Win32 call in a very small windows service.
I think there might be some underlying Win32 error but some bug overwrote the errorcode with a 0, thus giving me the "success" error message, but I don't know how to confirm or even diagnose this.
When I catch the exception, sessionId is 1 and userTokenPtr is 0. However, GetLastError returns 0 so I have no idea what happened.
Nearly all of the answers I found to this problem had to do with improper disposal of user controls. Since this is a Windows service, this is not the case.
I'm guessing there must be something wrong with my WTSQueryUserToken declaration, since it only fails on 32bit Windows, which leads me to think it's a marshaling problem. However, I still can't see what it might be.
Your sessionId parameter us defined as a c# ulong - an unsigned 64-bit integer, whereas the actual function export is expecting a Win32 ulong - an unsigned 32-bit integer.
c# ulong data type
Win32 data types

P/Invoke sometimes cause Win32 1008 Error with StringBuilder parameters

I have a DLL from which I need to P/Invoke the following C method:
int DAStart(
HANDLE hOpen,
char* IPAddress,
int IPPort,
int threadPriority,
char* name,
char* password,
char* userName)
Using the P/Invoke Assistant and my own research, I've come up with the following C# signature:
[DllImportAttribute("<libName>", EntryPoint="DAStart")]
static extern int DAStart(
IntPtr hOpen,
[MarshalAs(Unmanaged.LPStr)] StringBuilder IPAddress,
int IPPort,
int threadPriority,
[MarshalAs(Unmanaged.LPStr)] StringBuilder name,
[MarshalAs(Unmanaged.LPStr)] StringBuilder password,
[MarshalAs(Unmanaged.LPStr)] StringBuilder userName);
Now, I'm doing the call in the following way:
int port = 3000;
int threadPriority = 20;
DAStart(
this.nativeDllHandle, // an IntPtr class field
new StringBuilder("10.0.10.1"),
int port,
int threadPriority,
new StringBuilder("admin"),
new StringBuilder("admin"),
new StringBuilder("admin"));
Now, sometimes this works just fine, but something I get a Win32 Error 1008 - An attempt was made to reference a token that does not exist on following calls to this library.
Could it be that my StringBuilder objects get garbage collected so that the reference no longer exist if the native code tries to use it? Should I keep a reference for each one of them?
Would an IntPtr be better solution for passing my strings in that case?
** UPDATE **
This is all the API documentation I have for DAStart:
Inputs
HANDLE hInfo The handle returned by the DAOpen
char *IPAdress_in IP Address of the TMEE Server
int IPPort Console Port of the TMEE Server (default is port 3000)
int threadPriority The thread priority for the send file thread.
char *name Not used in Hardware DLL
char *password Not used in Hardware DLL
char *username Not used in Hardware DLL
Returns
ERROR_SUCCESS 0
ERROR_BAD_HANDLE -1
ERROR_BIND_FAILED -10
Comments
The DAStart API connects the client dll to the active TMEE Server service. The client thread is started with a priority set to the threadPriority parameter. The IP address parameter must be set to the address of the TMEE Server. The port parameter must be set to the port the TMEE Server listens on for Console connections (the default port the Consoles use is 3010). The Console thread is started with a priority set to the threadPriority parameter.
In the comments you indicate that the DLL takes a copy of the char* pointers (and not the contents of the strings) and then modifies the contents of the strings after DAStart returns.
In the face of this very unconventional interface design your only option is to take charge of the marshaling of the string parameters. You cannot use StringBuilder since the char* passed to the native code is valid only during the pinvoke call. It cannot be relied upon to be valid after the pinvoke call returns.
So your only solution is to pass the string parameters as IntPtr. Allocate the memory with Marshal.StringToHGlobalAnsi. Pass the resulting IntPtr to DAStart. When you are sure the DLL is done with the pointer, deallocate with Marshal.FreeHGlobal.
References outside the managed environment are unknown to the Garbage collector.
Thus you need to keep an additional reference somewhere as long as you need to the object - easiest is via a static property in the calling class.
An IntPtr does not make a difference - it will get collected as well.

Categories

Resources