3

The following GetProcAddress code fails when compiled under Delphi XE6 x64. It runs fine when compiled under Delphi x86. Could you help to comment what is done wrong ?

program Project11;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  SysUtils;

var
  Library_OpenGL: LongWord;

function LoadLibrary(lpFileName: pAnsiChar): LongWord; stdcall; external 'kernel32.dll' name 'LoadLibraryA';
function GetProcAddress(hModule: LongWord; lpProcName: pAnsiChar): Pointer; stdcall; external 'kernel32.dll' name 'GetProcAddress';

begin
  try
    Library_OpenGL := LoadLibrary('opengl32.dll');
    Assert(GetProcAddress(Library_OpenGL, 'glEnable') <> nil, 'GetProcAddress(Library_OpenGL, ''glEnable'') = nil');
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  ReadLn;
end.
SOUser
  • 3,802
  • 5
  • 33
  • 63
  • I can't imagine that a 64 bit process can load an obviously 32 bit DLL. That is bound to fail. – Rudy Velthuis Aug 29 '14 at 22:07
  • @Rudy, both 32 and 64 bit dlls are named opengl32, one in system32 and the other in syswow64. – Sertac Akyuz Aug 29 '14 at 22:13
  • @Ah, Ok, thanks. Why on earth don't they call it opengl64? – Rudy Velthuis Aug 29 '14 at 22:18
  • @RudyVelthuis Probably for the same reason that wow64 means 32-bit and system32 means 64 bit 0_o – J... Aug 29 '14 at 22:35
  • @J...: that's indeed inconsistent too, and probably also done for backward compatiblity reasons. – Rudy Velthuis Aug 29 '14 at 22:38
  • 1
    @Rudy Common DLL names available in both 32 and 64 bit flavours include kernel32, user32, advapi32, comctl32 and so on. The 32 is now meaningless. Added when 32 bit was introduced because that was the best compat choice moving from 16 bit. And retained when moving on to 64 bit, again the best compat choice. – David Heffernan Aug 30 '14 at 03:29

1 Answers1

14

Your translations are wrong. A module handle is pointer sized which explains why your erroneous translations worked on 32 bit but not 64 bit.

To correct, add the Windows unit to your uses clause, remove your declarations of LoadLibrary() and GetProcAddress(), and declare Library_OpenGL as HMODULE (which is 8 bytes in x64):

program Project11;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  SysUtils, Windows;

var
  Library_OpenGL: HMODULE;

begin
  try
    Library_OpenGL := LoadLibrary('opengl32.dll');
    Assert(GetProcAddress(Library_OpenGL, 'glEnable') <> nil, 'GetProcAddress(Library_OpenGL, ''glEnable'') = nil');
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  ReadLn;
end.

As an added benefit you now call the native Unicode LoadLibraryW directly rather than going via the LoadLibraryA adapter with its conversation from ANSI to the system native UTF-16.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169