Sending procedure to an exported dll function (organizing callback)

348 views Asked by At

The situation is such: I have a barcode scanner with dll (written in C++, all functions are stdcall) that exports all necessary functions to communicate with it. And there are several functions that should be used to assign as callbacks (I have to provide an appropriate procedures and those will be called as soon as certain event fires). And here is the main problem I faced with. These callback assigning functions can accept only "standalone" procedures (in this case everything is working fine), but not methods or even anonymous procedure. On these events I do have to access some class data (scanner is realized as class) like fields and methods, but normally it's not possible from a standalone unit procedure. Can You please help me to solve this problem?

Some code:

Scanner API descriptions:

    typedef void (__stdcall *TOnDevicePlug)(bool PluggedIn);
    extern "C" __declspec(dllexport) void __stdcall SetupOnDevicePlugCallback(TOnDevicePlug OnPresent);

My type descriptions:

    TOnDevicePlug = procedure(PluggedIn: Boolean); stdcall;
    TSetupOnDevicePlugCallback = function(AOnPresent: TOnDevicePlug): Integer; stdcall;

In case I do like so:

    procedure OnDevicePlug(PluggedIn: Boolean); stdcall;
    begin
      Form2.mmLog.Lines.Add('On plugged activated');
    end;

    ...
    @FSetupOnDevicePlugCallback := GetProcAddress(FDllHandle, 'SetupOnDevicePlugCallback');
    FSetupOnDevicePlugCallback(OnDevicePlug);
    ...

Everything works. (But again, I cannot work with my class).

If I try something like this:

    FOnPlug := TOnDevicePlug(
      procedure stdcall
      begin
        mmLog.Lines.Add('On plugged activated');
      end
      );
    FSetupOnDevicePlugCallback(FOnPlug);

Where FOnPlug - class field of TOnDevicePlug type. In this case there are two variants: if I leave old type description (TOnDevicePlug = procedure(PluggedIn: Boolean); stdcall;) I get exception with "privileged instruction". If I change type to "reference to procedure" (like TOnDevicePlug = reference to procedure stdcall;) I get access violation exception. These both errors are fired on event.

So can You please advise me something to make this event work with my class? Will be thankful for any idea. Or maybe You will see some errors in my code.

1

There are 1 answers

3
David Heffernan On BEST ANSWER

Your callback must be of the form:

procedure(PluggedIn: Boolean); stdcall;

An anonymous method is simply not compatible. Write a unit scoped procedure like this:

procedure MyOnDevicePlug(PluggedIn: Boolean); stdcall;
begin
  // do stuff
end;

Now, the library you are using does not provide any more information when it calls this callback. It does not pass an extra pointer to allow the callback recipient to gain access into their state.

You might be able to modify the library that you use so that it could accept an untyped pointer when you call it, and then pass that pointer back to you in your callback.

If you cannot make such a modification, then you may need to use a global variable, or even a thunk to obtain the state.