As we know, using an ActiveX control in an MFC application is very easy.
However, on many occasions I need to use an ActiveX control within a console
application. For example, I need to send e-mail from an NT service
program in one of my recent projects. Here is what I did to solve
this problem.
- Create an ActiveX control using simple MAPI calls that exposes
only a SendMail method.
- Write a few simple functions that can be used in a console
app to create the ActiveX control and call its methods.
- Send e-mail within my NT service program using the above functions.
Note: The functions I wrote in step 2 can handle methods
that take only string arguments (the return type is not restricted).
But they can be modified easily to handle more complicated arguments.
Here is a piece of sample code in a console application that sends an
e-mail message using the ActiveX control I built.
static CLSID clsid = {0xfd543ffb, 0x9664, 0x11d3, {0x8b, 0xd9, 0x40, 0, 0x31,
0x3, 0x95, 0xe3}};
VARIANT varOutput;
IDispatch* pInterface = 0;
if(CreateComDispatch(clsid,&pInterface))
{
const char * pParams[] = {"xliu", "jrao", "test message title",
"test message text"};
if(CallStringMethodByName(pInterface, "SendMail", 4, pParams,
&varOutput))
{
}
else
{
}
}
Here is header file for the fucntions in step 2.
#ifndef CONSOLEUTILITY_H
#define CONSOLEUTILITY_H
#include <wtypes.h>
IDispatch* CreateComDispatch(REFCLSID clsid,IDispatch** ppDisp);
int CallStringMethodByID(IDispatch* pDisp,
const DISPID dispid,
const int nParamCount,
const char* pInputParam[],
VARIANT* pOutput);
int CallStringMethodByName(IDispatch* pDisp,
const char* pName,
const int nParamCount,
const char* pInputParam[],
VARIANT* pOutput);
#endif
Here is the implementation file.
#include "ConsoleUtility.h"
IDispatch* CreateComDispatch(REFCLSID clsid,IDispatch** ppDisp)
{
static int init = 1;
if(init)
{
if(CoInitialize(NULL)!=S_OK) return 0;
init = 0;
}
HRESULT hRet = CoCreateInstance(clsid,
NULL,
1,
IID_IDispatch,
(void**)(ppDisp) );
if(hRet!=S_OK)
{
*ppDisp = 0;
}
return *ppDisp;
}
static unsigned short* GetBuffer(const char* input)
{
int nSize = 1;
if(input!=0)
{
nSize += strlen(input);
}
short* output = new short[nSize];
for(int i=0;i<nSize-1;i++)
{
output[i] = input[i];
}
output[nSize-1] = 0;
return (unsigned short*)output;
}
int CallStringMethodByID(IDispatch* pDisp,
const DISPID dispid,
const int nParamCount,
const char* pInputParam[],
VARIANT* pOutput)
{
HRESULT hRet;
DISPPARAMS callParams = {NULL,NULL,0,0};
if(nParamCount>0)
{
callParams.cArgs = nParamCount;
callParams.rgvarg = new VARIANTARG[nParamCount];
unsigned short * output;
for(int i=0;i<nParamCount;i++)
{
output = GetBuffer(pInputParam[nParamCount-i-1]);
callParams.rgvarg[i].bstrVal = ::SysAllocString(output);
callParams.rgvarg[i].vt = VT_BSTR;
delete []output;
}
}
unsigned int nArgErr;
hRet = pDisp->Invoke(dispid,
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD,
&callParams,
pOutput,
NULL,
&nArgErr);
if(hRet!=S_OK)
{
if(nParamCount>0) delete [](callParams.rgvarg);
return 0;
}
if(nParamCount>0) delete [](callParams.rgvarg);
return 1;
}
int CallStringMethodByName(IDispatch* pDisp,
const char* pName,
const int nParamCount,
const char* pInputParam[],
VARIANT* pOutput)
{
HRESULT hRet;
DISPID dispid;
unsigned short* pOLEName = GetBuffer(pName);
hRet = pDisp->GetIDsOfNames(IID_NULL,
&pOLEName,
1,
LOCALE_SYSTEM_DEFAULT,
&dispid);
delete []pOLEName;
if(hRet!=S_OK)
{
return 0;
}
return CallStringMethodByID(pDisp,
dispid,
nParamCount,
pInputParam,
pOutput);
}