COM sample (3) - component end code

zhaozj2021-02-16  60

COM Sample (3) - Component End Code This article focuses on this series of articles, the front design interface is just auxiliary nature, and there is no relationship with the COM thread model. Due to the interface IMODULE, IMODULESITE implementation, Imodulesite, etc., for use by the interface packaging function using the MFC, so all run in the STA suite, and can make the window of the component The client is the main thread to send a message. Assuming that the remote component is called to implement business logic, determine the data operation initiated by the remote and large data amounts (such as finding), and then invoke a remote method in this thread. Decide to use a class package task to implement the iTask interface to provide task management services, and the thread function Task is just a static member function of iTask's implementation class CTASK. Since CTASK is an internal object, it is not necessary to have a CLSID, so the example is obtained directly through a static member function CreateInstance. For the purpose of demonstration, consider how to express progress, there are two ways. I. Suppose the remote component method is synchronized, then the calling thread will be suspended due to the delay of the remote component method, so the progress cannot be represented. For this, a timer can be turned on, and each fixed time is notified by the front CTask to add a certain progress, and give a upper limit, it will no longer count after it is exceeded, and the progress is no longer increased until the method returns or ItaskManager termination; if it is asynchronous, the above-mentioned thread is initiated by the COM running period (later referred to as COM), it is meaningless, and it must be released in Win2000 and later released. It is only effective, that is, the client must be run on the Win2000 and subsequent operating systems, which is not a good proposal. II. Assuming that iTask is implemented by remote service components, not an internal object that is said to provide packaging, then every piece of code in the method of remote service components, it calls itasknotify to set the progress, and at the end of the method Call itasknotify to end the task. The CTask in the first case is not necessarily necessary in the MTA suite - it will only be called by the client main thread (regardless of the task of the ITASKMANAGER's implementation interface, the task initiated by the department component is through the client Thread operation). Therefore, it should be an APARTMENT component that is implemented using the MFC. However, since this instance is mainly the visits between the presentations, it is still designed to free component (even if it is not necessary), use ATL implementation to demonstrate how to call. However, because it is created directly through a static member function CreateInstance, there is no CLSID and related registry keys to illustrate the Free component. Since it creates it in the client main thread, it is a direct pointer to the client main thread, so it is in a STA suite that exists in the client main thread (even if the requirements of the Free component).

For the termination of the launching thread (both CTASK :: Task static member functions), if the initiation thread and the MTA thread association (ie, the COINIT_MULTITITHREADED is called as the parameter), the business component is a Free component, which will exist in the MTA. It is very unfortunate to initiate a thread to directly call the business component, that is, the initiator of the thread is also the executor of the service component method (assuming that the business component is a local component). Unfortunately reason is that if there is a business component of the business component, there is a long code, and it does not provide any termination (such as a short time waiting for an event), the only way to terminate the call is forced to terminate the thread. In turn, it is not possible to correctly call the business components, and cause some of the efficiency of COM (COUNITIALIZE no call, some resources of COM have failed to release). If you call (not the direct pointer) through agent, you can cancel the universal calls in the ICANCELMETHODCALLS, that is, the call to the business component in the thread. This is an interface provided by COM, so that customers can cancel synchronous calls. This is the work of both sides. If the component ends have always occupied thread resources, they must be forcibly terminated, but at least one way is provided so that it can reply to the running of threads, and then call Couninitialize exit. Like the front asynchronous calls, it must be the COM released by Win2000 and its above version of the operating system. This sample uses the latter, so the thread is sent to use Coinitialize to enter STA instead of MTA to obtain a pointer to the agent object rather than canceling the call (interested you can try it yourself, change CTASK :: Task Coinitialize to Coinitializeex To enter the MTA, the task will end failed). However, because any COM component object is generated in this thread, that is, any object is not included in this STA suite, so there is no need to write a message loop. In the second case, it is assumed that the CocreateInstance is called by calling CocreateInstance in each initiated call thread to obtain a new instance of the business component, then the method on which it is called, it is actually the call thread that will only be initiated. Call, there is no need to exist in the MTA suite. This is very compliant with the programming model provided by the MTS, and the service component is registered as the MTS component and implements the object pool function and the job-in-time activity, it is caused by each call CocreateInstance. The loss is almost equal, but the structure of the program is very simple, no complex logic. However, this is not considered to be written as the MTS component, and the above advantage is the harm of this article, and it is impossible to demonstrate the multi-thread to the call processing of business components. Therefore, a global business component object is provided to make it a FREE component, and the progress of the correct thread task is notified through the iTasknotify in each initiated call thread (actually only one thread will be notified - the client main thread. Here Just explain how to use the correct proxy object to notify, but because the business component is in the MTA suite, only one thread will be notified, there is no need to keep the NeutaskNotify * neutral form, that is, the agent object of each calling thread is meaningful. The same is the same, perhaps there will be fine differences, depending on the implementation of the COM running period. But here as a demonstration still saves iTaskNotify * in neutral form.

For the termination of the second case thread (see the following code), I just let the business logic are WaitForsingleObject an event to promptly respond to the time consumption of the termination event and the simulation work. It is certainly impossible. If you are a loop, you can wait for an event (or call the ICANCELMETHODCALLS method) through each cycle, there is no event to continue the cycle (this is best to monitor a global variable) Not waiting for an event). If it is not a loop, it is time-consuming operation, and the operation does not provide any interrupted interface, it can only be forced to terminate. In the above two cases, two methods TASK1 and TASK2 in the service component interface are implemented, respectively, and this service component is the process within the process of the free type. Due to the large number of code, only the code in the service component code in the second case is listed in the second case. If you want to get other relevant source code, please download it in "COM Sample (4)".

