Type: Translate Source: http://www.codeguru.com Time: 2004-09-27
Translator: Mrwang2000) Email: Yuanzhaowang@sohu.com or Yuanzhaoang@163.com
Example Download address Download Source Files - 116 KB
A few weeks ago, I desperately looked for an example of passing C objects through the COM interface, but I didn't find it. This is why I published this article.
Passing a C object parameter in the DLL of the ATL is not very difficult, but of course it will be a bit difficult, it is also very interesting.
Before starting a project, it is sure that your client and server components are adapted to C programs, second, you have to know how to set your clients and servers.
Interface limitations
COM technology requires the separation of the client and server height, which is implemented by the interface, but the problem is only available in the interface method, and if this interface is based on IdisPatch, parameter type optional range It is more limited, because these limitations, C objects can only be passed when they meet the following conditions:
1. All clients and servers are written by VC 2, they must share the definition of objects (such as header files) 3, pass a simple object 4 of the application design, and your application may need to run in a distributed environment. You want COM remote activities, local / remote activities are transparent, safe
I suggest that you will look at each title before starting working.
Now, I list the instance and make the following things:
1. Create an ATL DLL server 2, add a MFC class, derive from the COBJECT class 3, use the Declare_Serial Macro 4 in the head of the class, use the Implement_Seri Macro 5 in the middle of the class, override the serialize () method
// Your CSIMpleObj class should be like this: Class CsimpleObj: public cobject {declare_serial (csimpleObj) public: // Constructor and destructor csimpleObj (); Virtual ~ csimpleObj (); // Set internal string data Void setString CSTRING CSDATA); // Used to serialize data (serialization) Virtual Void Serialize (serialization) virtual void serialize (// Realistic string data void show (); // internal string data} ;
// Write this data object into the document Void CsimpleObj :: Serialize (carchive & ar) {cobject :: serialize (ar);
IF (ar.doading ()) {// extracts data from file file AR >> m_StrData;} Else {// put data into file file ar << m_strdata;}}}}
// Method of display object data Void CsimpleObj :: show () {afxMessageBox (m_strdata);
// Save string data to a variable void csimpleObj :: setString (cstring csdata) {m_strdata = csdata;}
6. Now, the next step is to use a Carchive object to serialize and reverse sequencing (load and storage objects), I use a CLASS CBLOB {public: CBLOB () {PUBLIC: CBLOB () {} called CBLOB. Virtual ~ cblob () {};
// extract data from a COBJECT object and load into a SafeArray object. SafeArray * load (cobject * pobj); // Recreate a SafeArray object BOOL Expand (COBJECT * & POBJ, SAFEARRAY * PVAR); private:};
// extract data from a COBJECT object and build a SafeArray object with it.
SafeArray * CBLOB :: Load (CObject * Pobj) {cmemfile memfile; // memory file
/ / Define a flag to mark the file is a logo for reading or a stored LONG LMODE = CARCHIVE :: Store | CARCHIVE :: BNOFLUSHONDELETE; // Create a file CARCHIVE AR (& Memfile, LMODE);
// m_pdocument does not use ar.m_pdocument = null; // serialized objects into archive file ar.writeObject (POBJ); // Close file file - now, data in memory file ar.close ();
/ / Get the length of the memory file (in bytes)
Long Llen = Memfile.getLength ();
// Release the buffer shutdown file unsigned char * PMEMDATA = Memfile.detach ();
// Set the SafeArray SafeArray * PSA;
// Create a SafeArray object access flow data PSA = SafeArrayCreateVector (VT_UI1, 0, LLEN);
/ / Pointer Unsigned Char * pdata = NULL pointing to byte arrays;
/ / A SAFE ARRAY pointer is obtained. Lock an array. SafearrayAccessData (PSA, (void **) & pdata;
// Copy memory file to SafeArray Memcpy (PDATA, PMEMDATA, LLEN);
// Clean up the buffer delete Pmemdata;
// Lock to SafeArrayunAccessData (PSA) on SafeArray;
/ / Return to a pointer Return PSA of SafeArray assigned to this
// Recreate a SafeArray object Bool CBLOB :: Expand (Cobject * & rpobj, SafeArray * psa) {cmemfile memfile; // Deserved memory file long LLEngth; // byte count CHAR * PBUFFER; / / Buffer pointer
// Lock the access of the array data to SafearrayAccessData (PSA, (void **) & pBuffer;
// Number of elements in arrays. Is the number of bytes LLLENGTH = PSA-> RgsAbound-> CELEMENTS;
/ / Connect the buffer to memory file Memfile.attach ((unsigned char *) PBuffer, LLEngth);
// Start Memfile.seektobegin from the buffer header;
// Create a file that connects to the memory file CARCHIVE AR (& Memfile, Carchive :: Load | CARCHIVE :: Bnoflushondelete);
// Do not use document pointer ar.m_pdocument = null; // Fill object acquisition pointer rpobj = ar.readObject (0);
// Turn off the file ar.close ();
// Note: PBUFFER is released // release the buffer closing file pBuffer = ();
// Release SafeArray buffer SafearrayunAccessData (PSA);
Return True;}
Here, I use SafeArray because it is the best choice for us, it can contain some complex multi-dimensional arrays, but this example we only use very simple arrays, SafeArray data has a question: MIDL recognizes Out of this data type, in the next article I will tell the easiest way: use the Variant data type
The next step is as follows: 1. Create a COM interface 2, create a SafeArray object 3, define [Helpstring ("Method setArray"] HRESULT STARRAY ([IN] SafeArray (unsigned char); [Helpstring " ")] HRESULT GETARRAY ([OUT / *, RETVAL * /] SAFEARRAY (UNSIGNED CHAR) * PDATA); 4. Create a MFC-based client to test the application
Your IDL file should be like this:
interface IBolbData: IUnknown {[helpstring ( "method SetArray")] HRESULT SetArray ([in] SAFEARRAY (unsigned char) pData); [helpstring ( "method GetArray")] HRESULT GetArray ([out / *, retval * /] SAFEARRAY UNISIGNED CHAR * PDATA);
// Set the object stdmethodimp cbolbdata :: setArray (SafeArray * pdata) {AFX_MANAGE_STATE ())
// Create a CSIMpleObj CSIMPLEOBJ * DUMMY = NULL; // Creating a BLOB object is used to fill, deserialized CBLOB blob; // Create a margin object blob.expand ((CObject * &) Dummy, PDATA) using SafeArray Dummy-> show (); // Call the display function test object delete dummy; // Remove pointer Return S_OK;}
// Create an object and send it to the client .StdMethodimp cbolbdata :: getArray (SafeArray ** PDATA) {AFX_MANAGE_STATE ()) // Create an object and send it to the server CSIMPLEOBJ * PMYOB = New csimpleObj ();
// Set string data PMYOB-> setString ("A Safearray from the Server!");
// Create blob to serialize the object CBLOB BLOB;
// Load the object into the blob * pdata = blob.load (PMYOB); // Delete the PMYOB pointer delete PMYOB;
Return S_OK;
Finally, write a dialog-based MFC application with two buttons and add the following code: void cclientdlg :: onok () {// Create a COM smart pointer from the CLSID string Try {IbolbDataPtr Pi ("Server.BolbData.1" ); SafeArray * psa; // gets from the server SafeArray Pi-> GetArray (& PSA);
// Create a pointer csimpleobj * Dummy = NULL;
// BLOB object CBLOB BLOB;
// Extend SafeArray to an object blob.expand ((COBJECT * &) DUMMY, PSA); // Test it Dummy-> show () by calling an object.
/ / Delete object delete dummy;} // Process any CAM exception Catch (_E.Error E) by smart pointer AFXMessageBox (E.ERRORMESSAGE ());}}
Void cclientdlg :: OnLoad () {try {// Create a smart pointer from the CLSID string IbolbDataPtr Pi ("Server.BolbData.1"); SafeArray * PSA;
// Create objects for the server CSIMPLEOBJ * PMYOB = new csimpleobj ();
// Set string data PMYOB-> setString ("The Client Sent A Safearray!");
// Create blob to serialize the object CBLOB BLOB;
// Load the object into the blob PSA = Blob.Load (PMYOB);
// Remove the object delete PMYOB;
Pi-> setArray (PSA);
} catch (_COM_ERROR E) {// Display Error Information AFXMessageBox (E.ErrorMessage ());}}
to sum up
This article contains a lot of topics:, for example, how to use serialization, how to use SafeArray, and how to pass C objects through the interface. I want to thank William Rubin, his article helps me very much, I have planned to explain this topic more detailed, but I can't do this because I will continue to update this article. During this time, please don't need Contact me with your polite
http://www.codeguru.com/code/legacy/atl/passing.zip