首页 > 解决方案 > 在 Delphi 的泛型函​​数中分配对象的指针函数属性 - 为什么这段代码有效?

问题描述

我已经有 20 多年没有使用 Delphi Pascal 编程了。当前的挑战是以或多或少的 OOP 方式在 Pascal 中包装 C 共享库 API。

我使用的模式是运行时的惰性绑定,即加载库和链接到函数是按需执行的。Pascal 端 API 被声明为具有许多指定类型的函数指针成员的对象 - 每个成员都GetProcAddress通过适当的后检查初始化为 's 结果。

我决定包装代码中最烦人和重复的部分,即按名称获取地址、分配、检查结果、检索错误消息并在 Pascal 泛型中报告结果。使用 C++ 模板可以轻松完成的事情在 Pascal 中出现了自己的挑战:

  1. 作为泛型参数的Pointer类型使用似乎受到限制。
  2. 没有简单的方法可以将简单(不是对象成员)函数指针转换为无类型指针或从无类型指针转换。

我找到的唯一可行的解​​决方案如下:

type PfnMemberT<pfnT> = record
  type PpfnT = ^pfnT;
  public
    class function assign(var member : PpfnT; const name : UnicodeString; var error : UnicodeString) : Boolean; static;
end;
    
class function PfnMemberT<pfnT>.assign(var member : PpfnT; const name : UnicodeString; var error : UnicodeString) : Boolean;
    begin
      Result := false;
      
      Assert(EsCore.instance.isLoaded); {EsCore.instance is a pointer to a library loader singleton}
      
      var pfnAddr : NativeUInt := NativeUInt(
        GetProcAddress(
          EsCore.instance.hlib,
          PWideChar(name)
        )
      );
    
      if 0 = pfnAddr then begin
        error := 'Error binding function ''' + name 
    {$IFNDEF POSIX}
          + ''': ''' + SysErrorMessage(GetLastError()) + ''''
    {$ENDIF}
        ;
        
      end else begin
        Result := true;
        PNativeUInt(member) := PNativeUInt(pfnAddr);
      end;
    end;

它在如下使用时起作用:

    if 
      not PfnMemberT<esResultStringGetPfn>.assign(
        PfnMemberT<esResultStringGetPfn>.PpfnT( @m_esResultStringGet ),
        'esResultStringGet',
        m_errmsg
      ) 
    then 
      exit;
    
    if 
      not PfnMemberT<esResultSeverityGetPfn>.assign(
        PfnMemberT<esResultSeverityGetPfn>.PpfnT( @m_esResultSeverityGet ),
        'esResultSeverityGet',
        m_errmsg
      ) 
    then 
      exit;
    
    if 
      not PfnMemberT<esResultFacilityPfn>.assign(
        PfnMemberT<esResultFacilityPfn>.PpfnT( @m_esResultFacilityGet ),
        'esResultFacilityGet',
        m_errmsg
      ) 
    then 
      exit;

我不想说:我不完全理解它为什么起作用。而且我不喜欢我不完全理解的代码。

任何具有现代 Pascal 知识的人都可以向我解释我的代码中发生了什么吗?

标签: pointersdelphigenericsfunction-pointersmember-pointers

解决方案


推荐阅读