I defined a function in C DLL library.
__declspec(dllexport) void* GetText();
It will return a string which is dynamically allocated from heap memory (And GlobalAlloc is used here for allocating memory). Note that the returned string is not null-terminated.
Then at C# side I tried two methods to declare the function
[DllImport("D:\\ca\\TextAccessLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
static extern String GetText();
When calling above method, the application will crash without any exception thrown.
[DllImport("D:\\ca\\TextAccessLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr GetText();
ptr = GetText();
string text = Marshal.PtrToStringAuto(ptr, 1000);
And calling this method will return incorrect string. Checked the real bytes by using Marshal.Copy, I found the bytes value is not same as the value in DLL library. (I think it's caused by Virtual Memory, C# process cannot access memory space of the DLL directly)
(Don't mind the string length, I hard coded it to 1000 for ease)
This is the C++ code and the memory value of the string when debugging (It's a Console Application but not the original DLL, because Console Application is easy to debug. But the DLL code is same as this one except the logging part). Following is the original DLL code
__declspec(dllexport) char* GetText(){
VTHDOC hDoc = NULL;
VTHTEXT hText = VTHDOC_INVALID;
DAERR da_err = NULL;
DAERR ta_err = NULL;
DAERR read_err = NULL;
char *buf = (char*)GlobalAlloc(GMEM_FIXED, 1000);
DWORD real_size;
DAInitEx(SCCOPT_INIT_NOTHREADS, OI_INIT_DEFAULT);
da_err = DAOpenDocument(&hDoc, 2, "D:\\1TB.doc", 0);
ta_err = TAOpenText(hDoc, &hText);
read_err = TAReadFirst(hText, (VTLPBYTE)buf, 1000, &real_size);
return buf;
}
But at C# side the bytes are not same as C++ side
You can see the first byte in C++ is 0, but it's 200 for C# (decimal)
Another thing to note: if I return a const string(e.g. "AASSDD") directly in DLL code, C# side will get the correct string
As already stated, it works for null-terminated strings only, in the following way:
C# part, declaration:
C# part, usage:
C++ part:
And the obtained C# string: "@ABCDEFGH??????????", value of size: 20
A treatment of the issue may be found here