不同进程之间如何通过DLL共享数据,望高手相助 (100分)

  • 主题发起人 主题发起人 happyxhl
  • 开始时间 开始时间
H

happyxhl

Unregistered / Unconfirmed
GUEST, unregistred user!
DLL代码如下:<br>library Conn;<br><br>uses<br>&nbsp; SysUtils,<br>&nbsp; Classes,<br>&nbsp; ShareMem,<br>&nbsp; Windows,<br>&nbsp; Dialogs,<br>&nbsp; DBTables;<br><br><br>var<br>&nbsp; hMem:THandle;<br>&nbsp; pMem:PChar;<br><br>function GetGlobalMem:THandle;export;<br>begin<br>&nbsp; Result := hMem;<br>end;<br><br>procedure OpenSharedData;<br>begin<br>&nbsp; size := SizeOf(TGlobalDLLData);<br>&nbsp; hMem := GlobalAlloc(gmem_MOVEABLE and gmem_DDEShare,100);<br>&nbsp; if hMem = 0 then<br>&nbsp; &nbsp; MessageDlg('Could not allocate memory',mtWarning,[mbOK],0)<br>&nbsp; else<br>&nbsp; &nbsp; showmessage('Init OK!');<br>end;<br><br>procedure CloseSharedData;<br>begin<br>&nbsp; CloseHandle(hMem);<br>end;<br><br>procedure DLLEntryPoint(dwReason:DWord);<br>begin<br>&nbsp; case dwReason Of<br>&nbsp; &nbsp; DLL_PROCESS_ATTACH:OpenSharedData;<br>&nbsp; &nbsp; DLL_PROCESS_DETACH:begin showmessage('DETACH……');CloseSharedData;end;<br>&nbsp; end;<br>end;<br><br>exports<br>&nbsp; GetGlobalMem;<br><br>begin<br>&nbsp; //通过DLLProc变量建立一个入口/出口函数<br>&nbsp; showmessage('Loading');<br>&nbsp; DllProc := @DLLEntryPoint;<br>&nbsp; DLLEntryPoint(DLL_PROCESS_ATTACH);<br>end.<br>写DLL共享数据的代码如下:<br>function GetGlobalMem: THandle; far; external DllName;<br><br>procedure TfrmMain.FormActivate(Sender: TObject);<br>Var<br>&nbsp; hMem:THandle;<br>&nbsp; pMem:PChar;<br><br>begin<br>&nbsp; hMem := GetGlobalMem;<br>&nbsp; if hMem &lt;&gt; 0 then<br>&nbsp; Begin<br>&nbsp; &nbsp; pMem := GlobalLock(hMem);<br>&nbsp; &nbsp; if pMem &lt;&gt; nil then<br>&nbsp; &nbsp; Begin<br>&nbsp; &nbsp; &nbsp; StrPCopy(pMem,'测试数据');<br>&nbsp; &nbsp; &nbsp; GlobalUnLock(hMem);<br>&nbsp; &nbsp; End<br>&nbsp; &nbsp; Else<br>&nbsp; &nbsp; &nbsp; MessageDlg('Couldnot Lock memory block',mtWarning,[mbOK],0);<br>&nbsp; End;<br>end;<br>其它程序读共享数据的代码如下:<br>function GetGlobalMem: THandle; far; external DllName;<br><br>procedure TForm1.Button1Click(Sender: TObject);<br>var<br>&nbsp; hMem: THandle;<br>&nbsp; pMem: PChar;<br>begin<br>&nbsp; hMem := GetGlobalMem; {获得全局内存块的句柄}<br>&nbsp; if hMem &lt;&gt; 0 then<br>&nbsp; begin<br>&nbsp; &nbsp; pMem := GlobalLock(hMem); {加锁全局内存块}<br>&nbsp; &nbsp; if pMem &lt;&gt; nil then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; Edit1.Text := StrPas(pMem);<br>&nbsp; &nbsp; &nbsp; GlobalUnlock(hMem); {解锁全局内存块}<br>&nbsp; &nbsp; end<br>&nbsp; &nbsp; else<br>&nbsp; &nbsp; &nbsp; MessageDlg('Couldnot Lock memory block',mtWarning,[mbOK],0);<br>&nbsp; end;<br>end;<br>但每次都传不了数据,出现乱码。而且程序运行时没问题,但一退出就会出错:<br>0x002962ce指令引用的"0x013509cc"内存。该内存不能为"read"。<br>不知道错误错在哪里,各位在用DLL共享数据时用什么方法的?<br>
 
