xtool/common/LibImport.pas

199 lines
4.9 KiB
ObjectPascal

unit LibImport;
interface
uses
MemoryModule,
WinAPI.Windows,
System.SysUtils, System.Classes, System.Character, System.RTLConsts;
type
TLibImport = class
private
FIsMemoryLib: Boolean;
FDLLLoaded: Boolean;
FImageFileName: String;
FDLLStream: TCustomMemoryStream;
FDLLHandle: NativeUInt;
FImagePtr: Pointer;
FImageSize: NativeInt;
public
constructor Create;
destructor Destroy; override;
procedure LoadLib(ALibrary: String)overload;
procedure LoadLib(AMemory: Pointer; ASize: NativeInt)overload;
procedure LoadLib(AStream: TStream; ASize: NativeInt)overload;
procedure UnloadLib;
function GetProcAddr(AProcName: PAnsiChar): Pointer;
property Loaded: Boolean read FDLLLoaded;
property IsMemory: Boolean read FIsMemoryLib;
property ImageFileName: String read FImageFileName;
property ImagePtr: Pointer read FImagePtr;
property ImageSize: NativeInt read FImageSize;
end;
procedure InjectLib(Source, Dest: String);
implementation
function ResourceExists(ResName: String): Boolean;
begin
Result := FindResourceEx(HInstance, RT_RCDATA, PWideChar(ResName), 0) <> 0;
end;
function FileToResourceName(FileName: String): String;
var
I: Integer;
begin
Result := ExtractFileName(FileName).ToUpper;
for I := 1 to Result.Length do
if not Result[I].IsLetterOrDigit then
Result[I] := '_';
end;
procedure UpdateFileResource(Source, Dest, ResName: string);
var
Stream: TFileStream;
hDestRes: THandle;
lpData: Pointer;
cbData: DWORD;
begin
Stream := TFileStream.Create(Source, fmOpenRead or fmShareDenyNone);
try
Stream.Seek(0, soFromBeginning);
cbData := Stream.Size;
if cbData > 0 then
begin
GetMem(lpData, cbData);
try
Stream.ReadBuffer(lpData^, cbData);
hDestRes := BeginUpdateResource(PChar(Dest), False);
if hDestRes <> 0 then
if UpdateResource(hDestRes, RT_RCDATA, PWideChar(ResName), 0, lpData,
cbData) then
begin
if not EndUpdateResource(hDestRes, False) then
RaiseLastOSError;
end
else
RaiseLastOSError
else
RaiseLastOSError;
finally
FreeMem(lpData);
end;
end;
finally
Stream.Free;
end;
end;
constructor TLibImport.Create;
begin
inherited Create;
FDLLLoaded := False;
FImageFileName := '';
FImagePtr := nil;
FImageSize := 0;
end;
destructor TLibImport.Destroy;
begin
UnloadLib;
inherited Destroy;
end;
procedure TLibImport.LoadLib(ALibrary: String);
var
LResName: String;
szFileName: array [0 .. MAX_PATH] of char;
begin
UnloadLib;
LResName := FileToResourceName(ALibrary);
FIsMemoryLib := ResourceExists(LResName);
if FIsMemoryLib then
begin
FDLLStream := TResourceStream.Create(HInstance, LResName, RT_RCDATA);
WriteLn(ErrOutput, FDLLStream.Size.ToString);
FDLLHandle := NativeUInt(MemoryLoadLibary(FDLLStream.Memory));
FDLLLoaded := Assigned(Pointer(FDLLHandle));
end
else
begin
FDLLStream := TMemoryStream.Create;
FDLLHandle := LoadLibrary(PWideChar(ALibrary));
FDLLLoaded := FDLLHandle >= 32;
if FDLLLoaded then
begin
FillChar(szFileName, sizeof(szFileName), #0);
GetModuleFileName(FDLLHandle, szFileName, MAX_PATH);
end;
end;
FImageFileName := ALibrary;
FImagePtr := FDLLStream.Memory;
FImageSize := FDLLStream.Size;
end;
procedure TLibImport.LoadLib(AMemory: Pointer; ASize: NativeInt);
begin
UnloadLib;
FIsMemoryLib := True;
FDLLStream := TMemoryStream.Create;
FDLLStream.WriteBuffer(AMemory, ASize);
FDLLHandle := NativeUInt(MemoryLoadLibary(FDLLStream.Memory));
FDLLLoaded := Assigned(Pointer(FDLLHandle));
FImageFileName := '';
FImagePtr := FDLLStream.Memory;
FImageSize := FDLLStream.Size;
end;
procedure TLibImport.LoadLib(AStream: TStream; ASize: NativeInt);
begin
UnloadLib;
FIsMemoryLib := True;
FDLLStream := TMemoryStream.Create;
FDLLStream.CopyFrom(AStream, ASize);
FDLLHandle := NativeUInt(MemoryLoadLibary(FDLLStream.Memory));
FDLLLoaded := Assigned(Pointer(FDLLHandle));
FImageFileName := '';
FImagePtr := FDLLStream.Memory;
FImageSize := FDLLStream.Size;
end;
procedure TLibImport.UnloadLib;
begin
if FIsMemoryLib then
begin
MemoryFreeLibrary(Pointer(FDLLHandle));
end
else if FDLLLoaded then
FreeLibrary(FDLLHandle);
if FDLLLoaded then
FDLLStream.Free;
FDLLLoaded := False;
FImagePtr := nil;
FImageSize := 0;
end;
function TLibImport.GetProcAddr(AProcName: PAnsiChar): Pointer;
begin
if not FDLLLoaded then
Result := nil
else if FIsMemoryLib then
Result := MemoryGetProcAddress(Pointer(FDLLHandle), AProcName)
else
Result := GetProcAddress(FDLLHandle, AProcName);
end;
procedure InjectLib(Source, Dest: String);
var
LResName: String;
begin
if not FileExists(Source) then
raise Exception.CreateRes(@SSpecifiedFileNotFound);
LResName := FileToResourceName(Source);
UpdateFileResource(Source, Dest, LResName);
end;
end.