Introduction
Programming with scripts (VBScript, JScript) is quite an enjoyable experience, you can even develop a script based application using script components. Everybody knows how this kind of programming becomes powerful, taking advantage of ActiveX controls, but if you try to deploy a script using standard Microsoft ActiveX controls (e.g., MsComm for serial communication), then you'll have to overcome an annoying problem: many of such controls require a Runtime License in order to work on the end user PC. By the way, Visual C++ and Visual Basic environments automatically provide, for standard applications, such runtime license for each of the deployed components, but with scripting languages, it's a completely different matter: you are left alone, and have to provide 'by hand' this piece of info. I know of some workarounds out there, namely wrappers built around the target ActiveX control, however, I will show a direct approach in this article. You have to deal with two different problems:
- Knowing (obtaining) the Runtime License text.
- Providing such text in your script.
Here, I'll only show how to obtain such Runtime License text (point 2 represents the subject of another article, I think), querying it to the ActiveX. Of course, you must have Visual Studio installed on your PC. I developed a small application, namely
ComLicenceFinder, able to recognize all ActiveX controls registered on your PC, and to ask them for that piece of info.
Background
You should know how to use ActiveX controls in a script (see MSDN). A general knowledge of COM is also required (there are a lot of books about COM: inside COM, essential COM, etc...).
Using the application
On loading, ComLicenceFinder
queries the registry to obtain and list all ActiveX controls available on the PC. If you are interested about the runtime license info about any of them, first of all, select it and then click the right mouse button, and select, on the newly appeared context menu, the Get info item. The application will try to:
- Query a
IClassFactory
interface pointer to the Class Object (or Class Factory) of the selected ActiveX control.
- Query to the obtained pointer for a new pointer, this time to a
IClassFactory2
interface.
- Call the
IClassFactory2::GetLicInfo
method.
- Call the
IClassFactory2::RequestLicKey
method.
On successful completion of all of the above steps, you will have the requested Runtime License text; however, the result of each step is reported in a field of the listview, that by the way, should be interpreted as follows:
Field | Type | Description | Note |
---|
Name | String | Friendly name of the ActiveX control, as found in the registry | - |
CLSID | String | Class ID of the ActiveX control. | This is the unique identifier of the ActiveX control, and has to be used by any script requiring the latter. |
Creatable | Yes/No | Yes if the IClassFactory interface was successfully obtained | If No , maybe the item corresponds to an incorrect entry in the registry |
Lic. Info | Yes/No | Yes if there is a runtime license available | If there isn't a runtime license available, you can still try to use the ActiveX control, perhaps it doesn't require a license at all. |
License text | String | The runtime license text | - |
The relevant code is contained by the GetLicenceInfo
function (I've stripped off some boring parts such as insertions into the listview):
HRESULT hr = CoGetClassObject(uuid, CLSCTX_ALL, NULL,
IID_IClassFactory, (void**)&pCF);
if ( FAILED(hr) ) return;
hr = pCF->QueryInterface(IID_IClassFactory2, (void**)& pCF2);
pCF->Release();
if ( FAILED(hr) ) return;
LICINFO licInfo;
licInfo.cbLicInfo = sizeof(licInfo);
hr = pCF2->GetLicInfo(&licInfo);
if ( FAILED(hr) )
{
pCF2->Release();
return;
}
fSuccess = (licInfo.fRuntimeKeyAvail == TRUE &&
licInfo.fLicVerified == TRUE ) ? true : false;
if (! fSuccess)
{
pCF2->Release();
return;
}
hr= pCF2->RequestLicKey( 0, & bstrLic );
if ( FAILED(hr) )
{
pCF2->Release();
return;
}
ZeroMemory(buf, BUFSIZE);
fSuccess = WideCharToMultiByte(CP_ACP, 0, bstrLic,
SysStringLen(bstrLic), buf, BUFSIZE,
NULL, NULL) == 0 ? false : true;
pCF2->Release();
SysFreeString(bstrLic);
if (! fSuccess )
{
return;
}
Points of Interest
The context menu Copy item can be used to copy the relevant info (i.e., Name, CLSID, License Text) to the Clipboard (and then to Paste them into your script...).
The Save item of the context menu, on the other hand, saves to a chosen XML file the whole (current) content of the list view (a lookup table for the CLSID of all the ActiveX controls on your PC?!?).
It is worth nothing that the application needs to link the Rpcrt4.lib to use the function UuidFromString
only.
History