win32下DLL已不能共享数据了,每个进程中它们有独立的拷贝<br>可以用文件映射
 
unit Unit1;<br><br>interface<br><br>uses<br>&nbsp; Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,<br>&nbsp; StdCtrls;<br><br>const<br>&nbsp; WM_DATA = WM_USER + 1024;<br>type<br>&nbsp; PShareMem = ^TShareMem;<br>&nbsp; TShareMem = record<br>&nbsp; &nbsp; Data: array[0..255] of char;<br>&nbsp; end;<br>&nbsp; TForm1 = class(TForm)<br>&nbsp; &nbsp; Button1: TButton;<br>&nbsp; &nbsp; procedure Button1Click(Sender: TObject);<br>&nbsp; &nbsp; procedure FormDestroy(Sender: TObject);<br>&nbsp; &nbsp; procedure FormCreate(Sender: TObject);<br>&nbsp; private<br>&nbsp; &nbsp; { Private declarations }<br>&nbsp; public<br>&nbsp; &nbsp; { Public declarations }<br><br>&nbsp; end;<br><br>var<br>&nbsp; Form1: TForm1;<br>&nbsp; PShare: PShareMem;<br>implementation<br><br>{$R *.DFM}<br>var<br>&nbsp; HMapping: THandle;<br>&nbsp; HMapMutex: THandle;<br>const<br>&nbsp; MAPFILESIZE = 1000;<br>&nbsp; REQUEST_TIMEOUT = 1000;<br><br>procedure OpenMap;<br>begin<br>&nbsp; &nbsp;{创建一个文件映射内核对象}<br>&nbsp; HMapping := CreateFileMapping(<br>&nbsp; &nbsp; $FFFFFFFF,<br>&nbsp; &nbsp; nil,<br>&nbsp; &nbsp; PAGE_READWRITE,<br>&nbsp; &nbsp; 0,<br>&nbsp; &nbsp; SizeOf(TShareMem),<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{这个文件映射对象的名字用于与其他进程共享该对象,}<br>&nbsp; &nbsp;pchar('Map Name')<br>&nbsp; &nbsp; );<br>&nbsp; if (hMapping = 0) then<br>&nbsp; begin<br>&nbsp; &nbsp; ShowMessage('不能创建内存映射文件');<br>&nbsp; &nbsp; Application.Terminate;<br>&nbsp; &nbsp; exit;<br>&nbsp; end;<br>&nbsp; &nbsp;{将文件数据映射到进程的地址空间}<br>&nbsp; &nbsp;{当创建了一个文件映射对象之后,仍然必须让系统为文件的数据保留<br>&nbsp; &nbsp; 一个地址空间区域,并将文件的数据作为映射到该区域的物理存储器进行提交。<br>&nbsp; &nbsp; }<br>&nbsp; PShare := PShareMem(MapViewOfFile(HMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0));<br>&nbsp; if PShare = nil then<br>&nbsp; begin<br>&nbsp; &nbsp; CloseHandle(HMapping);<br>&nbsp; &nbsp; ShowMessage('Can''t View Memory Map');<br>&nbsp; &nbsp; Application.Terminate;<br>&nbsp; &nbsp; exit;<br>&nbsp; end;<br><br>&nbsp; {既然我们通过pvFile得到了映象视图的起始地址,那么可以对视图做一些操作了}<br>end;<br><br>procedure CloseMap;<br>begin<br>&nbsp; if PShare &lt;&gt; nil then<br>&nbsp; &nbsp; {从进程的地址空间中撤销文件数据的映象}<br>&nbsp; &nbsp; UnMapViewOfFile(PShare);<br>&nbsp; if HMapping &lt;&gt; 0 then<br>&nbsp; &nbsp; CloseHandle(HMapping);<br>end;<br><br>function LockMap: Boolean;<br>begin<br>&nbsp; Result := true;<br>&nbsp; &nbsp;{创建互斥对象}<br>&nbsp; HMapMutex := CreateMutex(nil, false,<br>&nbsp; &nbsp; pchar('MY MUTEX NAME GOES HERE'));<br>&nbsp; if HMapMutex = 0 then<br>&nbsp; begin<br>&nbsp; &nbsp; ShowMessage('不能创建互斥对象');<br>&nbsp; &nbsp; Result := false;<br>&nbsp; end else begin<br>&nbsp; &nbsp; if WaitForSingleObject(HMapMutex, REQUEST_TIMEOUT)<br>&nbsp; &nbsp; &nbsp; = WAIT_FAILED then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; ShowMessage('不能对互斥对象加锁!');<br>&nbsp; &nbsp; &nbsp; Result := false;<br>&nbsp; &nbsp; end<br>&nbsp; end<br>end;<br><br>procedure UnlockMap;<br>begin<br>&nbsp; &nbsp;{关闭文件映射对象和文件对象}<br>&nbsp; ReleaseMutex(HMapMutex);<br>&nbsp; CloseHandle(HMapMutex);<br>end;<br><br>procedure TForm1.Button1Click(Sender: TObject);<br>var<br>&nbsp; str: pchar;<br>begin<br>&nbsp; str := pchar('简单的共享内存的例子');<br>&nbsp; CopyMemory(@(pShare^.data), Str, Length(str));<br>&nbsp; {发送消息表明有数据}<br>&nbsp; PostMessage(FindWindow(nil, 'MyForm'), WM_DATA, 1, 1)<br>end;<br><br>procedure TForm1.FormDestroy(Sender: TObject);<br>begin<br>&nbsp; UnlockMap;<br>&nbsp; CloseMap;<br>end;<br><br>procedure TForm1.FormCreate(Sender: TObject);<br>begin<br>&nbsp; OpenMap;<br>&nbsp; LockMap;<br>end;<br><br>end.<br><br><br>unit Unit2;<br><br>interface<br><br>uses<br>&nbsp; Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,<br>&nbsp; StdCtrls;<br><br>const<br>&nbsp; WM_DATA = WM_USER + 1024;<br>type<br>&nbsp; PShareMem = ^TShareMem;<br>&nbsp; TShareMem = record<br>&nbsp; &nbsp; Data: array[0..255] of char;<br>&nbsp; end;<br>&nbsp; TMyForm = class(TForm)<br>&nbsp; &nbsp; Memo1: TMemo;<br>&nbsp; &nbsp; Button1: TButton;<br>&nbsp; &nbsp; procedure FormCreate(Sender: TObject);<br>&nbsp; &nbsp; procedure Button1Click(Sender: TObject);<br>&nbsp; private<br>&nbsp; &nbsp; { Private declarations }<br>&nbsp; public<br>&nbsp; &nbsp; { Public declarations }<br>&nbsp; &nbsp; procedure getShareInfo(var Msg: TMessage); message WM_DATA; {处理WM_DATA}<br>&nbsp; end;<br><br>var<br>&nbsp; MyForm: TMyForm;<br>&nbsp; PShare: PShareMem;<br>&nbsp; MapHandle: THandle;<br><br>implementation<br><br>{$R *.DFM}<br><br>procedure TMyForm.getShareInfo(var Msg: TMessage); {处理WM_DATA}<br>begin<br>&nbsp; if msg.LParam=1 then {是我们设定的消息参数}<br>&nbsp; &nbsp; Memo1.Text := PShare^.Data;<br>end;<br><br>procedure TMyForm.FormCreate(Sender: TObject);<br>begin<br>&nbsp; MapHandle := OpenFileMapping(FILE_MAP_WRITE, {获取完全访问映射文件}<br>&nbsp; &nbsp; False, {不可继承的}<br>&nbsp; &nbsp; pchar('Map Name')); {映射文件名字}<br>&nbsp; if MapHandle = 0 then<br>&nbsp; begin<br>&nbsp; &nbsp; ShowMessage('不能定位内存映射文件块!');<br>&nbsp; &nbsp; Halt;<br>&nbsp; end;<br>&nbsp; PShare := PShareMem(MapViewOfFile(MapHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0));<br>&nbsp; if PShare = nil then<br>&nbsp; begin<br>&nbsp; &nbsp; CloseHandle(MapHandle);<br>&nbsp; &nbsp; ShowMessage('Can''t View Memory Map');<br>&nbsp; &nbsp; Application.Terminate;<br>&nbsp; &nbsp; exit;<br>&nbsp; end;<br>&nbsp; FillChar(PShare^, SizeOf(TShareMem), 0);<br>end;<br><br>procedure TMyForm.Button1Click(Sender: TObject);<br>begin<br>&nbsp; CloseHandle(MapHandle);<br>&nbsp; close;<br>end;<br><br>end.<br>
 
