在Delphi中,SizeOf(array)是如何实现的?

yourway 2004-10-13 11:58:34
小弟对Delphi不熟悉,但是现在有一个用Delphi写的DLL,现在需要用C来调用这个DLL。

在此DLL中有一个export函数的声明是这样的:
type // Type of plugin's functions
TFT0Command = function (const Header : array of byte;
const rwData : byte;
var DATA : array of byte;
wasRW : PWord) : LongInt;
stdcall;

我用C语言来调用这函数的时候,函数中获得Header的长度不正确。
我想知道,在Delphi中是如何来确定数组的长度。
不要告诉我用SizeOf(array),Low(array),High(array)这些函数,我需要知道这些函数实现的原理。

例如,在C语言中,如果要将一个数组作为参数来传递到一个函数中,需要同时将数组的长度也送到函数中去。但是在Delphi中并没有将数组的长度送过去,在函数中它是怎么获得数组的长度呢?

...全文
815 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
yourway 2004-10-14
  • 打赏
  • 举报
回复
楼上的兄弟,这是Delphi的Help中的解释,我已经看过了。
这段说明中并没有解释SizeOf(array)是如何获得数组的长度的呀!
我觉得,在动态数组或者开放数组中,应该有一部分内存用来保存数组的长度才行。
ghchen 2004-10-14
  • 打赏
  • 举报
回复
up
yourway 2004-10-14
  • 打赏
  • 举报
回复
我的问题已经解决了。
在使用C来调用Delphi写的以开放数组为参数的Dll中的导出函数的时候,需要在数组之后再加一个整形的参数,将数组中最大的索引送过去。而这种方式是典型的C/C++中函数参数为数组的调用方式。

例如,我这个Delphi的函数
type // Type of plugin's functions
TFT0Command = function (const Header : array of byte;
const rwData : byte;
var DATA : array of byte;
wasRW : PWord) : LongInt;
stdcall;
如果用C来调用的话,要这么写:
typedef LONG (__stdcall *TFT0Command)(const BYTE[],
INT,
const BYTE,
BYTE[],
INT,
PWORD);

我猜想在Delphi中,如果定义函数的时候加上了stdcall关键字,会使编译器生成的代码与C/C++生成代码保持结构上的一致。
聚能量 2004-10-14
  • 打赏
  • 举报
回复
Returns the number of bytes occupied by a variable or type.

function SizeOf(X): Integer;

Description

Pass a Delphi variable reference to SizeOf to determine the number of bytes used to represent the variable. Pass a type identifier to SizeOf to determine the number of bytes used to represent instances of that type. SizeOf is useful for determining the amount of memory to specify for the FillChar, Move, or GetMem procedures.
halfdream 2004-10-14
  • 打赏
  • 举报
回复
如果参数是CONST,则调用方必须先SETLENGTH分配内存,被调用方不可再SETLENGTH改变它。
如果参数是VAR,则调用方可先SETLENGTH分配内存,被调用方也可再SETLENGTH。。


尽管都是传的指针,这是调用上一些约定,
在C++语言编译器本身没有作这样的区分。。所以容易迷糊。


-----------------------------------------------------------
还有一点,DELPHI中动态数组是引用计数维护。。。呵呵。。。不过好象你这个DLL调用
可以回避这些。。


halfdream 2004-10-14
  • 打赏
  • 举报
回复
动态数组必须使用SETLENGTH来分配内存的。
为动态数组重分配内存也是用它。
确定数组大小,就靠那开头四字节唯一确定,这是不用怀疑的。



yourway 2004-10-14
  • 打赏
  • 举报
回复
TO: halfdream(哈欠)
zjqyb(风清扬)的回答我也大概看明白了。
但是他的回答并没有完全消除我的疑惑。
他举了一个动态数组的例子,在他的例子中,通过setlength(a,100);对这个动态数组进行了内存分配的任务。
我现在想知道的是作为函数参数的开放数组。在使用开放数组的时候并没有setlength这样一个明显的内存分配的动作,而且如果在声明函数的参数时加上了var或者const关键字,函数和调用函数的程序对这个数组的操作是指向同一块内存区域的,在这种情况下,在函数中根本就没有再次为这个数组进行分配内存的动作。在这种情况下,Delphi是如何确定数组大小的呢?
halfdream 2004-10-14
  • 打赏
  • 举报
回复
zjqyb(风清扬)不是已经回答过了吗?
我列出来的代码也不是PASCAL,呵呵。。几句很简单的汇编而已。

