DLL中的导出函数名称是否区分大小写?

3

我当时在win7和delphi 2010上工作。以下是我的代码:

library CFGFunc;

uses
sysUtils
Un_ExFuncDll in "base\Un_ExFuncDll.pas"
...

exports
LoadExFuncsInDLL,
...

并且Un_ExFuncDll.pas在这里

unit Un_ExFuncDll;
interface    
uses
  Classes;
  procedure LoadexfuncsIndll(); stdcall;
  ...

编译后,动态链接库无法正常工作。 但是,我将LoadexfuncsIndll()替换为与导出项中完全匹配的LoadExFuncsInDLL(),位于Un_ExFuncDll.pas中。然后它可以工作。

Delphi不区分大小写。 但似乎dll中的导出项是区分大小写的。 那么,这些导出项有什么关系呢?


3
这是由操作系统加载器和winapi限制的。可以查看 GetProcAddress 的文档以获取更多信息。 - Sertac Akyuz
唉,如果 Delphi 是大小写敏感的就好了..... - David Heffernan
2个回答

11
导入/导出 DLL 函数是区分大小写的,并且一直以来都是这样。这种行为与 OS DLL 加载器相关,后者是区分大小写的。 这是 Delphi 语言中唯一几个区分大小写的领域之一。 这是已记录的行为,至少部分如此: 编写动态加载库 名称说明符由指令名称后跟字符串常量组成。如果条目没有名称说明符,则使用原始声明名称导出例程,并保持其拼写和大小写相同。当您想要在不同的名称下导出例程时,请使用名称子句。 过程和函数 (Delphi) 在您的导入声明中,请确保精确匹配程序名称的拼写和大小写。稍后,当您调用导入的例程时,名称是不区分大小写的。

1
我很久以前学到的一课是通过一些快速简单的测试来自我确认。 - Jerry Dodge
1
@Jerry 为什么要写测试?只需要阅读文档即可。在MSDN的GetProcAddress文档中已经清楚地说明了。 - David Heffernan
2
我会说,在Delphi中过程Register可能是最后一个区分大小写的东西。Register - TLama
@DavidHeffernan 只需要更改导出函数的大小写,重新编译并检查是否有效。 - Jerry Dodge
@JerryDodge 只需要阅读文档,你就可以确定了。 - David Heffernan
@DavidHeffernan 我只有在通过测试/查看代码等方式进行了一些验证后才会相信文档 - 现在很少单纯相信文档。 - Nicholas Ring

0

如果你的应用程序有数百个导出函数和未知数量的为你的应用程序编写的dll,而且你不小心将某些导出例程的名称改成驼峰命名法,那就真是一个麻烦事。

下面是一种处理方法...

procedure GetExportedFunctions(const ModulePath: string; names: TStringList);

  function RvaToVa(Module: HMODULE; Rva: Cardinal): Pointer;
  begin
    Result := Pointer(Rva + Module);
  end;

var
  Module: HMODULE;
  DosHeader: PImageDosHeader;
  NtHeaders: PImageNtHeaders;
  EntryData: PImageExportDirectory;
  POrd: PWord;
  p: PDWORD;
  i: integer;

begin
  names. Clear;

  Module := LoadLibraryEx(PChar(ModulePath), 0, LOAD_LIBRARY_AS_DATAFILE);
  if Module = 0 then
       RaiseLastOSError;

  try
    DosHeader := PImageDosHeader(Module);
    NtHeaders := PImageNtHeaders(NativeUInt(Module) + DosHeader._lfanew);
    EntryData := RvaToVa(Module, NtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

    if not Assigned(EntryData) then
         Exit;

    with EntryData^ do begin
      POrd := RvaToVa(Module, AddressOfNameOrdinals);
      p := RvaToVa(Module, AddressOfNames);
    end;

    { Function names }
    for i := 0 to EntryData^.NumberOfNames - 1 do begin
      names. Add(string(PAnsiChar(RvaToVa(Module, p^))));
      Inc(p);
      Inc(POrd);
    end;
  finally
    FreeLibrary(Module);
  end;
end; { GetExportedFunctions }

function GPA_CaseInsensitive(Module: HMODULE; const ProcName: string): Pointer;
var
  EnumNames: TStringList;
  i: integer;
  FuncName: string;

begin
  Result := nil;

  EnumNames := TStringList.Create;
  try
    GetExportedFunctions(GetModuleName(Module), EnumNames);
    for i := 0 to EnumNames.count - 1 do begin
      FuncName := EnumNames[i];
      if SameText(FuncName, ProcName) then begin
        Result := GetProcAddress(Module, PChar(FuncName));
        Break;
      end;
    end;

    if not Assigned(Result) then begin
      MessageBox(0, PChar(Format('Function %s not found in module', [ProcName])),
         'DLL Error', MB_SYSTEMMODAL or MB_SETFOREGROUND or MB_TOPMOST or MB_ICONHAND);
    end;
  finally
    EnumNames.Free;
  end;
end; { GPA_CaseInsensitive }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接