楼上的代码有点小bug,跨进程发送自定义消息最好用registerwindowmessage函数保证两个应用程序之前使用一致的消息编号。我把楼上的程序加上了这两句<br><br>unit Unit1;<br>interface<br><br>uses<br>&nbsp;Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,<br>&nbsp;StdCtrls;<br><br>const<br>&nbsp;WM_DATA = WM_USER + 1024;<br>type<br>&nbsp;PShareMem = ^TShareMem;<br>&nbsp;TShareMem = record<br>&nbsp; &nbsp;Data: array[0..255] of char;<br>&nbsp;end;<br>&nbsp;TForm1 = class(TForm)<br>&nbsp; &nbsp;Button1: TButton;<br>&nbsp; &nbsp;procedure Button1Click(Sender: TObject);<br>&nbsp; &nbsp;procedure FormDestroy(Sender: TObject);<br>&nbsp; &nbsp;procedure FormCreate(Sender: TObject);<br>&nbsp;private<br>&nbsp; &nbsp;{ Private declarations }<br>&nbsp;public<br>&nbsp; &nbsp;{ Public declarations }<br><br>&nbsp;end;<br><br>var<br>&nbsp;Form1: TForm1;<br>&nbsp;PShare: PShareMem;<br>implementation<br><br>{$R *.DFM}<br>var<br>&nbsp;HMapping: THandle;<br>&nbsp;HMapMutex: THandle;<br>const<br>&nbsp;MAPFILESIZE = 1000;<br>&nbsp;REQUEST_TIMEOUT = 1000;<br><br>procedure OpenMap;<br>begin<br>&nbsp; {创建一个文件映射内核对象}<br>&nbsp;HMapping := CreateFileMapping(<br>&nbsp; &nbsp;$FFFFFFFF,<br>&nbsp; &nbsp;nil,<br>&nbsp; &nbsp;PAGE_READWRITE,<br>&nbsp; &nbsp;0,<br>&nbsp; &nbsp;SizeOf(TShareMem),<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {这个文件映射对象的名字用于与其他进程共享该对象,}<br>&nbsp; pchar('Map Name')<br>&nbsp; &nbsp;);<br>&nbsp;if (hMapping = 0) then<br>&nbsp;begin<br>&nbsp; &nbsp;ShowMessage('不能创建内存映射文件');<br>&nbsp; &nbsp;Application.Terminate;<br>&nbsp; &nbsp;exit;<br>&nbsp;end;<br>&nbsp; {将文件数据映射到进程的地址空间}<br>&nbsp; {当创建了一个文件映射对象之后,仍然必须让系统为文件的数据保留<br>&nbsp; &nbsp;一个地址空间区域,并将文件的数据作为映射到该区域的物理存储器进行提交。<br>&nbsp; &nbsp;}<br>&nbsp;PShare := PShareMem(MapViewOfFile(HMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0));<br>&nbsp;if PShare = nil then<br>&nbsp;begin<br>&nbsp; &nbsp;CloseHandle(HMapping);<br>&nbsp; &nbsp;ShowMessage('Can''t View Memory Map');<br>&nbsp; &nbsp;Application.Terminate;<br>&nbsp; &nbsp;exit;<br>&nbsp;end;<br><br>&nbsp;{既然我们通过pvFile得到了映象视图的起始地址,那么可以对视图做一些操作了}<br>end;<br><br>procedure CloseMap;<br>begin<br>&nbsp;if PShare &lt;&gt; nil then<br>&nbsp; &nbsp;{从进程的地址空间中撤销文件数据的映象}<br>&nbsp; &nbsp;UnMapViewOfFile(PShare);<br>&nbsp;if HMapping &lt;&gt; 0 then<br>&nbsp; &nbsp;CloseHandle(HMapping);<br>end;<br><br>function LockMap: Boolean;<br>begin<br>&nbsp;Result := true;<br>&nbsp; {创建互斥对象}<br>&nbsp;HMapMutex := CreateMutex(nil, false,<br>&nbsp; &nbsp;pchar('MY MUTEX NAME GOES HERE'));<br>&nbsp;if HMapMutex = 0 then<br>&nbsp;begin<br>&nbsp; &nbsp;ShowMessage('不能创建互斥对象');<br>&nbsp; &nbsp;Result := false;<br>&nbsp;end else begin<br>&nbsp; &nbsp;if WaitForSingleObject(HMapMutex, REQUEST_TIMEOUT)<br>&nbsp; &nbsp; &nbsp;= WAIT_FAILED then<br>&nbsp; &nbsp;begin<br>&nbsp; &nbsp; &nbsp;ShowMessage('不能对互斥对象加锁!');<br>&nbsp; &nbsp; &nbsp;Result := false;<br>&nbsp; &nbsp;end<br>&nbsp;end<br>end;<br><br>procedure UnlockMap;<br>begin<br>&nbsp; {关闭文件映射对象和文件对象}<br>&nbsp;ReleaseMutex(HMapMutex);<br>&nbsp;CloseHandle(HMapMutex);<br>end;<br><br>procedure TForm1.Button1Click(Sender: TObject);<br>var<br>&nbsp;str: pchar;<br>begin<br>&nbsp;str := pchar('简单的共享内存的例子');<br>&nbsp;registerwindowmessage(pchar('messageid'));//应该再加上这一句最好。<br>&nbsp;CopyMemory(@(pShare^.data), Str, Length(str));<br>&nbsp;{发送消息表明有数据}<br>&nbsp;PostMessage(FindWindow(nil, 'MyForm'), WM_DATA, 1, 1)<br>end;<br><br>procedure TForm1.FormDestroy(Sender: TObject);<br>begin<br>&nbsp;UnlockMap;<br>&nbsp;CloseMap;<br>end;<br><br>procedure TForm1.FormCreate(Sender: TObject);<br>begin<br>&nbsp;OpenMap;<br>&nbsp;LockMap;<br>end;<br><br>end.<br><br><br>unit Unit2;<br><br>interface<br><br>uses<br>&nbsp;Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,<br>&nbsp;StdCtrls;<br><br>const<br>&nbsp;WM_DATA = WM_USER + 1024;<br>type<br>&nbsp;PShareMem = ^TShareMem;<br>&nbsp;TShareMem = record<br>&nbsp; &nbsp;Data: array[0..255] of char;<br>&nbsp;end;<br>&nbsp;TMyForm = class(TForm)<br>&nbsp; &nbsp;Memo1: TMemo;<br>&nbsp; &nbsp;Button1: TButton;<br>&nbsp; &nbsp;procedure FormCreate(Sender: TObject);<br>&nbsp; &nbsp;procedure Button1Click(Sender: TObject);<br>&nbsp;private<br>&nbsp; &nbsp;{ Private declarations }<br>&nbsp;public<br>&nbsp; &nbsp;{ Public declarations }<br>&nbsp; &nbsp;procedure getShareInfo(var Msg: TMessage); message WM_DATA; {处理WM_DATA}<br>&nbsp;end;<br><br>var<br>&nbsp;MyForm: TMyForm;<br>&nbsp;PShare: PShareMem;<br>&nbsp;MapHandle: THandle;<br><br>implementation<br><br>{$R *.DFM}<br><br>procedure TMyForm.getShareInfo(var Msg: TMessage); {处理WM_DATA}<br>begin<br>&nbsp;if msg.LParam=1 then {是我们设定的消息参数}<br>&nbsp; &nbsp;Memo1.Text := PShare^.Data;<br>end;<br><br>procedure TMyForm.FormCreate(Sender: TObject);<br>begin<br>registerwindowmessage(pchar('messageid'));//再加上此句<br><br>&nbsp;MapHandle := OpenFileMapping(FILE_MAP_WRITE, {获取完全访问映射文件}<br>&nbsp; &nbsp;False, {不可继承的}<br>&nbsp; &nbsp;pchar('Map Name')); {映射文件名字}<br>&nbsp;if MapHandle = 0 then<br>&nbsp;begin<br>&nbsp; &nbsp;ShowMessage('不能定位内存映射文件块!');<br>&nbsp; &nbsp;Halt;<br>&nbsp;end;<br>&nbsp;PShare := PShareMem(MapViewOfFile(MapHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0));<br>&nbsp;if PShare = nil then<br>&nbsp;begin<br>&nbsp; &nbsp;CloseHandle(MapHandle);<br>&nbsp; &nbsp;ShowMessage('Can''t View Memory Map');<br>&nbsp; &nbsp;Application.Terminate;<br>&nbsp; &nbsp;exit;<br>&nbsp;end;<br>&nbsp;FillChar(PShare^, SizeOf(TShareMem), 0);<br>end;<br><br>procedure TMyForm.Button1Click(Sender: TObject);<br>begin<br>&nbsp;CloseHandle(MapHandle);<br>&nbsp;close;<br>end;<br><br>end.<br>&nbsp;<br><br>&nbsp;<br>
 
