How can I return a PChar from a DLL function to a

2019-01-26 12:40发布

I have to create a DLL which is used by a VB6 application. This DLL has to provide several functions, some of them must return strings.

This is the VB6 declaration:

Declare Function MyProc Lib "mylib.dll" (ByVal Param As String) As String

And this the Delphi implementation stub in mylib.dll:

function MyProc(AParam: PChar): PChar; stdcall;
var
  ReturnValue: string;
begin
  ReturnValue := GetReturnValue(AParam);
  Result := ???;
end;

What do I have to return here? Who will free the memory of the returnd PChar string?

EDIT: I'm asking about Delphi 2005 (PChar = PAnsiChar)

7条回答
唯我独甜
2楼-- · 2019-01-26 12:49

I'm not familiar with Dephi, but here are the two main options when using strings with a non-COM DLL and VB6.

Option 1. Use "ANSI" strings.

'DLL routine expecting to be passed pointers to ANSI strings '
'VB6 will allocate and deallocate the strings '
'Its vital that VB6 allocates sufficient space for the return string '
Declare Sub MyProc Lib "mylib.dll" (ByVal Param As String, _ 
  ByVal OutVal As String) 

Function DoMyProc(ByVal Param As String) As String
  Dim sResult As String
  sResult = Space$(255)  ' create 255 bytes of space for the return string '
  Call MyProc(Param, sResult) 
  DoMyProc = sResult
End Function

Option two. Use BSTRs.

'DLL routine expecting to be passed two BSTRs. It will modify the second one. '
'VB6 "owns" both BSTRs and will deallocate them when it has finished with them. '
Declare Sub MyProc(ByVal lpParam As Long, ByVal lpOutVal As Long)

Function DoMyProc(ByVal Param As String) As String
  Dim sResult As String
  Call MyProc(StrPtr(Param), StrPtr(sResult)) 
  DoMyProc = sResult
End Function

I'd also suggest looking at the Microsoft advice on writing C DLLs to be called from VB. Originally released with VB5 but still relevant to VB6.

查看更多
We Are One
3楼-- · 2019-01-26 12:50

I would say that whoever allocates the memory must also free it in this case. You will run into problems with other scenarios. So the most safe and clean way would be:

  1. The DLL allocates memory (because it knows how much) and returns the PChar to caller
  2. After the caller is done with it, it calls FreePointer back to the DLL
  3. DLL frees the memory in the FreePointer exported function

The setup would be like this:

unit DLL;

interface

uses
  SysUtils;

function Execute(const Params: PChar): PChar; stdcall;
procedure FreePointer(const P: PChar); stdcall;

exports Execute;
exports FreePointer;

implementation

function Execute(const Params: PChar): PChar; stdcall;
var
  Size: Cardinal;
begin
  Size := Calculate the size;
  GetMem(Result, Size);

  ...do something to fill the buffer
end;

procedure FreePointer(const P: PChar); stdcall;
begin
  FreeMem(P);
end;

end.
查看更多
冷血范
4楼-- · 2019-01-26 12:53

Use the Windows API to allocate the memory that the PChar pointer points into. Then, the VB app can deallocate the memory after use, using the Windows API, too.

查看更多
太酷不给撩
5楼-- · 2019-01-26 12:54

You cannot return a PChar as a function result, but you can pass an additional PChar parameter and copy the string you want to return to this PChar. Note, that VB must allocate that string to the required size before passing it to the dll. Also in VB that parameter must be declared as byval param as string AND it must be passed with byval:

  param = "aaaaaaaaaaaaaaaaaaaa" ' reserve 20 characters
  call myproc(byval param)

The additional byval in the call will do the compiler magic of converting a VB string to a PChar and back.

(I hope I remember this is correctly, it has been quite a while since I was forced to use VB.)

查看更多
Summer. ? 凉城
6楼-- · 2019-01-26 13:07

You need to craft a BSTR instead. VB6 strings are actually BSTRs. Call SysAllocString() on the Delphi side and return the BSTR to the VB6 side. The VB6 side will have to call SysFreeString() to free the string - it will do it automatically.

If PChar corresponds to an ANSI string (your case) you have to manually convert it to Unicode - use MultiByteToWideChar() for that. See this answer for how to better use SysAllocStringLen() and MultiByteToWideChar() together.

查看更多
你好瞎i
7楼-- · 2019-01-26 13:10

Combining Sharptooth and Lars D's answer; aren't widestrings already allocated via windows and BSTR?

查看更多
登录 后发表回答