2

I am using a windows dll in Delphi, and I have to check if my functions are well allocated.

I declared function types in order to put my dll functions in class attributes like this :

type
  MPOS_OpenResource = function (ResID: DWORD; CplNum:BYTE; BlockingMode: DWORD):WORD;stdcall;
  MPOS_CloseResource = function (ResID: DWORD; CplNum:BYTE):WORD;stdcall;
  MPOS_GetResourceID = function (CplNum : Byte; ResID : PDWord) : word;stdcall;
  ...

Then, I assign a method to each coresponding field in my dll class like this:

@Self.m_MPOS_OpenResource := GetProcAddress( libHandler, '_MPOS_OpenResource@12' );
@Self.m_MPOS_CloseResource := GetProcAddress( libHandler, '_MPOS_CloseResource@8' );
@Self.m_MPOS_GetResourceID := GetProcAddress( libHandler, '_MPOS_GetResourceID@8');
...

And I finally check that each allocation worked with a giant if clause :

If(not Assigned(@m_MPOS_OpenResource) OR
  not Assigned(@m_MPOS_CloseResource) OR
  not Assigned(@m_MPOS_GetResourceID) OR 
...) then { Some code for exception}

I would like to avoid the giantic if clause using reflection but I could not find something that works. I tried multiple things, the last one begin this :

for f in rttiType.GetFields() do 
  if(not Assigned(rttiType.GetField(f.Name).GetValue(Self)) 
      OR (Self.FieldAddress(f.Name) = Nil)) then begin
    ShowMessage('Field not assigned');
  end;
end;

But it does not work. Can someone help me out?

yanneke
  • 106
  • 7
  • An alternative is to use `Delay loading`, as explained [here](http://stackoverflow.com/a/9263746/576719). – LU RD Mar 27 '17 at 14:34
  • Thanks, this seems to be what I need :) – yanneke Mar 27 '17 at 14:46
  • 1
    `TRttiField.GetValue()` returns a `TValue`. You can't use `Assigned()` with that. Use `TValue.IsEmpty` instead. Also, you can use `TRttiField.FieldType.TypeKind` or `TValue.Kind` to make sure you are operating on a pointer field. – Remy Lebeau Mar 27 '17 at 15:15

1 Answers1

6

You can write a wrapper function to perform the test:

procedure CheckedGetProcAddress(libHandle: HMODULE; const name: string; var proc: Pointer);
begin
  proc := GetProcAddress(libHandle, PChar(Name));
  if not Assigned(Proc) then
    raise EProcNotFound.Create(...);
end;

Then you write:

CheckedGetProcAddress(libHandler, '_MPOS_OpenResource@12', @@Self.m_MPOS_OpenResource);
CheckedGetProcAddress(libHandler, '_MPOS_CloseResource@8', @Self.m_MPOS_CloseResource);
CheckedGetProcAddress(libHandler, '_MPOS_GetResourceID@8', @Self.m_MPOS_GetResourceID);

FWIW, handler is the wrong terminology. This is a module handle, so your variable should be named libHandle.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490