Suppose I have a TMemoryStream
I need to pass to my DLL and get back TMemoryStream
(Bitmap stream) from the DLL.
I was thinking my DLL would have:
procedure Process(
InBuff: Pointer;
InBuffSize: Integer;
var OutBuff: Pointer;
var OutBuffSize: Integer
); stdcall;
The InBuff
is easy (I think). I pass TMemoryStream.Memory
and TMemoryStream.Size
.
Question is how do I allocate the OutBuff
in the DLL, and the caller application can convert it back to TMemoryStream
and later free that memory (by the caller application)?
The caller will use dynamic LoadLibrary
/FreeLibrary
each DLL call.
I would very much like a sample code. Hope I'm not being too rude.
Note 1: The caller application dose not know the output size, and assume it can not specify a MAX buff size.
Note 2: I am not sure about my DLL signature. Please forgive me if I did it wrong. I am Looking for a pattern that will work well (maybe not only for Delphi but for C++/C# Caller as well = Bonus for me)
Two obvious options, assuming the callee is to allocate the memory:
1. Use a shared heap
For instance you can use the COM heap. In the callee your write:
OutBuffSize := ...; // you know what this value is
OutBuff := CoTaskMemAlloc(OutBuffSize);
// populate the buffer
The caller destroys this with CoTaskMemFree
. You can use LocalAlloc
, or HeapAlloc
if you prefer, it doesn't really matter.
2. Use the callee's heap and export a deallocator
Here you use the native heap of the callee:
OutBuffSize := ...; // you know what this value is
GetMem(OutBuff, OutBuffSize);
// populate the buffer
You also need to export a deallocator:
procedure DeallocateMemory(Ptr: Pointer); stdcall;
begin
FreeMem(Ptr);
end;
Another option that I rejected is to use a shared memory manager. I tend to avoid that because it constrains the caller to be a Delphi program.
To fill a stream from a buffer call WriteBuffer
:
Stream.WriteBuffer(Buff^, BuffSize);
where Buff
is a pointer to the buffer.