将过程发送到导出的 dll 函数(组织回调)

Sending procedure to an exported dll function (organizing callback)

情况是这样的:我有一个条形码扫描器,带有 dll(用 C++ 编写,所有函数都是 stdcall),它导出所有必要的函数来与之通信。并且有几个函数应该用于分配为回调(我必须提供适当的过程,这些过程将在特定事件触发时立即调用)。这是我面临的主要问题。这些回调分配函数只能接受 "standalone" 过程(在这种情况下一切正常),但不能接受方法甚至匿名过程。在这些事件中,我确实必须访问一些 class 数据(扫描器实现为 class),例如字段和方法,但通常不可能从独立的单元过程中访问。你能帮我解决这个问题吗?

一些代码:

扫描仪API描述:

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

我的类型描述:

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

万一我喜欢:

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

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

一切正常。 (但同样,我无法使用我的 class)。

如果我尝试这样的事情:

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

其中 FOnPlug - class TOnDevicePlug 类型的字段。在这种情况下,有两种变体:如果我保留旧的类型描述 (TOnDevicePlug = procedure(PluggedIn: Boolean); stdcall;),我会得到 "privileged instruction" 的异常。如果我将类型更改为 "reference to procedure"(如 TOnDevicePlug = reference to procedure stdcall;),我将获得访问冲突异常。这两个错误都是在事件中触发的。

那么你能给我一些建议,让这个活动与我的 class 一起工作吗?将感谢任何想法。或者您可能会在我的代码中看到一些错误。

您的回调必须采用以下形式:

procedure(PluggedIn: Boolean); stdcall;

匿名方法根本不兼容。像这样编写一个单元范围的过程:

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

现在,您正在使用的库在调用此回调时不会提供更多信息。它不会传递额外的指针来允许回调接收者访问他们的状态。

您可以修改您使用的库,以便它可以在您调用它时接受未类型化的指针,然后在您的回调中将该指针传回给您。

如果你不能进行这样的修改,那么你可能需要使用全局变量,甚至是thunk来获取状态。