Data delivery between programs with Delphi
In practical applications, we often need multiple programs to cooperate with each other to complete certain features. For example, synchronization, mutual exclusion between two applications; the application automatically passes the parameters when the application is in the second instance. To implement these features, you must implement data transfer between the program.
Some special advanced technologies can deliver data between different programs, such as clipboards, dynamic data exchange, and OLE automation, but have conditional restrictions and relatively complicated. Here, I introduced three effective underlying technology, I hope to help program enthusiasts.
Use WM_COPYDATA message
Using this message involves a pointer to a TcopyDataStruct structure type. There are three members in this structure:
DWDATA is a 32-bit additional parameter
CBData indicates the size of the data area to be transmitted
LPDATA indicates a pointer to the data area to be passed
Let's take an example. This example consists of two programs, which are SendData and GetData, respectively.
The SendData program sends a message to the getData program and transmits the string in Edit1; getData accepts the character string sent by SendData after receiving the message and displayed in the corresponding Edit1.
Senddata program:
VAR
FORM1: TFORM1;
IMPLEMENTATION
{$ R * .dfm}
Proceduretform1.button1click (sender: TOBJECT);
VAR
DS: tcopydatastruct;
HD: thandle;
Begin
Ds.cbdata: = Length (edit1.text) 1;
GetMem (DS.LPDATA, DS.CBDATA); // Assign memory for the transferred data area
Strcopy (DS.LPDATA, PCHAR (EDIT1.TEXT));
HD: = FindWindow (NIL, 'FORM2'); // Get the handle of the receiving window
IFHD <> 0Then SendMessage (HD, WM_COPYDATA, HANDLE,
Cardinal (@ds)) // Send WM_COPYDATA message
Else
SHOWMESSAGE ('"target window is not found!');
FreeMem (DS.LPDATA); // Release Resources
END;
GetData program:
TFORM2 = Class (TFORM)
EDIT1: TEDIT;
Private
{Privateeclarations}
public
ProcedureMyMessage (VART: TWMCopyData); MessageWM_CopyData;
{PublicDeclarations}
END;
VAR
Form2: TFORM2;
IMPLEMENTATION
Proceduretform2.mymessage (VART: TWMCOPYDATA);
Begin
Edit1.Text: = StrPas (T.copyDataStruct ^ .lpdata); // Accept data and display.
END;
Using this method is the easiest way to interact with Win32 applications.
Use the global atom
In the Win32 system, in order to achieve information sharing, the system maintains a global atomic table. Some shared data is stored in each atom. About the operation of the atom, there is a set of special API functions:
GlobalAddatom adds global atoms in the table
GlobalDeleTom deletes global atoms in the table
GlobalFindatom searches for global atoms in the table
GlobalGetAMname Gets the global atom from the table
The author uses this method to avoid programs secondary start, but transmit parameters of the second start-up belt to the first instance to perform corresponding processes. Basic processing is as follows:
In the project file:
Programpvdde;
Uses
Forms, shellapi, windows, dialogs, ddein'dde.pas' {form1}; {$ r * .res}
Begin
Ifglobalfindatom (Pchar ('PDDE_IS_Running')) = 0then
/ / Avoid secondary startup
Begin
K: = GlobalAddatom (Pchar ('PDDE_IS_RUNNING');
Application.INITIALIZE;
Application.createform (TFORM1, FORM1);
Application.run;
end
Else
Begin
/ / Parameter to the first instance when passing the second start
H: = FindWindow (Pchar ('TForm1'), PCHAR ('Data Confidential Prohibition of Outer Transmission ");
IFParamcount> 0Then
Begin
L: = GlobalAddatom (Pchar (Pramstr (1)));
IFH <> 0then
SendMessage (H, WM_MYMESSAGE, 0, L);
{Pass atom handle}
GLOBALDETEATOM (L); {Release after use}
END;
Application.Terminate;
END;
End.
Add the processing of custom messages WM_MYMESSAGE in the corresponding window unit Dde.PAS:
Proceduretform1.mymessage (VART: TMESSAGE);
{Processing WM_MYMESSAGE message}
VAR
P: array [0..255] OFCHAR;
Begin
GlobalGetaMname (T.LPARAM, P, 255); {Accept data to p array}
END;
Use storage image files
This approach is relatively complicated.
When Win95 with Winows
NT When loading a file in memory, a special global memory area is used. In this area, the application's virtual memory address and the corresponding position in the file correspond together. Since all processes share a global memory area for storing the image file, they can actually share their execution code in memory when the two processes are loaded with the same module (application or DLL file).
The author uses a CREATEFILEMAPPING function with special parameters to indirectly reach the purpose of sharing memory. The following is briefly explained.
HandlecreateFilemapping (Handlehfile, //) Handle
LPSecurity_attributeslpfilemappingAttributes, // Optional Security Properties
DWORDFLPROTECT, / / Image file protection
DWordDwmaximumumsizeHigh, / / The bottom value of the image file area
DWORDDWMAXIMUMSIZELOW, / / The value of the image file area
LPCTSTRLPNAME / / The name of the image file);
If hfile is 0xfffffffff, you must specify dwmaximumsizehigh in the call program.
And the value of the dwmaximumsizelow parameter to determine the size of the image file. By specifying such parameters, the function creates a special logical image file supported by the operating system page file instead of a logical image file supported by the actual operating system. This logical image file can be shared by copying, inheriting, or by name. For a detailed description of other parameters, please see online help.
After the image file is created, we can access its memory by calling another API function MapViewOffile, which returns a specific pointer to the shared memory block.
LPVOIDMAPVIEWOFFILE
HandlehfilemappingObject, // Image File Handle
DWORDDWDESIREDACCESS, // Access method
DWordDWFileOffSethigh, / / The bottom value of the image file area
DWORDDWFILEOFFSETLOW, // Image of the image of the image file DWORDDWNUMBEROFBYTOSTOMAP // Map Biostament
);
If dwnumberofbytestomap is 0, map the entire file.
The following example shows:
Private
Hmapfile: thandle;
MapFilePointer: Pointer;
public
{PublicDeclarations}
END;
VAR
FORM1: TFORM1;
IMPLEMENTATION
{$ R * .dfm}
Proceduretform1.formcreate (Sender: TOBJECT);
Begin
Hmapfile: = CreateFilemapping
$ Fffffff, // special memory map handle
NIL, Page_Readwrite, 0,10000, 'DDHDHDEMAPPEDFILE'); // File Name
IFHMAPFILE <> 0then
MapFilePointer: = MapViewoffile (HmapFile, / / Handle of the Image File
FILE_MAP_ALL_ACCESS, 0, 0, 0) // Access the entire image file
Else
ShowMessage ('hmapfile = 0');
ifmapfilepointer = nilthen
ShowMessage ('MapFilePointer = nil');
END;
Proceduretform1.btnWriteClick (Sender: TOBJECT);
Begin
Stropy (pchapfilepointer),
Pchar (editwrite.text)); // write content to shared memory
END;
Proceduretform1.btnreadclick (sender: TOBJECT);
VAR
String;
Begin
S: = pchar (mapfilepointer); // read the content from the shared memory
EditRead.Text: = S;
END;
In this way, data can be shared between different programs, but also share data between different examples of the same program. In order to inform other changes in other process sharing data, you can customize a user message, and is implemented by sending a message, and details will not be described here.