|
|
Can I use The Enabler ActiveX controls from within a Windows Service EXE?
Good question! The answer is yes. Before we tell you how, we will first explain some of the background to the answer.
Background
The Enabler ActiveX controls (like many third-party controls) were created using MFC, so are easily used from within a VC++ MFC application.
However, Windows Service EXE projects created using the Visual C++ AppWizard are ATL applications. The AppWizard does not properly support MFC for this type of application so (as you may have discovered) it is not obvious how to use our ActiveX controls from within one of these projects.
The main problem is not with The Enabler ActiveX controls themselves, but with the AppWizard and the Windows Service code it produces. Luckily Microsoft have provided some clues in the following article in their Knowledge base:
173974 KB: How To Add MFC Support to an ATL Project
Although the advice in this article does not work for an ATL Service EXE, most of the advice is still relevant. We have developed this further to assist you in creating an ATL Service that should allow you to use any ActiveX control.
There are other ways to use ActiveX controls from within an ATL Service, but we believe the most logical approach is to create an MFC dialog. An MFC dialog provides the best container for an ActiveX control, and using the Class Wizard you can write code just as you would for any normal dialog-based MFC C++ application.
NOTE: Unless your Windows Service is setup to allow interaction with the Windows Desktop, any dialog(s) you create from within the Service will not be visible (open the Service Manager and check the service properties). In most cases you are choosing to write your application as a Service because no user interaction is required, but you may also want to display a status window directly from the Service.
Creating an ATL Windows Service project
To create a new ATL Service project using Visual C++:
Go to the File menu and select New...->Projects->ATL COM AppWizard
Enter the project name, and click Ok.
Select NT Service and click Ok.
Creating an MFC Dialog within an ATL Windows Service project
Add the following lines to StdAfx.h prior to including Atlbase.h:
#include <afxwin.h> // MFC core and standard components
#include <afxext.h> // MFC extensions
#include <afxdisp.h> // MFC Automation extensions
Change project settings to use MFC. From the Project Settings dialog box, click the General tab, and make sure the Microsoft Foundation Classes dropdown list is set to Use MFC as a Static Library.
For Unicode builds, make sure the entry point is set to wWinMainCRTStartup in the Output category of the Link field in the Project Settings dialog box. For additional information, please see the following article in the Microsoft Knowledge base:
125750 PRB: Error LNK2001: '_WinMain@16': Unresolved External Symbol
If your Service Application publishes any COM interface of it's own, you may need to add the following line of code to the beginning of every member function of the COM interface:
AFX_MANAGE_STATE( AfxGetAppModuleState() );
For more information on AFX_MANAGE_STATE, consult the VC++ online documentation.
Before you can add a form to your project, you need a ClassWizard file. If you already have a ClassWizard file go to the next step. To create an empty Class Wizard (CLW) file:
Go to the View menu and click ClassWizard.
A popup dialog will prompt you to select the files to add, just click Ok.
The ClassWizard will now be shown, and you can click Ok to close it.
Go to the Insert menu and click New Form... to add a form to your project. Enter a name for the new form, and the wizard will generate the form class code.
The sample code below assumes the form class is called CEnablerDlg. You may need to add the following line to the header file for your new Form Class:
#include "resource.h"
To create a thread for our form, add the following code to your main Service .CPP file prior to the definition of _tWinMain:
class CFormThread : public CWinThread
{
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
DECLARE_DYNCREATE( CFormThread );
};
IMPLEMENT_DYNCREATE(CFormThread, CWinThread)
BOOL CFormThread::InitInstance()
{
// now call the InitInstance() in our parent class
CWinThread::InitInstance();
// initialise COM for use by this thread
HRESULT hr = CoInitialize( NULL );
// we have to initialise the Instance and Resource handles
afxCurrentInstanceHandle = GetModuleHandle( NULL );
AfxSetResourceHandle( GetModuleHandle( NULL ) );
// Initialize OLE libraries.
if ( !AfxOleInit() )
{
AfxMessageBox(_T("OLE Initialization Failed!"));
return FALSE;
}
// we want to be a container for OLE controls
AfxEnableControlContainer();
// at last we can create the MFC window object and show it
LPCTSTR szClass = AfxRegisterWndClass( NULL );
// YOUR FORM CLASS NAME
m_pMainWnd = new CEnablerDlg;
CDialog* tmpDialog = (CDialog*)m_pMainWnd;
// YOUR FORM RESOURCE ID
tmpDialog->Create( IDD_ENABLERDLG_DIALOG );
tmpDialog->ShowWindow( true );
return TRUE;
}
int CFormThread::ExitInstance()
{
return 0;
}
To load your MFC form at Service startup, locate _Module.Start(); in _tWinMain and add the lines in bold below::
// create our MFC thread object, and start it
CFormThread CFormThread;
CWinThread *form = AfxBeginThread( RUNTIME_CLASS( CFormThread ),
0, 0, 0, NULL );
// now start the main service control thread
_Module.Start();
// before we exit, we need to tell the MFC form thread to quit
form->PostThreadMessage( WM_QUIT, 0, 0 );
You should now be able to compile and register your ATL Service. When the service is started, the form should be displayed (requires the service to be allowed to interact with the desktop).
Adding The Enabler ActiveX controls to the project
Once you have completed all the steps in the previous section it is now a simple task to add The Enabler ActiveX controls to the project, and to your MFC dialog.
Go to the Project menu and click Add to project->Components and Controls...
Double click Registered ActiveX Controls.
Select the required controls (e.g. EnbSessionX, EnbPumpX) one at a time, and click Insert.
You will be prompted to confirm the wrapper Classes for the Control, click Ok.
When you have added all the required controls, click Close.
When you open your form in the VC++ dialog editor, the Controls palette should now show the ActiveX controls you have added into the project, allowing you to add these to your form.
You can now use the ClassWizard to associate controls to variables, and to add method and event implementations.
© 2005 Integration Technologies Limited
Last revised Wednesday, 04-Nov-2009 18:41:47 EST
|