System.AccessViolationException while marshaling from native to managed by implementing ICustomMarshaler - c#

Somehow the continuation to the question I recently posted, I've a nasty System.AccessViolationException while trying to marshal from native to managed (by using ICustomMarshaler), which I do not understand. Here a sample code that reproduce the error (**). The C++ side:
typedef struct Nested1{
int32_t n1_a; // (4*)
char* n1_b;
char* n1_c;
} Nested1;
typedef struct Nested3{
uint8_t n3_a;
int64_t n3_b;
wchar_t* n3_c;
} Nested3;
typedef struct Nested2{
int32_t n2_a;
Nested3 nest3;
uint32_t n2_b;
uint32_t n2_c;
} Nested2;
typedef struct TestStruct{
Nested1 nest1; // (2*)
Nested2 nest2;
} TestStruct;
void ReadTest(TestStruct& ts)
{
ts.nest2.n2_c = 10; // (3*)
}
On the C# side a fake TestStruct just to show the error and the ICustomMarshaler implementation:
class TestStruct{};
[DllImport("MyIOlib.dll", CallingConvention = CallingConvention.Cdecl)]
extern static void ReadTest([Out, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(CustomMarshaler))]TestStruct ts);
class CustomMarshaler : ICustomMarshaler
{
public static ICustomMarshaler GetInstance(string Cookie) { return new CustomMarshaler(); }
public object MarshalNativeToManaged(IntPtr pNativeData)
{
return new TestStruct();
}
public void CleanUpNativeData(IntPtr pNativeData)
{
} // (1*)
public int GetNativeDataSize() { return 40; }
public IntPtr MarshalManagedToNative(object ManagedObj)
{
TestStruct ts = (TestStruct)ManagedObj;
IntPtr intPtr = Marshal.AllocHGlobal(GetNativeDataSize());
return intPtr;
}
}
private void Form1_Load(object sender, EventArgs e)
{
TestStruct ts = new TestStruct();
ReadTest(ts);
}
Now, I have the following:
with exactly this code I get a System.AccessViolationException just after line (1*);
if I comment out line (2*) or line (3*) I get no exception and everything works fine;
if I comment one among several other struct fields, e.g. line (3*) I get a "Managed Debugging Assistant 'FatalExecutionEngineError' has detected a problem in [...] This error may be a bug in the CLR or in the unsafe or non verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack"
(**) I did an heavy editing of my original post because I think I've found an easier way to show the problem and leaving my previous text would have confused the reader. Hope is not a problem, however if previous readers want I can re-post my original text.

You need the In attribute as well as Out. Without the In attribute, MarshalManagedToNative is never called. And no unmanaged memory is allocated. Hence the access violation.
extern static void ReadTest(
[In, Out, MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(CustomMarshaler))]
TestStruct ts
);
Strictly speaking, the unmanaged code should use a pointer to the struct rather than a reference parameter. You can pass null from the managed code but that is then invalid as a C++ reference parameter.
void ReadTest(TestStruct* ts)
{
ts->nest2.n2_c = 10;
}

David Haffernan's reply (thanks a lot BTW!) is correct (so read that for the quick reply), here I add only a few considerations, which might be helpful for readers (even if I'm not an expert on the matter, so please take it with a pinch of salt). When MarshalManagedToNative is called to pass the struct to the native code (only [In] attribute), the code is something similar to:
public IntPtr MarshalManagedToNative(object managedObj)
{
IntPtr intPtr = MarshalUtils.AllocHGlobal(GetNativeDataSize());
// ...
// use Marshal.WriteXXX to write struct fields and, for arrays,
// Marshal.WriteIntPtr to write a pointer to unmanaged memory
// allocated with Marshal.AllocHGlobal(size)
return intPtr;
}
Now, when it is needed to read the struct from the native code as David Haffernan said we still need to allocate memory (it cannot be done on the native side as also Hans Passant suggested), hence the need to add also in this case the [In] attribute (aside the [Out] one).
However I need only the memory for the first level struct and not all the other memory for storing arrays (I have several memory consuming arrays), which is allocated on the native side (e.g. with malloc()) and should be freed later on (with a call to a method that uses free() to reclaim the native memory), hence I detect that MarshalManagedToNative is going to be used for that purpose using a public static variable in CustomMarshaler that I set once I know I need to read the struct from the native code (I understand it is not an elegant solution, but it helps me to save time):
public IntPtr MarshalManagedToNative(object managedObj)
{
IntPtr intPtr = MarshalUtils.AllocHGlobal(GetNativeDataSize());
if(readingFromNative) // this is my public static variable
return intPtr;
// ...
// use Marshal.WriteXXX to write struct fields and, for arrays, Marshal.WriteIntPtr
// to write a pointer to unmanaged memory allocated with Marshal.AllocHGlobal(size)
return intPtr;
}