采用MapFile不过得自己建立一个内存分配机制.
 
&lt;delphi下深入windows核心编程&gt;这本书中有不少例子和讲述
 
昨天发完贴就下班了,所以现在才回贴。各位真是令我很佩服。我先去试一下。我原先也是用的内存映射,但是有同样的错误,退出程序时就会报会“内存xxx只能read”。是不是想不同程序之间共享数据在WIN32下已经不能使用DLL了呢?
 
好呀.大家挺热心.说的被人抢先了
 
谢谢楼上捧场
 
我试了一下,好象还是接收不到数据噢,我跟踪发现是在<br>PShare := PShareMem(MapViewOfFile(MapHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0));这一句根本没有接收到数据。<br>不用消息行不行,我想让知道映射文件名的程序都能访问共享数据。
 
终于搞定:把FillChar(PShare^, SizeOf(TShareMem), 0);这句拿掉就可以了,是这一句丢失了接收回来的数据的,不是上一句没接收到。再问一下各位,能共享其它类型的数据吗?比如说是某个控件<br>type TShareMem=record<br>&nbsp; Table1:TTable;<br>&nbsp; str:array [0..255] or char;<br>End;<br>这样可以吗?<br>可以的话如何向内存映射区读、写数据呢?
 
参考一下这个吧<br>By David Spies. <br>如何使用Win32内存映象文件,实现多个程序数据交换<br>http://www.csdn.net/dev/delphi/Samples/mmapfile.zip
 
多人接受答案了。
 
后退
顶部