CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 5 of 5
  1. #1
    Join Date
    May 1999
    Location
    Saint Paul, Minnesota, US
    Posts
    91

    Access to COM Methods in ATL Service

    Hi ...

    I have written a Windows Service using ATL COM (ATL3 / Visual Studio 6.0). The service works fine, I am able to start and stop the service.

    I have created a COM Class called CTest with a methof called TestBeep(). I would like to access this object and call the method from the CServiceModule::Run() method.

    Below is the CServiceModule::Run() Method.
    The code will fail on both attempts to create the ITest* pTest using CoCreateInstance(). The error message are written to the event log
    "Error: ITest failed"
    "CoCreateInstance failed"

    Any help is appreciated,
    Thanks,
    Chris



    Code:
    void CServiceModule::Run()
    {
        _Module.dwThreadID = GetCurrentThreadId();
    
        HRESULT hr = CoInitialize(NULL);
    //  If you are running on NT 4.0 or higher you can use the following call
    //  instead to make the EXE free threaded.
    //  This means that calls come in on a random RPC thread
    //  HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    
        _ASSERTE(SUCCEEDED(hr));
    
        // This provides a NULL DACL which will allow access to everyone.
        CSecurityDescriptor sd;
        sd.InitializeFromThreadToken();
        hr = CoInitializeSecurity(sd, -1, NULL, NULL,
            RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
        _ASSERTE(SUCCEEDED(hr));
    
        hr = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, REGCLS_MULTIPLEUSE);
        _ASSERTE(SUCCEEDED(hr));
    
        LogEvent(_T("Blue Service started"));
        LogEvent(_T("Message 1"));
        LogEvent(_T("Message 2"));
    
        if (m_bService)
            SetServiceStatus(SERVICE_RUNNING);
    
        MSG msg;
        while (GetMessage(&msg, 0, 0, 0))
            DispatchMessage(&msg);
    
        _Module.RevokeClassObjects();
    
    
        // --------------------------------------------
        // We will try to call the COM Object from here 
    
    	char progID[] = "Blue.Test.1";
    
    	// Now make that object.
    	CLSID clsid;
    	wchar_t wide[80]; 
    	mbstowcs(wide, progID, 80);
    	CLSIDFromProgID(wide, &clsid);
    
        LogEvent(_T("Attempt to use ITest"));
    
    	ITest* pTest = NULL;
    	if(SUCCEEDED(CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_ITest, (void**)&pTest)))
    	{
    		pTest->TestBeep(); 
    	}
        else
        { 
            LogEvent(_T("Error: ITest failed"));
        } 
    
    
        // We will try this another way !! 
        // We have downloaded a ATL COM Server sample and it had 
        // A COM Method in in and it was not called from within the 
        // Service (as we are trying to do) it was called from a
        // Windows Console Application using the following.  
        // We would like to make this call into com from in the 
        // Service !! 
    
        // Time to write to the CodeGuru
        
    	CComPtr<ITest> pObj;
    	hr = pObj.CoCreateInstance(OLESTR("Blue.Test.1"));
    	if( SUCCEEDED(hr) )
    	{
    		hr = pObj->TestBeep();
    		if( SUCCEEDED(hr) )
            { 
                LogEvent(_T("Call to ITest was successful"));
            }
            else
            { 
                LogEvent(_T("Error: ITest failed"));
            } 
    	}
    
    	if( FAILED(hr) )
        { 
            LogEvent(_T("CoCreateInstance failed"));
        }
    
        CoUninitialize();
    }

    This is the implementation of the CTest Class and the TestBeep() method


    Code:
    // Test.h : Declaration of the CTest
    
    #ifndef __TEST_H_
    #define __TEST_H_
    
    #include "resource.h"       // main symbols
    
    /////////////////////////////////////////////////////////////////////////////
    // CTest
    class ATL_NO_VTABLE CTest : 
    	public CComObjectRootEx<CComSingleThreadModel>,
    	public CComCoClass<CTest, &CLSID_Test>,
    	public IDispatchImpl<ITest, &IID_ITest, &LIBID_BLUELib>
    {
    public:
    	CTest()
    	{
    	}
    
    DECLARE_REGISTRY_RESOURCEID(IDR_TEST)
    
    DECLARE_PROTECT_FINAL_CONSTRUCT()
    
    BEGIN_COM_MAP(CTest)
    	COM_INTERFACE_ENTRY(ITest)
    	COM_INTERFACE_ENTRY(IDispatch)
    END_COM_MAP()
    
    // ITest
    public:
    	STDMETHOD(TestBeep)();
    	STDMETHOD(GetCount)();
    	int nCount;
    };
    
    #endif //__TEST_H_
    
    
    
    // Test.cpp : Implementation of CTest
    #include "stdafx.h"
    #include "Blue.h"
    #include "Test.h"
    
    /////////////////////////////////////////////////////////////////////////////
    // CTest
    
    
    STDMETHODIMP CTest::GetCount()
    {
    	// TODO: Add your implementation code here
    
    	return S_OK;
    }
    
    STDMETHODIMP CTest::TestBeep()
    {
    	// TODO: Add your implementation code here
        Beep(4000, 200); 
        Beep(1000, 50); 
        Beep(4000, 200); 
        Beep(1000, 50); 
    	return S_OK;
    }

  2. #2
    Join Date
    Mar 2004
    Posts
    7

    Re: Access to COM Methods in ATL Service

    Which error code does CoCreateInstance return?

  3. #3
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Access to COM Methods in ATL Service

    Macgowen, your code seems to imply that you are trying to call the Blue.Test.1 interface from within the void CServiceModule::Run() method. Is this correct? If so, any code after the following won't get executed until after the service has shutdown.

    Code:
    MSG msg;
    while (GetMessage(&msg, 0, 0, 0))
      DispatchMessage(&msg);
    
    _Module.RevokeClassObjects();
     
    // code here doesn't execute until after the service has been signalled to exit.
    Arjay

  4. #4
    Join Date
    May 1999
    Location
    Saint Paul, Minnesota, US
    Posts
    91

    Re: Access to COM Methods in ATL Service

    Thanks Arjay ....

    I put the code before the message loop and it works great :--)
    Thanks again

    Below is the working code if anyone is interested

    Code:
    void CServiceModule::Run()
    {
        _Module.dwThreadID = GetCurrentThreadId();
    
        HRESULT hr = CoInitialize(NULL);
    //  If you are running on NT 4.0 or higher you can use the following call
    //  instead to make the EXE free threaded.
    //  This means that calls come in on a random RPC thread
    //  HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    
        _ASSERTE(SUCCEEDED(hr));
    
        // This provides a NULL DACL which will allow access to everyone.
        CSecurityDescriptor sd;
        sd.InitializeFromThreadToken();
        hr = CoInitializeSecurity(sd, -1, NULL, NULL,
            RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
        _ASSERTE(SUCCEEDED(hr));
    
        hr = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, REGCLS_MULTIPLEUSE);
        _ASSERTE(SUCCEEDED(hr));
    
        LogEvent(_T("Blue Service started"));
        LogEvent(_T("Message 1"));
        LogEvent(_T("Message 2"));
    
        if (m_bService)
            SetServiceStatus(SERVICE_RUNNING);
    
    
        // --------------------------------------------
        // We will try to call the COM Object from here 
    
    	char progID[] = "Blue.Test.1";
    
        string strTemp; 
        char szTemp[10]; 
    
    	// Now make that object.
    	CLSID clsid;
    	wchar_t wide[80]; 
    	mbstowcs(wide, progID, 80);
    	CLSIDFromProgID(wide, &clsid);
    
        LogEvent(_T("Attempt to create the ITest Com Object"));
    
    	ITest* pTest = NULL;
    
        hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_ITest, (void**)&pTest); 
    
    	if(SUCCEEDED(hr))
    	{
    		pTest->TestBeep(); 
    	}
        else
        { 
            // LogEvent(_T("Error: ITest failed hresult"));
            sprintf(szTemp, "%h", hr); 
            strTemp = "Error: ITest failed.  HResult=" + (string)szTemp; 
            LogEvent(_T(strTemp.c_str()));
        } 
    
    
    
        MSG msg;
        while (GetMessage(&msg, 0, 0, 0))
            DispatchMessage(&msg);
    
        _Module.RevokeClassObjects();
    
        CoUninitialize();
    }

  5. #5
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Access to COM Methods in ATL Service

    Glad to hear you have it working.One small suggestion, if I may. Since you are working with COM and will undoubtly be using BSTR, check out the _bstr_t and CComBSTR classes. Also, you can use the L"" literal to create a wide string directly in code.

    The following code:

    Code:
     char progID[] = "Blue.Test.1"; 
    CLSID clsid;
    wchar_t wide[80]; 
    mbstowcs(wide, progID, 80);
    CLSIDFromProgID(wide, &clsid);
    becomes this after using the 'L' literal.
    Code:
     
    CLSID clsid;
    CLSIDFromProgID(L"Blue.Test.1", &clsid);
    Using CComBSTR, you'd have:

    Code:
     CLSID clsid; 
    CLSIDFromProgID(CComBSTR("OWC.Chart.9"), &clsid);

    If compiling for both ANSI and UNICODE are important, check out the
    _T("") macro found in <tchar.h>

    Code:
     // #include <tchar.h> 
    CLSID clsid;
    CLSIDFromProgID(CComBSTR(_T("OWC.Chart.9")), &clsid);
    The code above allows you to compile in either ANSI or UNICODE without having to change the string (when compiled in UNICODE, the
    _T("") macro handily adds the 'L' to the string)

    Arjay

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured