Sto lavorando a qualcosa che carica dinamicamente DLL appositamente formulate. Devo essere in grado di controllare la DLL e assicurarsi che tutte le funzioni previste esistano prima di considerare l'utilizzo di questa DLL. Se mancano alcune funzioni, non dovrei provare a caricarlo. So che potrei provare a chiamare una delle funzioni e vedere se c'è un'eccezione, ma vedrei gli errori in modalità di debug.Come controllare una DLL se esiste una funzione?
Come devo verificare la presenza di una DLL se esiste una funzione? Vorrei controllarlo prima del Lo carico (usando LoadLibrary
) ma suppongo che sia OK se devo caricarlo per eseguire anche questo controllo.
UPDATE
ho accettato la risposta di David qui sotto, e ho pensato di postare il mio codice finale per mostrare l'intero processo. L'ho trasformato in una funzione che restituisce un Bool, che sia riuscita o meno, ha pulito un po 'il codice e ha aggiunto un'altra funzione nella parte inferiore che utilizza questo per controllare ciascun nome uno per uno.
Ho deciso di utilizzare questo metodo invece di leggere GetProcAddress
perché mi aiuterà in futuro con altre cose.
type
PIMAGE_NT_HEADERS = ^IMAGE_NT_HEADERS;
PIMAGE_EXPORT_DIRECTORY = ^IMAGE_EXPORT_DIRECTORY;
function ImageNtHeader(Base: Pointer): PIMAGE_NT_HEADERS; stdcall;
external 'dbghelp.dll';
function ImageRvaToVa(NtHeaders: Pointer; Base: Pointer; Rva: ULONG;
LastRvaSection: Pointer): Pointer; stdcall; external 'dbghelp.dll';
function ExportedFunctionNames(const ImageName: string; NamesList: TStrings): Bool;
var
i: Integer;
FileHandle: THandle;
ImageHandle: THandle;
ImagePointer: Pointer;
Header: PIMAGE_NT_HEADERS;
ExportTable: PIMAGE_EXPORT_DIRECTORY;
NamesPointer: Pointer;
Names: PAnsiChar;
NamesDataLeft: Integer;
begin
Result:= False;
NamesList.Clear;
FileHandle:= CreateFile(PChar(ImageName), GENERIC_READ, FILE_SHARE_READ,
nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if FileHandle = INVALID_HANDLE_VALUE then Exit;
try
ImageHandle:= CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil);
if ImageHandle = 0 then Exit;
try
ImagePointer:= MapViewOfFile(ImageHandle, FILE_MAP_READ, 0, 0, 0);
if not Assigned(ImagePointer) then Exit;
try
Header:= ImageNtHeader(ImagePointer);
if not Assigned(Header) then Exit;
if Header.Signature <> $00004550 then Exit; // "PE\0\0" as a DWORD.
ExportTable:= ImageRvaToVa(Header, ImagePointer,
Header.OptionalHeader.DataDirectory[0].VirtualAddress, nil);
if not Assigned(ExportTable) then Exit;
NamesPointer:= ImageRvaToVa(Header, ImagePointer,
Cardinal(ExportTable.AddressOfNames), nil);
if not Assigned(NamesPointer) then Exit;
Names:= ImageRvaToVa(Header, ImagePointer, Cardinal(NamesPointer^), nil);
if not Assigned(Names) then Exit;
NamesDataLeft:= Header.OptionalHeader.DataDirectory[0].Size;
for i:= 0 to ExportTable.NumberOfNames - 1 do begin
NamesList.Add(Names);
while (Names^ <> chr(0)) and (NamesDataLeft > 0) do begin
Inc(Names);
Dec(NamesDataLeft);
end;
Inc(Names);
end;
Result:= True;
finally
UnmapViewOfFile(ImagePointer);
end;
finally
CloseHandle(ImageHandle);
end;
finally
CloseHandle(FileHandle);
end;
end;
function IsMyDLL(const Filename: String): Bool;
var
H: THandle;
L: TStringList;
function InList(const Func: String): Bool;
begin
Result:= L.IndexOf(Func) >= 0;
end;
begin
Result:= False;
L:= TStringList.Create;
try
if ExportedFunctionNames(Filename, L) then begin
Result:=//Names of functions which need to exist
InList('GetName') and
InList('GetDescription') and
InList('GetVersion') and
InList('Start') and
InList('Stop');
end;
finally
L.Free;
end;
end;
Sembra promettente, e quando torno alla mia scrivania faccio un tentativo: D Questa potrebbe essere la strada giusta, ho accettato troppo presto ... –
Bene, questo è un codice provato e testato. Ma cosa ti impedisce di utilizzare LoadLibrary e GetProcAddress? Sapendo che potrebbe aiutare. –
Perché in realtà dovrò capire come elencare queste funzioni alla fine per questo progetto comunque :) –