How to return a string from a DLL to Inno Setup?

2020-06-16 02:40发布

问题:

I need to return a string value to the calling inno setup script. Problem is I can't find a way to manage the allocated memory. If I allocate on the DLL side, I don't have anything to deallocate with on the script side. I can't use an output parameter, because there is no allocation function in the Pascal Script either. What should I do?

回答1:

Here is a sample code of how to allocate a string that returns from a DLL:

[Code]
Function GetClassNameA(hWnd: Integer; lpClassName: PChar; nMaxCount: Integer): Integer; 
External 'GetClassNameA@User32.dll StdCall';

function GetClassName(hWnd: Integer): string;
var
  ClassName: String;
  Ret: Integer;
begin
  { allocate enough memory (pascal script will deallocate the string) }
  SetLength(ClassName, 256); 
  { the DLL returns the number of characters copied to the buffer }
  Ret := GetClassNameA(hWnd, PChar(ClassName), 256); 
  { adjust new size }
  Result := Copy(ClassName, 1 , Ret);
end;


回答2:

A very simple solution for the case where the DLL function is called only once in the installation - use a global buffer in your dll for the string.

DLL side:

char g_myFuncResult[256];

extern "C" __declspec(dllexport) const char* MyFunc()
{
    doSomeStuff(g_myFuncResult); // This part varies depending on myFunc's purpose
    return g_myFuncResult;
}

Inno-Setup side:

function MyFunc: PChar;
external 'MyFunc@files:mydll.dll cdecl';


回答3:

The only practical way to do this is to allocate a string in Inno Setup, and pass a pointer to that along with the length to your DLL that then writes to it up to the length value before returning.

Here's some example code taken from the newsgroup.

function GetWindowsDirectoryA(Buffer: AnsiString; Size: Cardinal): Cardinal;
external 'GetWindowsDirectoryA@kernel32.dll stdcall';
function GetWindowsDirectoryW(Buffer: String; Size: Cardinal): Cardinal;
external 'GetWindowsDirectoryW@kernel32.dll stdcall';

function NextButtonClick(CurPage: Integer): Boolean;
var
  BufferA: AnsiString;
  BufferW: String;
begin
  SetLength(BufferA, 256);
  SetLength(BufferA, GetWindowsDirectoryA(BufferA, 256));
  MsgBox(BufferA, mbInformation, mb_Ok);
  SetLength(BufferW, 256);
  SetLength(BufferW, GetWindowsDirectoryW(BufferW, 256));
  MsgBox(BufferW, mbInformation, mb_Ok);
end;

Also see this thread for more up to date discussion.