Calls originating in the second case the code ...... // marshaled interface pointer IExample1Logic IStream * pStream = NULL; if (FAILED (:: CoMarshalInterThreadInterfaceInStream (IID_IExample1Logic, m_pLogic, & pStream))) {m_pError-> ReportHardError (__WFILE__, __LINE__, L "Columns IExample1Logic Interface Failed!"); Return;} // Starting thread Handle Hthread = CreateThread (Null, 0, Task2, Pstream, 0, Null); if (! Hthread) {pstream-> release (); m_Perror -> ReporthardError (__wfile__, __line__, l "task thread creation failed!"); Return;} :: closehandle (hthread); ...... Calling thread code STATIC DWORD WINAPI Task2 (LPVOID PPARAM) {Assert PPARAM); // Bind this thread with the MTA Sackage :: CoinitializeEx (null, coinit_multithread; // Spread Iexample1Logic interface pointer IExample1Logic * PLogic = NULL; if (Failed (:: cogeti) nterfaceAndReleaseStream (reinterpret_cast (pParam), IID_IExample1Logic, reinterpret_cast (& pLogic)))) return static_cast (-1); // perform tasks pLogic-> Task2 (); // release resources Plogic-> Release (); :: Couninitialize (); RETURN 0;} Interface definition of business component business components in the second case [Object, UUID (348FF439-26B3-495D-85C1-4464CAA98CD9), Pointer_Default (unique) ] interface iexample1logic: IUNKNOWN {HRESULT TASK1 (); HRESULT TASK2 ();

