OSEC

Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
 
From: Ben Callister (BCallister_at_TUTOR.COM)
Date: Thu Feb 27 2003 - 10:54:14 CST

  • Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]

    hello:

    i have a vc++ component that has a method that takes some params about a COM object (its progid, desired method name, desired argument, and desired apartment model). it will then spawn a new thread in the specified apartment model (STA or MTA), creates the object and calls the desired method. eventually it will post the results back to the main thread.

    below is my thread function. the question i have is whether or not this thread function is done correctly. in particuliar, for an STA scenario. i thought you were supposed to manage your own message pump, and as you can see, im not doing anything like that. can someone explain this situation for my context? i know you want a message pump to keep messages flowing, but i dont know how i would do that in this situation because the method im calling on the desired COM object is a syncronous blocking call - which is one of the reasons why this is on another thread. anyway, please help me understand if im missing something.

    the reason i ask is twofold:
    1) i want to make sure im doing this correctly
    2) im experiencing a problem where every so often a thread doesnt want to return. of course, this could be due to the work that is being done in the created COM object, but i wanted to rule out this possibility.

    thanks for any help you can offer.

    Benjamin Callister
    Vice President of Engineering, Tutor.com
    Real Tutors, Real Results.
     
    e: bcallistertutor.com
    p: 212.528.3101; x.227
    w: http://www.tutor.com

    ================================================
    ================================================

    // -----------------------------------------------------------------------
    // DispatcherWorkerThreadProc
    // -----------------------------------------------------------------------
    DWORD WINAPI DispatcherWorkerThreadProc(LPVOID lpParameter)
    {
            /////////////////////////////////////////////////////////////////////////////
            // This is a "Worker" thread function (check 'GetCurrentThreadId()')
            /////////////////////////////////////////////////////////////////////////////
            
            HRESULT hr;
            USES_CONVERSION;
            
            //get data passed to worker thread from main thread
            LP_DISPATCHER_THREAD_PACKAGE lpPackage = NULL;
            lpPackage = (LP_DISPATCHER_THREAD_PACKAGE)lpParameter;
            if (lpPackage)
            {
                    //enter the desired apartment type
                    if (lpPackage->lAptType == 1)
                            ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
                    else
                            ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
                    
                    ///////////////////////////////////////////////////////////////////////////////////////////
                    
                    CComBSTR bProgID = lpPackage->bstrProgID;
                    CComBSTR bMethodName = lpPackage->bstrMethodName;
                    CComBSTR bInitArg = lpPackage->bstrInitArg;
                    
                    ///////////////////////////////////////////////////////////////////////////////////////////
                    
                    VARIANT_BOOL vbSuccess = VARIANT_TRUE; //success indicator 1
                    CComBSTR bstrErrDesc(""); //success indicator 2
                    long lErrNum = 0; //success indicator 3
                    
                    VARIANT vResults;
                    ::VariantInit(&vResults);
                    IDispatch* pTargetDisp = NULL;
                    if (bProgID.Length() > 0)
                    {
                            CLSID theCLSID;
                            hr = ::CLSIDFromProgID(bProgID, &theCLSID);
                            if (SUCCEEDED(hr))
                            {
                                    hr = ::CoCreateInstance(theCLSID, NULL, CLSCTX_INPROC, IID_IDispatch, (void**)&pTargetDisp);
                                    if (SUCCEEDED(hr))
                                    {
                                            if (bMethodName.Length() > 0)
                                            {
                                                    //build up paramaters to pass to Invoke() call
                                                    VARIANTARG vArg;
                                                    ::VariantInit(&vArg);
                                                    vArg.vt = VT_BSTR;
                                                    vArg.bstrVal = bInitArg;
                                                    
                                                    DISPPARAMS dispparams;
                                                    dispparams.cArgs = 1;
                                                    dispparams.rgvarg = &vArg;
                                                    dispparams.cNamedArgs = 0;
                                                    dispparams.rgdispidNamedArgs = NULL;
                                                    
                                                    //get the dispID for the function that we want to run on the passed interface
                                                    DISPID dispid;
                                                    OLECHAR FAR* szMember = bMethodName;
                                                    hr = pTargetDisp->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_USER_DEFAULT, &dispid);
                                                    
                                                    //now invoke the method on the passed interface
                                                    hr = pTargetDisp->Invoke(
                                                                                            dispid,
                                                                                            IID_NULL,
                                                                                            LOCALE_USER_DEFAULT,
                                                                                            DISPATCH_METHOD,
                                                                                            &dispparams, &vResults, NULL, NULL);
                                                    if (FAILED(hr))
                                                    {
                                                            #ifdef _TRACE
                                                            ATLTRACE("DispatcherWorkerThreadProc() - COM Invoke Failed.\n");
                                                            #endif // _TRACE
                                                            
                                                            //TODO: hook this up with ISupportErrorInfo
                                                            lErrNum = 13;
                                                            vbSuccess = VARIANT_FALSE;
                                                            LPVOID lpMsgBuf;
                                                            ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL );
                                                            std::string sTempErr = "Error, the specified method on the specified object failed. ";
                                                            sTempErr += (LPCTSTR)lpMsgBuf;
                                                            ::LocalFree(lpMsgBuf);
                                                            bstrErrDesc = sTempErr.c_str();
                                                    }
                                            }
                                    }
                                    else
                                    {
                                            lErrNum = 13;
                                            vbSuccess = VARIANT_FALSE;
                                            bstrErrDesc = L"Error, unable to create target object. CoCreateInstance() failed.";
                                    }
                            }
                            else
                            {
                                    lErrNum = 13;
                                    vbSuccess = VARIANT_FALSE;
                                    bstrErrDesc = L"Error, unable to retrieve CLSID from specified ProgID.";
                            }
                    }
                    
                    ///////////////////////////////////////////////////////////////////////////////////////////
                    
                    //create some data to pass back to "main" thread on the heap
                    LP_DISPATCHER_RETURN_THREAD_PACKAGE lpReturn = NULL;
                    lpReturn = new DISPATCHER_RETURN_THREAD_PACKAGE;
                    if (lpReturn)
                    {
                            lpReturn->bstrTag = lpPackage->bstrTag;
                            lpReturn->bstrTag2 = lpPackage->bstrTag2;
                            lpReturn->vResult = vResults;
                            lpReturn->bResult = vbSuccess;
                            lpReturn->bstrErrDesc = bstrErrDesc;
                            lpReturn->lErrNum = lErrNum;
                            lpReturn->dwThreadId = GetCurrentThreadId();
                    }
                    
                    //this is an asynchronous call to post a message back to the main thread
                    //but you could make this a synchronous call by calling ::SendMessage(),
                    //however, if you made it synchronous, you would not make the call to
                    //AtlWaitWithMessageLoop() in the "OnThreadComplete()" method
                    ::PostMessage(lpPackage->hWnd, _WM_DISPATCHTHREADCOMPLETE, 0, (LPARAM)lpReturn);
                    // LRESULT lResult = ::SendMessage(lpPackage->hWnd, _WM_DISPATCHTHREADCOMPLETE, 0, (LPARAM)lpReturn);
                    
                    //delete parameter data from the heap
                    delete lpPackage;
                    
                    ///////////////////////////////////////////////////////////////////////////////////////////
                    CoUninitialize();
            }
            
            return 0;
    }

     

     

    ----------------------------------------------------------------
    Users Guide http://discuss.microsoft.com/archives/mailfaq.asp
    contains important info. Save time, search the archives at
    http://discuss.microsoft.com/archives/index.html .
    To unsubscribe, mailto:DCOM-signoff-requestDISCUSS.MICROSOFT.COM