8

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?

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Tamás Szelei
  • 23,169
  • 18
  • 105
  • 180

3 Answers3

7

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;
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
kobik
  • 21,001
  • 4
  • 61
  • 121
4

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';
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
yairchu
  • 23,680
  • 7
  • 69
  • 109
  • 1
    I love this simple answer, it is helpful when you write an extension DLL especially for Inno Setup. In this case you can ignore the missing support for re-entrance safety which comes from using a global buffer. – blerontin Nov 18 '15 at 13:54
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.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Deanna
  • 23,876
  • 7
  • 71
  • 156