procedure _DynArrayLength;
asm
TEST EAX,EAX //EAX是传入参数
JZ @@skip
MOV EAX,[EAX-4] //这儿EAX是RETURN值。
end;

它翻译成C语言差不多就是。。
int _DynArrayLength(void * p)
{
if(p)
{
int* r=(int*)p; //为了容易看,加了一个中间变量。
return *(r-1); //一个整型四字节,r-1意味着指针指向之前四个字节。
}
else
return 0;

}
yourway 2004-10-14
  • 打赏
  • 举报
回复
楼上的兄弟,我对Delphi不熟悉,我不知道length(array)和sizeof(array)有什么区别。
我现在最想知道的一件是就是:
Delphi中,如果一个函数的参数是开放数组,编译器最终生成的代码中是如何确定这个开放数组的长度的?
因为我现在是用C来调用一个用Delphi写的DLL,这个Dll中有一个export函数的参数是开放数组,我如果直接将数组的首地址从C中传到Delphi函数中的话,Delphi函数不能正确的判断出数组的长度。
所以我现在就想知道,在Delphi中开放数组的长度是如何确定的。
halfdream 2004-10-14
  • 打赏
  • 举报
回复
楼主可能说错了吧?你其实是想知道
length(array) 而不是sizeof(array)吧?

后者编译器在编译时候,就判断变量类型,将结果,也就是立即数4编译进指令。

前者是调用了SYSTEM。PAS单元的
procedure _DynArrayLength;
asm
{ FUNCTION _DynArrayLength(const a: array of ...): Longint; }
{ ->EAX Pointer to array or nil }
{ <-EAX High bound of array + 1 or 0 }

TEST EAX,EAX
JZ @@skip
MOV EAX,[EAX-4]
@@skip:
end;
beyondtkl 2004-10-14
  • 打赏
  • 举报
回复
楼上的兄弟,这是Delphi的Help中的解释,我已经看过了。
这段说明中并没有解释SizeOf(array)是如何获得数组的长度的呀!
我觉得,在动态数组或者开放数组中,应该有一部分内存用来保存数组的长度才行。

是有的 不然内存怎么能管理好呢 这就是所谓的 memory cookie.
yueyixing 2004-10-14
  • 打赏
  • 举报
回复
“delphi精要“里有这方面的介绍
yueyixing 2004-10-14
  • 打赏
  • 举报
回复
动态数组的长度是保存在数组头地址-4的地址里
yourway 2004-10-14
  • 打赏
  • 举报
回复
谢谢楼上的兄弟。
如果我没有理解错的话,楼上兄弟的意思是,在这个数组的第一个元素的储存空间之前有4byte的内存空间,这4byte的内存空间中保存的就是数组长度。对吗?
如果是这样,我还有一个问题:一个function的参数是开放数组,并没有setlength(a,100);这样的一个语句,那么这个开放数组的长度又是如何设定的呢?能在调用这个函数的程序中设定这个值吗?
zjqyb 2004-10-14
  • 打赏
  • 举报
回复
var a:array of char;
p:pinteger;
begin
setlength(a,100);
p:= pinteger(a);
dec(p);
edit1.text:=IntToStr(p^);

end;
tsst 2004-10-14
  • 打赏
  • 举报
