COM in-depth understanding (below) - Method parameter type is CRUNTIMECLASS *, VOID *, etc. The following article has explained that the class object is actually a structural instance, and in order to implement the process between the process, it is necessary to achieve the purpose of the reference. The class specifically prepares an agent class and exemplifies (ie, instantiates) an object to implement the agent object. And this agent class must be divided into two parts, the number of member functions specifically in the customer process, and the other is specifically transmitted to the component object in the component process to implement data delivery between the process, and transmit the customer's call command. To achieve customer operating components objects. The above approach is actually writing something that should be done when a custom collection operation is written, but you still need to do a few additional provisions of COM, if you must implement the Imarshal interface. This article explains how to transfer a standard proxy / placeholder component for such types to deliver a pointer to a class object across processes (using MIDL to complete). In order to generate a proxy object on the client, some information must be passed, and then build a proxy object based on the passing information. In the type definition of the IDL language, there is no class, so it is impossible to make the interface method to a pointer to a custom class. However, there is indeed, you can only transfer class object pointers to a type identified in a certain IDL. The best candidate is Void *, and then the information generated by the MIDL will pass the information of the agent object. Void * does not have any semantics, which only represents an address, so passing VOID * is incorrect in the IDL because MIDL cannot determine how it should collect it in memory according to the semantic determination of the VOID *. But MIDL still provides a variety of ways to solve this problem, and only two of them are used up to: [call_as ()] attributes and [Wire_Marshal ()] properties. [local] and [CALL_AS ()] [local] interface or interface method can be added to [local] attribute to indicate this method or the method in this interface does not need to generate a collection code, and then avoid the above due to void * without There is any semantics and cannot bring it to the content of the content, because it is not necessary to generate a collection code, and the parameters of the method thereof can be VOID *. The method or interface modified by this property is referred to as a local method or a local interface because these methods do not have a collection code and cannot be remotely called. This is very wide in the standard interface of COM. If you look at the IDL code of IUNKNOWN, it is a local interface.
Another example IClassFactory See IDL interface definitions, as follows: [object, uuid (00000001-0000-0000-C000-000000000046), pointer_default (unique)] interface IClassFactory: IUnknown {typedef [unique] IClassFactory * LPCLASSFACTORY; [local] HRESULT CreateInstance ([In, unique] iUnknown * punkouter, [in] refiid riid, [out, IID_ID)] void ** ppvobject); [Call_as (CreateInstance)] HRESULT RemoteCreateInstance ([In] Refiid RIID, [OUT, IID_IS riid)] IUnknown ** ppvObject); [local] HRESULT LockServer ([in] BOOL fLock); [call_as (LockServer)] HRESULT __stdcall RemoteLockServer ([in] BOOL fLock);} where is the local function CreateInstance and LockServer, MIDL will not generate code for the collection of these two functions, i.e. agent / mass codes, its performance is similar to the following two prototype code: HRESULT STDMETHODCALLTYPE IClassFactory_LockServer_Proxy (IClassFactory * this, BOOL fLock); HRESULT STDMETHODCALLTYPE IClassFactory_LockServer_Stub (IClassFactory * This, Bool flock; that is, when detected a definition of an interface method in .IDL file, MIDL will generate two additional functions for this method. The names are
It is not like [local] attribute modified method, which still generates a collection code, but does not appear in the interface, that is, the declaration of this type of method (but it can be seen in the type library " See, this is a bug, which can be wound by predefined macros). This is called method alias because it associates two methods, one ([Local] modified) is another alias of another ([Call_as] modified), is actually used. As mentioned in the previous RemoteLockServer, with the property [Call_as (LOCKSERVER)] to indicate that this function is called when the customer calls LockServer and needs to be delivered. The method of [local] modification is called local version, [Call_as ()] is called a remote version, and it can be considered that the remote version function solves the problem that the local version of the function does not generate a collection code, because local version of the function may have some special Requirements (such as parameter type void *) and cannot generate a collection code. Since [Call_AS ()] produces a function alias, it is associated with two functions, so there must be such a mechanism to achieve this association. MIDL is to achieve this relationship by requesting developers to write a collection code of local version of the local version. For the above LockServer, MIDL generated for two prototype will be as follows: HRESULT STDMETHODCALLTYPE IClassFactory_LockServer_Proxy (IClassFactory * This, BOOL fLock); HRESULT __stdcall IClassFactory_LockServer_Stub (IClassFactory * This, BOOL fLock); but only a prototype declaration i.e., Not defined. Therefore developers need to write the definition of the above two functions. Note: Although the name is iClassFactory_lockServer_stub, its prototype is just with RemoteLockServer, to implement the parameters that pass the remote version of the function to convert to the parameters of the local version. So the associated process is: Customer calls iClassFactory_lockServer_Proxy, then develop this function and converts the passing MIDL cannot or does not want to be processed into parameter forms of iClassFactory_remoteLockServer_Proxy, and calls to deliver parameters. In the component, COM running period library calling developer IClassFactory_lockServer_stub (Note: This function is not LockServer, but RemoteLockServer) to replace the parameters passing through the network to the original MIDL operating or undesired parameter form And call the LockServer method of the passed iClassFactory * parameter to implement the method of calling the component object, and then return.
The following is a special example: there is a custom class CA, as follows: Class Ca {long m_a, m_b; public: long geta (); void seta (long a);}; to deliver its object pointer in the following interface: //Abc.idl/import "oaidl.idl"; import "ocidl.idl"; [Object, UUID (1A201ABC-A669-4AC7-9E02-2DA772E927FC), Pointer_Default (unique) Interface IABC: iUnknown {[local] HRESULT GETA ([OUT] Void * Pa); [Call_as (Geta)] HRESULT RemoteGeta ([OUT] long * pa, [out] long * pb);}; new DLL project, turn off "Pre-translated" Compiling the switch, add the generated ABC_I.C, ABC_P.C, DLLDATA.C and ABC.H to the project, and create an ABC.DEF file to import several necessary functions for registration, as follows : ;;;;;;;;;;;;;;; abc.def ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; LIBRARY "abc" EXPORTS DllCanUnloadNow PRIVATE DllGetClassObject PRIVATE DllRegisterServer PRIVATE DllUnregisterServer PRIVATE abc.cpp and a newly added file, as follows: ///abc.cpp/#include "abc.h" #include
Make sure there is no open / tc or / tp compilation switch to ensure C compilation on the above ABC.cpp, and C-compilation for MIDL generated .c source files. As follows: IABC * Pa; // Assume that CA A; PA-> Geta (ReinterPret_cast
The most common application is the handles are defined as follows: typedef union _RemotableHandle switch (long fContext) u {case WDT_INPROC_CALL: long hInproc; case WDT_REMOTE_CALL: long hRemote;} RemotableHandle; typedef [unique] RemotableHandle * wireHWND; #define DECLARE_WIREM_HANDLE (name) / Typedef [wire_marshal] void * namedeclare_wirem_handle (hwnd); that is, our common HWnd type is: typedef [wire_marshal (WirehWnd) Void * hwnd; 即 其 customer or component The user of the agent / occupancy is the VOID * type. When it is required, it is actually an instance of the transmission structure RemotableHandle, and this structure is a combination of fcontext as an identifier, actually 8-byte length.
In order to implement the association of the VOID * and RemotableHandle * mentioned above, the developer must provide the definition of the following four functions: unsigned long __rpc_user
Still transmitting the HWnd instances in front and the assigned buffer pointers to set this HWnd instance column to the buffer 4. Transfer the buffer content to the other process space through the RPC channel 5. Call hwnd_usemarshal and pass the RPC channel The resulting column data buffer pointer and the generated one temporary HWnd instance of the pointer to record the astoped HWnd instance 6. Method for calling the application with the returned HWnd instance 7. Call hwnd_userfree, passing the front due to call hwnd_usemarshal The generated temporary record is a pointer to the HWnd instance of the HWnd instance, which is therefore allocated, and the [Wire_Marshal ()] property is the binding of the type and the type of description type. But it is missing, it is the use of flag parameters PFLAGS. This flag parameter is a 4-byte number, which is some coding rules about the NDR format so that the NDR engine (the completed buffer content is arranged in the NDR format rule to transmit the program). Can make the correct data conversion. It is a MSHCTX enumeration value that specificallys the call environment. It is a process within the process or a cross-process. It is a remote or local (please refer to the MSDN), so it can be made according to this value in the above four functions. optimization. The following is the above CA * implementation [Wire_Marshal ()] attribute. As far as, CA * should be delivered using VOID * due to the corresponding type in the IDL, adding the following code in abc.idl: typedef struct _sa {long A, b;} * psa; typedef [Wire_Marshal PSA)] Void * Pa; adds a method for interface IABC: HRESULT SETA ([In] PA A); then adding the following code in abc.cpp: unsigned long __rpc_user pa_usersize (unsigned long * / * pflags * /, unsigned LONG Startingsize, PA * / * PPA * /) {// The reason why this parameter may not be the first column set parameter, // such as HRESULT SETA ([in] long tem1, [in] CHAR TEM2, [IN] Pa A); // At this time, STARTINGSIZE is the reason why it will pass it in order to align it to alignment. Processing, because the structure _SA is only two simple // structures of the unsigned long, no need to be aligned again. Return Startingsize SizeOf (_SA);} unsigned char * __rpc_user pa_usermarshal (unsigned long * pflags, unsigned char * buffer, pa * ppa) {// Point line type (ie, structure _SA) definition fill buffer, pay attention Fill in NDR transmission format //, here is simply replicated due to _sa, so it is simply replicated, there is no problem with one / / toggle data.
For details on the NDR transmission format, please refer to // http://www.opengroup.org/onlinepubs/9629399/chap14.htm if (* pflags & mshctx_inproc) {// is in the process, directly transfer CA * , Not copy * reinterpret_cast