|
-
February 22nd, 2006, 11:56 AM
#1
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;
}
-
February 22nd, 2006, 12:22 PM
#2
Re: Access to COM Methods in ATL Service
Which error code does CoCreateInstance return?
-
February 22nd, 2006, 01:01 PM
#3
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
-
February 24th, 2006, 02:27 PM
#4
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();
}
-
February 24th, 2006, 08:41 PM
#5
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|