I have an dll written in C++, and I want to call it from C#. The function outputs outputChar and deadChar, the deadChar variable is also read by the C++ function.
I tried to call function from C# in different ways, but all time I got AccessViolationException: "Attempted to read or write protected memory. This is often an indication that ot开发者_运维知识库her memory is corrupt."
C++ dll:
extern "C" _declspec (dllexport) int convertVirtualKeyToWChar(int virtualKey, PWCHAR outputChar, PWCHAR deadChar);
C# code 1:
[DllImport("keylib.dll")]
static extern int convertVirtualKeyToWChar(int virtualKey,
StringBuilder output,
StringBuilder deadchar);
C# code 2:
static extern int convertVirtualKeyToWChar(int virtualKey,
out char output,
ref char deadchar);
Note: The two PWCHAR
arguments to your function convertVirtualKeyToWChar
are ambiguous. They could be pointers to a single WCHAR
or pointers to aWCHAR
string. Given the name of the function and arguments, this answer assumes they are pointers to a single WCHAR
.
You want to use the following:
[DllImport("keylib.dll", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.Cdecl)] static extern int convertVirtualKeyToWChar( int virtualKey, out char output, ref char deadchar );
Your crash is caused by two reasons: DllImport
defaults to the ANSI character set and StdCall calling convention. Your C++ DLL does not specify any calling convention, so it will default to CDecl.
See DllImportAttribute.CallingConvention and DllImportAttribute.CharSet
This is a stab in the dark, so caveat emptor...
static extern int convertVirtualKeyToWChar(int virtualKey,
char[] output,
char[] deadchar);
Pass a single-element array to each char[]
parameter.
Try this (bearing in mind that if an exception is thrown between Alloc and Free you will leak memory, so build some error handling in):
static void Main(string[] args)
{
IntPtr pout = Marshal.AllocHGlobal(2);
IntPtr pdead = Marshal.AllocHGlobal(2);
int ret = convertVirtualKeyToWChar(1, pout, pdead);
char output = (char)Marshal.ReadInt16(pout);
char dead = (char)Marshal.ReadInt16(pdead);
Marshal.FreeHGlobal(pout);
Marshal.FreeHGlobal(pdead);
}
static extern int convertVirtualKeyToWChar(int virtualKey,
IntPtr output,
IntPtr deadchar);
精彩评论