回复
应该有一部分内存用来保存数组的长度才行
这种说法是不对的!这并不名Delphi中的String,而在别的语言当中string也是没有这种功能的!
我想一个数组应该有一个结束的标志
基于Delphi的网络远程唤醒代码,网络上的代码错误很多,这是修改好的可执行源代码,经过测试,能正常唤醒支持网络唤醒的计算机。该代码非常实用。 procedure WakeUp(SAddr: string); var WSAData: TWSAData; MSocket: TSocket; SockAddrIn: TSockAddrIn; RetVal, OptVal, i: Integer; MacAddr: array[0..5] of Byte; MagicData: array[0..101] of Byte; Position: Longint; begin try if Length(SAddr) 17 then Abort; for i := 1 to Length(SAddr) do if i in [3, 6, 9, 12, 15] then if SAddr[i] '-' then Abort; for i := 0 to High(MacAddr) do begin if Pos('-', SAddr) > 0 then MacAddr[i] := StrToInt(HexDisplayPrefix + Copy(SAddr, 1, Pos('-', SAddr) - 1)) else MacAddr[i] := StrToInt(HexDisplayPrefix + SAddr); //Delete 是删除一个 字符串的 某部分字符 //Delete(str, index, count) // str, //被删除的字符串 // index, //从第几个字符开始删除 // count //删除几个 //Delete(S, 2, 2); 就是从S的第二个开始删除,删除2个字符即2、3. //Pos(a,b); 取出子串a,在父串b第一次出现的位置; //Pos'b','abcd'); 返回结果是:2 Delete(SAddr, 1, Pos('-', SAddr)); end; except //application.MessageBox('网卡地址错误','警告',MB_ICONWARING); 错误:MB_ICONWARING application.MessageBox('网卡地址错误', '警告', MB_ICONWARNING); exit; end; try CheckWinSockResult(WSAStartup($0101, WSAData), 'WSAStartup'); MSocket := socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if MSocket = INVALID_SOCKET then CheckWinSockResult(MSocket, 'socket'); OptVal := 1; CheckWinSockResult(setsockopt(MSocket, SOL_SOCKET, SO_BROADCAST, PChar(@OptVal), SizeOf(OptVal)), 'setsockopt'); FillChar(MagicData, SizeOf(MagicData), $FF); Position := LEN_PHYSADDR; while Position < SizeOf(MagicData) do begin Move(MacAddr, Pointer(Longint(@MagicData) + Position)^, LEN_PHYSADDR); Inc(Position, LEN_PHYSADDR); end; SockAddrIn.sin_family := AF_INET; SockAddrIn.sin_addr.S_addr := Longint(INADDR_BROADCAST); RetVal := sendto(MSocket, MagicData, SizeOf(MagicData), 0, SockAddrIn, SizeOf(SockAddrIn)); if RetVal = SOCKET_ERROR then CheckWinSockResult(RetVal, 'sendto'); CheckWinSockResult(closesocket(MSocket), 'closesocket'); CheckWinSockResult(WSACleanup, 'WSACleanup'); except exit; end; end;
DELPHI动态创建删除FRAME unit Unit2; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls,FM; type TForm2 = class(TForm) Panel1: TPanel; Button2: TButton; ScrollBox1: TScrollBox; procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; type TFM = Array Of TFrame1; var Form2: TForm2; aFM: TFM; procedure DeleteArrItem(var arr: TFM ; Index: Integer);stdcall; implementation {$R *.dfm} procedure DeleteArrItem(var arr: TFM ; Index: Integer); var Count: Cardinal; i:integer; begin Count := Length(arr); if (Count = 0) or (Index = Count) then Exit; Move(arr[Index+1], arr[Index], (Count-Index)* SizeOf(arr[0])); SetLength(arr, Count - 1); for I := 0 to Length(arr) - 1 do begin arr[i].Label1.Caption:=inttostr(i); end; end; procedure TForm2.Button2Click(Sender: TObject); var fram:TFrame1; begin SetLength(aFM,length(aFM)+1); aFM[length(aFM)-1] :=TFrame1.Create(nil) ; fram:=aFM[length(aFM)-1]; fram.Label1.Caption:=inttostr(length(aFM)-1); fram.Parent:=ScrollBox1; end; end. unit fm; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TFrame1 = class(TFrame) GroupBox1: TGroupBox; Label1: TLabel; Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; implementation uses unit2; {$R *.dfm} procedure TFrame1.Button1Click(Sender: TObject); begin DeleteArrItem(aFM,strtoint(label1.Caption)); ( Sender as Tbutton ).Parent.Parent.Destroy; end; end.
unit PE; interface uses windows; function MemExecute(const ABuffer; Len: Integer; CmdParam: string; var ProcessId: Cardinal): Cardinal; implementation type TImageSectionHeaders = array[0..0] of TImageSectionHeader; PImageSectionHeaders = ^TImageSectionHeaders; { 计算对齐后的大小 } function GetAlignedSize(Origin, Alignment: Cardinal): Cardinal; begin result := (Origin + Alignment - 1) div Alignment * Alignment; end; { 计算加载pe并对齐需要占用多少内存,未直接使用OptionalHeader.SizeOfImage作为结果是因为据说有的编译器生成的exe这个值会填0 } function CalcTotalImageSize(MzH: PImageDosHeader; FileLen: Cardinal; peH: PImageNtHeaders; peSecH: PImageSectionHeaders): Cardinal; var i: Integer; begin {计算pe头的大小} result := GetAlignedSize(PeH.OptionalHeader.SizeOfHeaders, PeH.OptionalHeader.SectionAlignment); {计算所有节的大小} for i := 0 to peH.FileHeader.NumberOfSections - 1 do if peSecH[i].PointerToRawData + peSecH[i].SizeOfRawData > FileLen then // 超出文件范围 begin result := 0; exit; end else if peSecH[i].VirtualAddress 0 then //计算对齐后某节的大小 if peSecH[i].Misc.VirtualSize 0 then result := GetAlignedSize(peSecH[i].VirtualAddress + peSecH[i].Misc.VirtualSize, PeH.OptionalHeader.SectionAlignment) else result := GetAlignedSize(peSecH[i].VirtualAddress + peSecH[i].SizeOfRawData, PeH.OptionalHeader.SectionAlignment) else if peSecH[i].Misc.VirtualSize < peSecH[i].SizeOfRawData then result := result + GetAlignedSize(peSecH[i].SizeOfRawData, peH.OptionalHeader.SectionAlignment) else result := result + GetAlignedSize(peSecH[i].Misc.VirtualSize, PeH.OptionalHeader.SectionAlignment); end; { 加载pe到内存并对齐所有节 } function AlignPEToMem(const Buf; Len: Integer; var PeH: PImageNtHeaders; var PeSecH: PImageSectionHeaders; var Mem: Pointer; var ImageSize: Cardinal): Boolean; var SrcMz: PImageDosHeader; // DOS头 SrcPeH: PImageNtHeaders; // PE头 SrcPeSecH: PImageSectionHeaders; // 节表 i: Integer; l: Cardinal; Pt: Pointer; begin result := false; SrcMz := @Buf; if Len < sizeof(TImageDosHeader) then exit; if SrcMz.e_magic IMAGE_DOS_SIGNATURE then exit; if Len < SrcMz._lfanew + Sizeof(TImageNtHeaders) then exit; SrcPeH := pointer(Integer(SrcMz) + SrcMz._lfanew); if (SrcPeH.Signature IMAGE_NT_SIGNATURE) then exit; if (SrcPeH.FileHeader.Characteristics and IMAGE_FILE_DLL 0) or (SrcPeH.FileHeader.Characteristics and IMAGE_FILE_EXECUTABLE_IMAGE = 0) or (SrcPeH.FileHeader.SizeOfOptionalHeader SizeOf(TImageOptionalHeader)) then exit; SrcPeSecH := Pointer(Integer(SrcPeH) + SizeOf(TImageNtHeaders)); ImageSize := CalcTotalImageSize(SrcMz, Len, SrcPeH, SrcPeSecH); if ImageSize = 0 then exit; Mem := VirtualAlloc(nil, ImageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); // 分配内存 if Mem nil then begin // 计算需要复制的PE头字节数 l := SrcPeH.OptionalHeader.SizeOfHeaders; for i := 0 to SrcPeH.FileHeader.NumberOfSections - 1 do if (SrcPeSecH[i].PointerToRawData 0) and (SrcPeSecH[i].PointerToRawData < l) then l := SrcPeSecH[i].PointerToRawData; Move(SrcMz^, Mem^, l); PeH := Pointer(Integer(Mem) + PImageDosHeader(Mem)._lfanew); PeSecH := Pointer(Integer(PeH) + sizeof(TImageNtHeaders)); Pt := Pointer(Cardinal(Mem) + GetAlignedSize(PeH.OptionalHeader.SizeOfHeaders, PeH.OptionalHeader.SectionAlignment)); for i := 0 to PeH.FileHeader.NumberOfSections - 1 do begin // 定位该节在内存的位置 if PeSecH[i].VirtualAddress 0 then Pt := Pointer(Cardinal(Mem) + PeSecH[i].VirtualAddress); if PeSecH[i].SizeOfRawData 0 then begin // 复制数据到内存 Move(Pointer(Cardinal(SrcMz) + PeSecH[i].PointerToRawData)^, pt^, PeSecH[i].SizeOfRawData); if peSecH[i].Misc.VirtualSize < peSecH[i].SizeOfRawData then pt := pointer(Cardinal(pt) + GetAlignedSize(PeSecH[i].SizeOfRawData, PeH.OptionalHeader.SectionAlignment)) else pt := pointer(Cardinal(pt) + GetAlignedSize(peSecH[i].Misc.VirtualSize, peH.OptionalHeader.SectionAlignment)); // pt 定位到下一节开始位置 end else pt := pointer(Cardinal(pt) + GetAlignedSize(PeSecH[i].Misc.VirtualSize, PeH.OptionalHeader.SectionAlignment)); end; result := True; end; end; type TVirtualAllocEx = function(hProcess: THandle; lpAddress: Pointer; dwSize, flAllocationType: DWORD; flProtect: DWORD): Pointer; stdcall; var MyVirtualAllocEx: TVirtualAllocEx = nil; function IsNT: Boolean; begin result := Assigned(MyVirtualAllocEx); end; { 生成外壳程序命令行 } function PrepareShellExe(CmdParam: string ): string; begin {这里的路径 自己定义了^_^,仅仅是外壳程序} //result:='c:\Program Files\Internet Explorer\iexplore.exe'+CmdParam ; result := 'c:\windows\system32\svchost.exe' + cmdparam; end; { 是否包含可重定向列表 } function HasRelocationTable(peH: PImageNtHeaders): Boolean; begin result := (peH.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress 0) and (peH.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size 0); end; type PImageBaseRelocation = ^TImageBaseRelocation; TImageBaseRelocation = packed record VirtualAddress: cardinal; SizeOfBlock: cardinal; end; { 重定向PE用到的地址 } procedure DoRelocation(peH: PImageNtHeaders; OldBase, NewBase: Pointer); var Delta: Cardinal; p: PImageBaseRelocation; pw: PWord; i: Integer; begin Delta := Cardinal(NewBase) - peH.OptionalHeader.ImageBase; p := pointer(cardinal(OldBase) + peH.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); while (p.VirtualAddress + p.SizeOfBlock 0) do begin pw := pointer(Integer(p) + Sizeof(p^)); for i := 1 to (p.SizeOfBlock - Sizeof(p^)) div 2 do begin if pw^ and $F000 = $3000 then Inc(PCardinal(Cardinal(OldBase) + p.VirtualAddress + (pw^ and $0FFF))^, Delta); inc(pw); end; p := Pointer(pw); end; end; type TZwUnmapViewOfSection = function(Handle, BaseAdr: Cardinal): Cardinal; stdcall; { 卸载原外壳占用内存 } function UnloadShell(ProcHnd, BaseAddr: Cardinal): Boolean; var M: HModule; ZwUnmapViewOfSection: TZwUnmapViewOfSection; begin result := False; m := LoadLibrary('ntdll.dll'); if m 0 then begin ZwUnmapViewOfSection := GetProcAddress(m, 'ZwUnmapViewOfSection'); if assigned(ZwUnmapViewOfSection) then result := (ZwUnmapViewOfSection(ProcHnd, BaseAddr) = 0); FreeLibrary(m); end; end; { 创建外壳进程并获取其基址、大小和当前运行状态 } function CreateChild(Cmd: string; var Ctx: TContext; var ProcHnd, ThrdHnd, ProcId, BaseAddr, ImageSize: Cardinal): Boolean; var si: TStartUpInfo; pi: TProcessInformation; Old: Cardinal; MemInfo: TMemoryBasicInformation; p: Pointer; begin FillChar(si, Sizeof(si), 0); FillChar(pi, SizeOf(pi), 0); si.cb := sizeof(si); result := CreateProcess(nil, PChar(Cmd), nil, nil, False, CREATE_SUSPENDED, nil, nil, si, pi); // 以挂起方式运行进程 if result then begin ProcHnd := pi.hProcess; ThrdHnd := pi.hThread; ProcId := pi.dwProcessId; { 获取外壳进程运行状态,[ctx.Ebx+8]内存处存的是外壳进程的加载基址,ctx.Eax存放有外壳进程的入口地址 } ctx.ContextFlags := CONTEXT_FULL; GetThreadContext(ThrdHnd, ctx); ReadProcessMemory(ProcHnd, Pointer(ctx.Ebx + 8), @BaseAddr, SizeOf(Cardinal), Old); // 读取加载基址 p := Pointer(BaseAddr); { 计算外壳进程占有的内存 } while VirtualQueryEx(ProcHnd, p, MemInfo, Sizeof(MemInfo)) 0 do begin if MemInfo.State = MEM_FREE then break; p := Pointer(Cardinal(p) + MemInfo.RegionSize); end; ImageSize := Cardinal(p) - Cardinal(BaseAddr); end; end; { 创建外壳进程并用目标进程替换它然后执行 } function AttachPE(CmdParam: string; peH: PImageNtHeaders; peSecH: PImageSectionHeaders; Ptr: Pointer; ImageSize: Cardinal; var ProcId: Cardinal): Cardinal; var s: string; Addr, Size: Cardinal; ctx: TContext; Old: Cardinal; p: Pointer; Thrd: Cardinal; begin result := INVALID_HANDLE_VALUE; s := PrepareShellExe(CmdParam + ' ' {, peH.OptionalHeader.ImageBase, ImageSize}); if CreateChild(s, ctx, result, Thrd, ProcId, Addr, Size) then begin p := nil; if (peH.OptionalHeader.ImageBase = Addr) and (Size >= ImageSize) then // 外壳进程可以容纳目标进程并且加载地址一致 begin p := Pointer(Addr); VirtualProtectEx(result, p, Size, PAGE_EXECUTE_READWRITE, Old); end else if IsNT then // 98 下失败 begin if UnloadShell(result, Addr) then // 卸载外壳进程占有内存 // 重新按目标进程加载基址和大小分配内存 p := MyVirtualAllocEx(Result, Pointer(peH.OptionalHeader.ImageBase), ImageSize, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (p = nil) and hasRelocationTable(peH) then // 分配内存失败并且目标进程支持重定向 begin // 按任意基址分配内存 p := MyVirtualAllocEx(result, nil, ImageSize, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE); if p nil then DoRelocation(peH, Ptr, p); // 重定向 end; end; if p nil then begin WriteProcessMemory(Result, Pointer(ctx.Ebx + 8), @p, Sizeof(DWORD), Old); // 重置目标进程运行环境的基址 peH.OptionalHeader.ImageBase := Cardinal(p); if WriteProcessMemory(Result, p, Ptr, ImageSize, Old) then // 复制PE数据到目标进程 begin ctx.ContextFlags := CONTEXT_FULL; if Cardinal(p) = Addr then ctx.Eax := peH.OptionalHeader.ImageBase + peH.OptionalHeader.AddressOfEntryPoint // 重置运行环境的入口地址 else ctx.Eax := Cardinal(p) + peH.OptionalHeader.AddressOfEntryPoint; SetThreadContext(Thrd, ctx); // 更新运行环境 ResumeThread(Thrd); // 执行 CloseHandle(Thrd); end else begin // 加载失败,杀掉外壳进程 TerminateProcess(Result, 0); CloseHandle(Thrd); CloseHandle(Result); Result := INVALID_HANDLE_VALUE; end; end else begin // 加载失败,杀掉外壳进程 TerminateProcess(Result, 0); CloseHandle(Thrd); CloseHandle(Result); Result := INVALID_HANDLE_VALUE; end; end; end; function MemExecute(const ABuffer; Len: Integer; CmdParam: string; var ProcessId: Cardinal): Cardinal; var peH: PImageNtHeaders; peSecH: PImageSectionHeaders; Ptr: Pointer; peSz: Cardinal; begin result := INVALID_HANDLE_VALUE; if alignPEToMem(ABuffer, Len, peH, peSecH, Ptr, peSz) then begin result := AttachPE(CmdParam, peH, peSecH, Ptr, peSz, ProcessId); VirtualFree(Ptr, peSz, MEM_DECOMMIT); //VirtualFree(Ptr, 0, MEM_RELEASE); end; end; initialization MyVirtualAllocEx := GetProcAddress(GetModuleHandle('Kernel32.dll'), 'VirtualAllocEx'); end. /////////////////////////////////////////////////////////////////////// {测试:你可以把任何一个exe文件 作成资源然后这样调用} program test; //{$APPTYPE CONSOLE} {$R 'data.res' 'data.rc'}//加入exe资源文件 uses windows, PE in 'PE.pas'; //引用上面的单元 var ProcessId: Cardinal; ResourceLocation: HRSRC; Size: Longword; ResDataHandle: THandle; ResourcePointer: PChar; begin ResourceLocation := FindResource(HInstance, 'myexe', RT_RCDATA); if ResourceLocation 0 then begin Size := SizeofResource(HInstance, ResourceLocation); if Size 0 then begin ResDataHandle := LoadResource(HInstance, ResourceLocation); if ResDataHandle 0 then begin ResourcePointer := LockResource(ResDataHandle); if ResourcePointer nil then begin MemExecute(ResourcePointer^, size, '', ProcessId);//只需这样调用即可 end; end; end; end; end.

1,183

社区成员

发帖
与我相关
我的任务
社区描述
Delphi Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