[Object, uuid (348FF439-26B3-495D-85C2-4464CAA98CD9), pointer_default (unique)] interface ISetTaskManager: IUnknown {HRESULT SetTaskManager ([in] ITaskManager * pManager);}; ITask implementation class header code class CExample1Logic; class ATL_NO_VTABLE CTask: public CComObjectRootEx , public ITask {// ATL define macros DECLARE_NOT_AGGREGATABLE (CTask) DECLARE_PROTECT_FINAL_CONSTRUCT () BEGIN_COM_MAP (CTask) COM_INTERFACE_ENTRY (ITask) END_COM_MAP () // member variables protected: float m_Rate; // current progress DWORD m_Cookie / // i i i; 等 等 等 等 等 合 合 合 构 合 合 合 合 合 合 合 合 合 合 合 合 合 共 合 合 合 共 合 合 合 合,,, (() ), M_hevent (null) {// everything does not do} ~ ctask () {:: closehandle (m_hevent);} // interface implementation public: // itask stdmethod (float * PRATE); stdmethod (TerminateTask) (); // Friends Waters Friend Class Cexample1Logic;}; Itask Implementation Class Source File Code Stdmethodimp Ctask :: GetProc essRateOfTask (float * pRate) {if (! pRate) return E_INVALIDARG; * pRate = m_Rate; return S_OK;} STDMETHODIMP CTask :: TerminateTask () {if return E_FAIL; return :: SetEvent (m_hEvent) S_OK (m_hEvent!)?: E_FAIL;} Business component header code Class ATL_NO_VTABLE CEXAMPLE1LOGIC: PUBLIC CCOMOBJECTEX , Public CCOMCOCLASS

, Public IExample1Logic, public ISetTaskManager {// ATL define the macro public: DECLARE_PROTECT_FINAL_CONSTRUCT () DECLARE_REGISTRY_RESOURCEID (IDR_EXAMPLE1LOGIC) BEGIN_COM_MAP (CExample1Logic) COM_INTERFACE_ENTRY (IExample1Logic) COM_INTERFACE_ENTRY (ISetTaskManager) END_COM_MAP () // constructor, destructor blic: CExample1Logic (): m_Cookie ( static_cast (-1)) {:: InitializeCriticalSection (& m_CS);} ~ CExample1Logic (); // member variable protected: DWORD m_Cookie; GIT // ITaskManager of the cookie CRITICAL_SECTION m_CS; // for protecting m_TaskManagerCookie // interface public: // IExample1Logic STDMETHOD (Task1) (); STDMETHOD (Task2) (); // ISetTaskManager STDMETHOD (SetTaskManager) (ITaskManager * pManager);}; extern source code for the business component IGlobalInterfaceTable * g_pGIT; CExample1Logic :: ~ CEXAMPLE1LOGIC () {:: deletecriticalsection; atlassert (g_pgit); // Logouts the original M_Cookie if (m_cookie! = Static_cast (-1)) atlverify (succeeded (g_pgit-> revokeinterfacefrom Global (m_cookie)));}}}}} {SLEEP (300; i ) {Sleep CEXAMPLE1LOGIC :: Task1 () {// SLEEP For a period of time to simulate long-time call for if (:: CoTestCancel () == RPC_E_CALL_CANCELED) return E_ABORT;} return S_OK;} STDMETHODIMP CExample1Logic :: Task2 () {// get the right by GIT ITaskManager agent ITaskNotify * pNotify = NULL; ITaskManager * pManager = NULL;: : ENTERCRITICALSECTION; if (m_cookie! = Static_cast (-1)) {atlassert (g_pgit); // must complete the work IF regardless of whether GetInterfaceFromGlobal is successful,

GetInterfaceFromGlobal (m_Cookie, IID_ITaskManager, reinterpret_cast (& pManager)))) pManager-> QueryInterface (IID_ITaskNotify, reinterpret_cast (& pNotify));} :: LeaveCriticalSection (& m_CS); // Start Task static DWORD index = 1; ITask * pTask = NULL; CComObject * pTaskObject = NULL; if (FAILED (CComObject :: CreateInstance (& pTaskObject))) return E_FAIL; ATLVERIFY (SUCCEEDED (pTaskObject-> QueryInterface (IID_ITask, reinterpret_cast (& ptask)))))); DWORD cookie = static_cast (-1); wchar Temp [10]; WSPRINTF (Temp, L "task two% D", Index ); ptaskobject-> m_hevent = :: CreateEvent (Null, True, False, Null); IF (PManager && Faled (PManager-> Addtask (Temp, PTASK, & Cookie)) Cookie = static_cast (-1 ); SAFERELEASE (PManager); // Sleep Division Division During the simulation of the completion of the work IF (: waitforsingleObject (ptaskobject-> m_hevent, 4000) == Wait_Object_0) goto terminate; ptaskobject-> m_rate = 0.3f; if (IF) pNotify) pNotify-> ProcessRateChange (cookie); if (:: WaitForSingleObject (pTaskObject-> m_hEvent, 4000) == WAIT_OBJECT_0) goto TERMINATE; pTaskObject-> m_Rate = 0.6f; if (pNotify) pNotify-> ProcessRateChange (cookie); IF (:: WaitForsingleObject (ptaskobject-> m_hevent, 4000) == Wait_Object_0) goto terminate; PTASKObject->

转载请注明原文地址:https://www.9cbs.com/read-22591.html

New Post(0)