DLL plugin question

I'm developing DLL plugin system. Main application is written in Delphi. I'm having problem when I need to direct some variable to DLL, that will modify the variable content. Raw example:

main application runs ProcessPlugin procedure that will update some text variable, let's call it AData.

main application:

var AData: string;
begin
  AData := 'OldData'; // AData may contain some old data
   ProcessPlugin(AData);
   ShowMessage(AData);
end;

DLL plugin:

procedure ProcessPlugin(var AData: string);
begin
   AData := 'New Data';
end;

What is the better way to make this? I think there should be some tricks with pointers and memory allocations?

Alex
iam_dumbAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Russell LibbySoftware Engineer, Advisory Commented:

Alex,

When writing dlls, it is best to avoid the passing of Delphi strings, unless the caller (application) is ALWAYS going to be Delphi. And even when it is Delphi, you still need to include the ShareMem unit in BOTH the dll and the executables "uses" clause.

In many Windows API situations, where the dll modifies the contents of some "buffer" passed in to it, the caller passes a pointer to PChar/Block of memory, etc, as well as a flag indicating the max size of the buffer passed in. If the buffer is too small, the dll returns a status code indicating so (or GetLastError returns the error). In newer APIs, the size flag is passed "By reference" and modified to reflect the size of the data written/or size required.

Simple example:

function ProcessPlugin(lpszData: PChar; var dwSize: DWORD): Boolean;
var s: String;
begin

 s:='New Data';
 // Make sure buffer is large enough
 if dwSize > Succ(Length(s)) then
 begin
   // Copy string
   StrPCopy(lpszData, s)
  // Update the byref size variable to indicate the size of the result
   dwSize:=Length(s);
  // Success
   result:=true;
 end
 else
 begin
   // Update the size variable to notify the caller how large a buffer is needed
   dwSize:=Succ(Length(s));
  // Failure
   result:=False;
 end;
end;

Caller Code:

var
 p:           PChar;
 dwSize:  DWORD;
begin

 dwSize:=100;
 p:=AllocMem(dwSize);

 if not(ProcessPlugin(p, dwSize)) then
 begin
   FreeMem(p);
   p:=AllocMem(dwSize);
   ProcessPlugin(p, dwSize);
 end;

end;

There may also be times (maybe your situation), where the dll may need a very large buffer to write the return results, and it is not feasible for the application to allocate this much memory blindly. If this is the case, then you could have the dll/exe use standard heap functions, like HeapAlloc, HeapFree, etc or GlobalAlloc, GlobalLock, GlobalFree, etc. The the caller would just pass in a var Pointer, the dll would allocate required memory via the function, and when the app is done, it could call the associated free function (HeapFree/GlobalFree). This would allow apps written in other languages to utilize your dll as well

Hope this helps (and makes sense),
Russell







0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Russell LibbySoftware Engineer, Advisory Commented:

Sorry, small typo on my part...

Example code

 // Make sure buffer is large enough
 if dwSize > Succ(Length(s)) then
 begin
    ....

should be:

 if dwSize >= Succ(Length(s)) then
 begin
    ....

Also, as another note; by reference (var) Variant passing is also another viable option, where the string can be set with StringToOleStr, and retrieved with OleStrToString. Once the application clears the variant (variant = unassigned) the memory is freed for you. Under the covers,  CoTaskMemAlloc / CoTaskMemFree / SysAllocString / etc, all get handled for you.

Regards,
Russell

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Web Components

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.