Related

Preserve C++ Pointer in C#

I am writing a little Program in C# which includes a C++ Dll.
In C++, there are many classes which needed to be instanced and left for later use.
This looks like the following function:
C++:
__declspec(dllexport) FrameCapture* GetFrameCapturer(HWND windowHandle) {
ProcessWindow* window = ProcessWindowCollection::GetInstance()->FindWindow(windowHandle);
FrameCapture* capture = new FrameCapture(window);
return capture;
}
As you can see I just create a FrameCapture class and return a Pointer to it.
This Pointer is stored in C# as an IntPtr.
C#:
[DllImport("<dllnamehere>")]
public static extern IntPtr GetFrameCapturer(IntPtr windowHandle);
This works really well so far.
But if I use that Pointer to get an Instance of FrameCapture
C++:
__declspec(dllexport) BITMAPFILEHEADER* GetBitmapFileHeader(FrameCapture* frameCapturer) {
return frameCapturer->GetBitmapFileHeader();
}
the class will be completely empty.
How do I get the Instance of the Class I initialized in step one?
EDIT:
I did some testing and replaced the Pointers with integers which are better to look at.
I casted 'capture' to an Int32 and returned this instead.
In my testcase it returned byte(208,113,244,194).
This values are, as expected, in C++ and C# the same.
But, now it becomes odd.
If I pass this Int32 into 'GetBitmapFileHeader' the value becomes suddenly byte(184,231,223,55).
That's not even close! I thought of Little <-> Big Endian or something like this but, this is a whole new Memoryblock?
The same behavior will go on with the IntPtr.
As requested I post also the Import of 'GetBitmapFileHeader'
[DllImport("<dllnamehere>")]
public static extern tagBITMAPFILEHEADER GetBitmapFileHeader(IntPtr capturerHandle);
Okay, I got it.
See this import from C#.
C#:
[DllImport("<dllnamehere>")]
public static extern tagBITMAPFILEHEADER GetBitmapFileHeader(IntPtr capturerHandle);
Its wrong!
The function now returns an IntPtr wich works completely fine.
This is the new Setup:
C++:
__declspec(dllexport) void* __stdcall GetBitmapFileHeader(void* frameCapturer) {
FrameCapture* cap = (FrameCapture*)frameCapturer;
return cap->GetBitmapFileHeader();
}
C#:
[DllImport("libWinCap.dll", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr GetBitmapFileHeader(IntPtr frameCapturer);
[...]
//calling
IntPtr ptr = GetBitmapFileHeader(m_capturerHandle);
m_bitmap.m_fileHeader = (tagBITMAPFILEHEADER)Marshal.PtrToStructure(ptr, typeof(tagBITMAPFILEHEADER));
Iam only moving Pointers now and use PtrToStructure to read the Memory.
Also, Thanks for every comment.

How to fix 'Method's type signature is not PInvoke compatible' error in C#

All I need to know is how to return a struct from a PInvoke in C++ that has the following struct. For the moment I can deal with it being blank and I just want to know how to return the struct under the conditions set in the code.
I've tried with with the entire struct that I need to return and isolated each part of struct to know which part is giving me the issue (which will be made apparent in the code provided).
I've tried the same method by wanting to return a few integers within the struct which works fine. (Tried to make this bold using ***, ___)
//.header file
typedef struct { //Defintion of my struct in C++
TCHAR msg[256];
}testTCHAR;
//.cpp file
extern "C" {
__declspec(dllexport) testTCHAR* (_stdcall TestChar(testTCHAR* AR))
{
AR->msg;
return AR;
}
}
In my C# I Call the .dll as:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void testChar(testTCHAR AR);
[DllImport("C:\\Users\\jch\\source\\repos\\FlatPanelSensor\\x64\\Debug\\VADAV_AcqS.dll", EntryPoint = "TestCallBackChar", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern testTCHAR TestCallBackChar([MarshalAs(UnmanagedType.FunctionPtr)] testChar call);
//Struct
public struct testTCHAR
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string rMsg; //I assume the error should be fixed here
but to what exactly I don't know.
}
//Defining the callback
testChar tChar =
(test) =>
{
//As far as I'm aware this part can be left blank
as I followed a tutorial online
};
testTCHAR returned = TestCallBackChar(tChar); //This is where the error
happens
I just need to return the struct, preferably with a value attached to it.
The error I get is 'Method's type signature is not PInvoke compatible.' Which is in the title, but I'm covering all basis.
If you need anymore information about this please ask away and I should be able to provide.
Since the testTCHAR type contains managed references, you cannot use a pointer as a part of signature (which you didn't), but also it does not make sense to pass it by value (this is why the runtime produces the error you see).
You need to change your signatures so that it's apparent that you want to pass a pointer into the native method:
public delegate void testChar(IntPtr data);
public unsafe static extern IntPtr TestCallBackChar([MarshalAs(UnmanagedType.FunctionPtr)] testChar call);
When calling you need to explicitly marshal structures to the managed equivalent (and vice versa):
testChar tChar =
(inputPtr) =>
{
testTCHAR input = (testTCHAR)Marshal.PtrToStructure(inputPtr, typeof(testTCHAR));
};
IntPtr returnedPtr = TestCallBackChar(tChar);
testTCHAR returned = (testTCHAR)Marshal.PtrToStructure(returnedPtr, typeof(testTCHAR));
Additionally, I guess there is a mismatch between C++ and C# signature and method name.

How safe is ref when used with unsafe code?

Using Microsoft Visual C# 2010, I recently noticed that you can pass objects by ref to unmanaged code. So I tasked myself with attempting to write some unmanaged code that converts a C++ char* to a a C# string using a callback to managed code. I made two attempts.
Attempt 1: Call unmanaged function that stores a ref parameter. Then, once that function has returned to managed code, call a another unmanaged function that calls a callback function that converts the char* to a managed string.
C++
typedef void (_stdcall* CallbackFunc)(void* ManagedString, char* UnmanagedString);
CallbackFunc UnmanagedToManaged = 0;
void* ManagedString = 0;
extern "C" __declspec(dllexport) void __stdcall StoreCallback(CallbackFunc X) {
UnmanagedToManaged = X;
}
extern "C" __declspec(dllexport) void __stdcall StoreManagedStringRef(void* X) {
ManagedString = X;
}
extern "C" __declspec(dllexport) void __stdcall CallCallback() {
UnmanagedToManaged(ManagedString, "This is an unmanaged string produced by unmanaged code");
}
C#
[DllImport("Name.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void StoreCallback(CallbackFunc X);
[DllImport("Name.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void StoreManagedStringRef(ref string X);
[DllImport("Name.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void CallCallback();
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void CallbackFunc(ref string Managed, IntPtr Native);
static void Main(string[] args) {
string a = "This string should be replaced";
StoreCallback(UnmanagedToManaged);
StoreManagedStringRef(ref a);
CallCallback();
}
static void UnmanagedToManaged(ref string Managed, IntPtr Unmanaged) {
Managed = Marshal.PtrToStringAnsi(Unmanaged);
}
Attempt 2: Pass string ref to unmanaged function that passes the string ref to the managed callback.
C++
typedef void (_stdcall* CallbackFunc)(void* ManagedString, char* UnmanagedString);
CallbackFunc UnmanagedToManaged = 0;
extern "C" __declspec(dllexport) void __stdcall StoreCallback(CallbackFunc X) {
UnmanagedToManaged = X;
}
extern "C" __declspec(dllexport) void __stdcall DoEverything(void* X) {
UnmanagedToManaged(X, "This is an unmanaged string produced by unmanaged code");
}
C#
[DllImport("Name.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void StoreCallback(CallbackFunc X);
[DllImport("Name.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void DoEverything(ref string X);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void CallbackFunc(ref string Managed, IntPtr Unmanaged);
static void Main(string[] args) {
string a = "This string should be replaced";
StoreCallback(UnmanagedToManaged);
DoEverything(ref a);
}
static void UnmanagedToManaged(ref string Managed, IntPtr Unmanaged) {
Managed = Marshal.PtrToStringAnsi(Unmanaged);
}
Attempt 1 doesn't work but attempt 2 does. In attempt 1 it seems that as soon as the unmanaged code returns after storing the ref, the ref becomes invalid. Why is this happening?
Given the outcomes of attempt 1, I have doubts that attempt 2 will work reliably. So, how safe is ref on the unmanaged side of code when used with unmanaged code? Or in other words, what won't work in unmanaged code when using ref?
Things I'd like to know are are:
What exactly happens when objects are passed using ref to unmanaged code?
Does it guarantee that the objects will stay at their current position in memory while the ref is being used in unmanaged code?
What are the limitations of ref (what can't I do with a ref) in unmanaged code?
A complete discussion of how p/invoke works is beyond the proper scope of a Stack Overflow Q&A. But briefly:
In neither of your examples are you really passing the address of your managed variable to the unmanaged code. The p/invoke layer includes marshaling logic that translates your managed data to something usable by the unmanaged code, and then translates back when the unmanaged code returns.
In both examples, the p/invoke layer has to create an intermediate object for the purpose of marshaling. In the first example, this object is gone by the time you call the unmanaged code again. Of course in the second example, it's not, since all of the work happens all at once.
I believe that your second example should be safe to use. That is, the p/invoke layer is smart enough to handle ref correctly in that case. The first example is unreliable because p/invoke is being misused, not because of any fundamental limitation of ref parameters.
A couple of additional points:
I wouldn't use the word "unsafe" here. Yes, calling out to unmanaged code is in some ways unsafe, but in C# "unsafe" has a very specific meaning, related to the use of the unsafe keyword. I don't see anything in your code example that actually uses unsafe.
In both examples, you have a bug related to your use of the delegate passed to unmanaged code. In particular, while the p/invoke layer can translate your managed delegate reference to a function pointer that unmanaged code can use, it doesn't know anything about the lifetime of the delegate object. It will keep the object alive long enough for the p/invoked method call to complete, but if you need it to live longer than that (as would be the case here), you need to do that yourself. For example, use GC.KeepAlive() on a variable in which you've stored the reference. (You likely can reproduce a crash by inserting a call to GC.Collect() between the call to StoreCallback() and the later call to unmanaged code where the function pointer would be used).

Release unmanaged memory from managed C# with pointer of it

The question in short words is :
How to free memory returned from Native DLL as ItrPtr in managed code?
Details :
Assume we have simple function takes two parameters as OUTPUT, The first one is Reference Pointer to byte array and the second one is Reference Int .
The function will allocate amount of bytes based on some rules and return the pointer of memory and the size of bytes and the return value (1 for success and 0 for fail) .
The code below works fine and I can get the byte array correctly and the count of bytes and the return value, but when I try to free the memory using the pointer (IntPtr) I get exception :
Windows has triggered a breakpoint in TestCppDllCall.exe.
This may be due to a corruption of the heap, which indicates a bug in TestCppDllCall.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while TestCppDllCall.exe has focus.
The output window may have more diagnostic information.
To make things clear :
The next C# code work correctly with other DLL function have the same signature and freeing the memory works without any problem .
Any modification in (C) code accepted if you need to change allocation memory method or adding any other code .
All the functionality I need is Native DLL function accept Two Parameter by reference (Byte array and int , In c# [IntPtr of byte array and int]) fill them with some values based on some rules and return the function result (Success or Fail) .
CppDll.h
#ifdef CPPDLL_EXPORTS
#define CPPDLL_API __declspec(dllexport)
#else
#define CPPDLL_API __declspec(dllimport)
#endif
extern "C" CPPDLL_API int writeToBuffer(unsigned char *&myBuffer, int& mySize);
CppDll.cpp
#include "stdafx.h"
#include "CppDll.h"
extern "C" CPPDLL_API int writeToBuffer(unsigned char*& myBuffer, int& mySize)
{
mySize = 26;
unsigned char* pTemp = new unsigned char[26];
for(int i = 0; i < 26; i++)
{
pTemp[i] = 65 + i;
}
myBuffer = pTemp;
return 1;
}
C# code :
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace TestCppDllCall
{
class Program
{
const string KERNEL32 = #"kernel32.dll";
const string _dllLocation = #"D:\CppDll\Bin\CppDll.dll";
const string funEntryPoint = #"writeToBuffer";
[DllImport(KERNEL32, SetLastError = true)]
public static extern IntPtr GetProcessHeap();
[DllImport(KERNEL32, SetLastError = true)]
public static extern bool HeapFree(IntPtr hHeap, uint dwFlags, IntPtr lpMem);
[DllImport(_dllLocation, EntryPoint = funEntryPoint, CallingConvention = CallingConvention.Cdecl)]
public static extern int writeToBuffer(out IntPtr myBuffer, out int mySize);
static void Main(string[] args)
{
IntPtr byteArrayPointer = IntPtr.Zero;
int arraySize;
try
{
int retValue = writeToBuffer(out byteArrayPointer, out arraySize);
if (retValue == 1 && byteArrayPointer != IntPtr.Zero)
{
byte[] byteArrayBuffer = new byte[arraySize];
Marshal.Copy(byteArrayPointer, byteArrayBuffer, 0, byteArrayBuffer.Length);
string strMyBuffer = Encoding.Default.GetString(byteArrayBuffer);
Console.WriteLine("Return Value : {0}\r\nArray Size : {1}\r\nReturn String : {2}",
retValue, arraySize, strMyBuffer);
}
}
catch (Exception ex)
{
Console.WriteLine("Error calling DLL \r\n {0}", ex.Message);
}
finally
{
if (byteArrayPointer != IntPtr.Zero)
HeapFree(GetProcessHeap(), 0, byteArrayPointer);
}
Console.ReadKey();
}
}
}
When I debug this code i set break point in the line (return 1) and the value of the buffer was :
myBuffer = 0x031b4fc0 "ABCDEFGHIJKLMNOPQRSTUVWXYZ‎‎‎‎««««««««î‏"
And I got the same value in C# code when the function call return and the value was :
52121536
The result I Got the correct Memory pointer and i am able to get the byte array value , how to free these memory blocks with this pointer in C# ?
Please let me know if there anything is not clear or if there any typo, I am not native English speaker .
Short answer: you should add a separate method in the DLL that frees the memory for you.
Long answer: there are different ways in which the memory can be allocated inside your DLL implementation. The way you free the memory must match the way in which you have allocated the memory. For example, memory allocated with new[] (with square brackets) needs to be freed with delete[] (as opposed to delete or free). C# does not provide a mechanism for you to do it; you need to send the pointer back to C++.
extern "C" CPPDLL_API void freeBuffer(unsigned char* myBuffer) {
delete[] myBuffer;
}
If you are allocating your own memory in native code, use CoTaskMemAlloc and you can free the pointer in managed code with Marshal.FreeCoTaskMem. CoTaskMemAlloc is described as "the only way to share memory in a COM-based application" (see http://msdn.microsoft.com/en-us/library/windows/desktop/aa366533(v=vs.85).aspx )
if you need to use the memory allocated with CoTaskMemAlloc with a native C++ object, you can use placement new to initialize the memory as if the new operator was used. For example:
void * p = CoTaskMemAlloc(sizeof(MyType));
MyType * pMyType = new (p) MyType;
This doesn't allocate memory with new just calls the constructor on the pre-allocated memory.
Calling Marshal.FreeCoTaskMem does not call the destructor of the type (which isn't needed if you just need to free memory); if you need to do more than free memory by calling the destructor you'll have to provide a native method that does that and P/Invoke it. Passing native class instances to managed code is not supported anyway.
If you need to allocate memory with some other API, you'll need to expose it in managed code through P/Invoke in order to free it in managed code.
HeapFree(GetProcessHeap(), 0, byteArrayPointer);
No, that can't work. The heap handle is wrong, the CRT creates its own heap with HeapCreate(). It's buried in the CRT data, you can't get to it. You could technically find the handle back from GetProcessHeaps(), except you don't know which one it is.
The pointer can be wrong too, the CRT may have added some extra info from the pointer returned by HeapAlloc() to store debugging data.
You'll need to export a function that calls delete[] to release the buffer. Or write a C++/CLI wrapper so you can use delete[] in the wrapper. With the extra requirement that the C++ code and the wrapper use the exact same version of the CRT DLL (/MD required). This almost always requires that you can recompile the C++ code.

free memory not clears the memory block

I am using DllImport to call method in c wrapper library from my own .net class. This method in c dll creates a string variable and returns the pointer of the string.
Something like this;
_declspec(dllexport) int ReturnString()
{
char* retval = (char *) malloc(125);
strcat(retval, "SOMETEXT");
strcat(retval, "SOMETEXT MORE");
return (int)retval;
}
Then i read the string using Marshall.PtrToStringAnsi(ptr). After i get a copy of the string, i simply call another c method HeapDestroy which is in c wrapper library that calls free(ptr).
Here is the question;
Recently while it is working like a charm, I started to get "Attempted to read or write protected memory area" exception. After a deeper analysis, i figured out, i beleive, although i call free method for this pointer, value of the pointer is not cleared, and this fills the heap unattended and makes my iis worker process to throw this exception. By the way, it is an web site project that calls this method in c library.
Would you kindly help me out on this issue?
Sure, here is C# code;
[DllImport("MyCWrapper.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private extern static int ReturnString();
[DllImport("MyCWrapper.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private extern static void HeapDestroy(int ptr);
public static string GetString()
{
try
{
int i = ReturnString();
string result = String.Empty;
if (i > 0)
{
IntPtr ptr = new IntPtr(i);
result = Marshal.PtrToStringAnsi(ptr);
HeapDestroy(i);
}
return result;
}
catch (Exception e)
{
return String.Empty;
}
}
What may be the problem is the underlying C code. You are not adding a NULL terminator to the string which strcat relies on (or checking for a NULL return from malloc). It's easy to get corrupted memory in that scenario. You can fix that by doing the following.
retval[0] = '\0';
strcat(retval, "SOMETEXT");
Also part of the problem is that you are playing tricks on the system. It's much better to write it correctly and let the system work on correctly functioning code. The first step is fixing up the native code to properly return the string. One thing you need to consider is that only certain types of memory can be natively freed by the CLR (HGlobal and CoTask allocations). So lets change the function signature to return a char* and use a different allocator.
_declspec(dllexport) char* ReturnString()
{
char* retval = (char *) CoTaskMemAlloc(125);
retval[0] = '\0';
strcat(retval, "SOMETEXT");
strcat(retval, "SOMETEXT MORE");
return retval;
}
Then you can use the following C# signature and free the IntPtr with Marshal.FreeCoTaskMem.
[DllImport("SomeDll.dll")]
public static extern IntPtr ReturnString();
Even better though. When marshalling, if the CLR ever thinks it needs to free memory it will use FreeCoTaskMem to do so. This is typically relevant for string returns. Since you allocated the memory with CoTaskMemAlloc you can save yourself the marshalling + freeing steps and do the following
[DllImport("SomeDll.dll", CharSet=Ansi)]
public static extern String ReturnString();
Freeing memory doesn't clear it, it just frees it up so it can be re-used. Some debug builds will write over the memory for you to make it easier to find problems with values such as 0xBAADFOOD
Callers should allocate memory, never pass back allocated memory:
_declspec(dllexport) int ReturnString(char*buffer, int bufferSize)
{
if (bufferSize < 125) {
return 125;
} else {
strcat(buffer, "SOMETEXT");
strcat(buffer, "SOMETEXT MORE");
return 0;
}
}
Although memory is allocated by the DLL in the same heap as your application, it MAY be using a different memory manager, depending on the library it was linked with. You need to either make sure you're using the same exact library, or add code to release the memory that the DLL allocates, in the DLL code itself.

Categories