user
user

Reputation: 681

Using C++ DLL in D10

I use a C++ DLL in my app.

type
  Tcl_bla = function(filename: PChar): Integer; cdecl;

var
  cl_bla: Tcl_bla;

function CallLibraryProc(Proc: String): Pointer;
begin
  Result := GetProcAddress(Handle, PChar(Proc));
  if not Assigned(Result) then
    Loaded := False;
  if not Loaded then
    MessageBox(0, PChar('Error => ' + Proc), 'Alert', MB_OK or MB_TOPMOST);
end;
...    
Handle := SafeLoadLibrary(
  PChar(CurrentPath + Dll),
  SEM_FAILCRITICALERRORS or SEM_NOGPFAULTERRORBOX or SEM_NOOPENFILEERRORBOX
);
if (Handle < HINSTANCE_ERROR) then
  raise Exception.Create(
    Dll + ' library can not be loaded or not found.' + SysErrorMessage(GetLastError)
  );
if Handle <> 0 then
begin
  // blabla  
  cl_bla := CallLibraryProc('cl_bla');
end;
...    
FreeLibrary(Handle);

The codes aboves works fine with D6. I'm trying to port my code so it can run in Delphi with Unicode support but I have a trouble.

I've read the documentation from Embarcadero about GetProcAddress

procedure CallLibraryProc(const LibraryName, ProcName: string);
var
  Handle: THandle;
  RegisterProc: function: HResult stdcall;
begin
  Handle := LoadOleControlLibrary(LibraryName, True);
  @RegisterProc := GetProcAddress(Handle, PAnsiChar(AnsiString(ProcName)));
end;

I can't try this because I don't know how to declare LoadOleControlLibrary!

My CallLibraryProc can load the DLL but somehow cl_bla works incorrectly.

I think the problem with my code because of GetProcAddress's parameter or.. maybe my ported header is wrong.

Upvotes: 2

Views: 536

Answers (2)

David Heffernan
David Heffernan

Reputation: 612844

I may as well post this this as an answer, because it seems like the answer!

The code that you say is D6 code will work fine unmodified in D2010, and have the same meaning. There are two GetProcAddress overloads in Windows.pas. One of them converts from Unicode to ANSI. So you can just call GetProcAddress(Handle, PChar(Proc)) just like you always did.

The magic one looks like this:

function GetProcAddress(hModule: HMODULE; lpProcName: LPCWSTR): FARPROC;
begin
  if ULONG_PTR(lpProcName) shr 16 = 0 then // IS_INTRESOURCE
    Result := GetProcAddress(hModule, LPCSTR(lpProcName))
  else
    Result := GetProcAddress(hModule, LPCSTR(AnsiString(lpProcName)));
end;

Upvotes: 1

Rob Kennedy
Rob Kennedy

Reputation: 163257

You don't need to declare or use LoadOleControlLibrary. Just call plain old LoadLibrary like you always have. The important part of the code you saw was to convert Delphi's UnicodeString values into AnsiString values, and then type-cast explicitly to PAnsiChar instead of PChar. (PChar is PWideChar nowadays, and GetProcAddress requires non-Unicode characters.) I suggest changing ProcName to declare it as an AnsiString from the beginning. You'll need less type-casting. Keep LibraryName declared as string.

Upvotes: 1

Related Questions