HP Operations Manager for Windows

COM-API Development Practices


This section includes the following articles:

Creating a New COM-based MSI Client

Note NOTE:
You can perform the first two steps of this procedure in a few minutes using the wizards built into Visual Studio 2005.

To create a new COM-based MSI client, follow these steps:

  1. Create a COM application that can act as a host for your MSI Client class.

    This application might be an executable (EXE) or a DLL, which is designed to run in a surrogate process. Either way, your MSI Client class must support the instantiation as a local server (CLSCTX_LOCAL_SERVER).

    This figure shows an example project setup in Microsoft Visual Studio 2005. The Application is called "ComMsiApp." The build result is a COM executable.

    Sample Project: ComMsiApp

  2. Inside the new COM application, create the new MSI Client class.

    In the example, this class is the "ComMsiClient" class.

  3. Include IOvOWMsiClient.idl and OvOWExTypes.idl in your project, so that it can be processed by the MIDL tool.

    Including these files will generate the type library as well as a header file and marshalling code.

  4. Declare the IOvOWMsiClient interface in your COM client IDL file.
    import "oaidl.idl";
    import "ocidl.idl";
    
    import "OvOWMsiClient.idl";
    
    //...
    // interface definition for your ComMsiClient
    
    [
    		uuid(52463E05-58AB-4D33-B675-E20D6CCA2F0D),
    		version(1.0),
    		helpstring("ComMsiApp 1.0 Type Library")
    ]
    library ComMsiAppLib
    {
    		importlib("stdole2.tlb");
    		[
    				uuid(48A4B84E-9A15-43BC-8260-60152C2482EE),
    				helpstring("ComMsiClient Class")
    		]
    		coclass ComMsiClient
    		{
    				[default] interface IComMsiClient;
    				interface IOvOWMsiCLient;
    	};
    };
    
  5. Declare the IOvOWMsiClient interface in your COM client header file.
    // ComMsiClient.h : Declaration of the CComMsiClient
    
    #pragma once
    #include "resource.h"
    
    #include "ComMsiApp.h"
    
    // CComMsiClient
    class ATL_NO_VTABLE CComMsiClient :
    		public CComObjectRootEx<CComMultiThreadModel>,
    		public CComCoClass<CComMsiClient, &CLSID_ComMsiClient>,
    		public ISupportErrorInfo,
    		public IComMsiClient,
    		public IOvOWMsiClient
    {
    //...
    };
    

In Microsoft Visual Studio 2005, you can reuse large parts of the wizard-generated code. You just need to implement the methods derived from IOvOWMsiClient. When the build succeeds, you are done with the basics.

You can find the MSI client example in the following directory:

%OvInstallDir%\examples\OVOW\DevelopmentKit\Server\MSI\CppCOM"

Working with MSI Interfaces

When working with MSI interfaces, you can do the following:

Connecting to the MSI Server

To connect to the MSI server, follow these steps:

  1. Retrieve the MSI server.

    To retrieve the MSI server in a method, you can use code such as the following.

    STDMETHODIMP CComMsiClient::retrieveMsiServer(IOvOWMsiServer **ppMsiServer)
    {
      CComPtr<IOvOWMsiLocator> pMsiLocator;
      HRESULT hr = CoCreateInstance(CLSID_OvOWMsiLocator, NULL, CLSCTX_INPROC_SERVER, IID_IOvOWMsiLocator, reinterpret_cast<void **>(&pMsiLocator));
      if (FAILED(hr))
      {
    	// maybe trace the hr; something went wrong
    	return hr;
      }
      if (pMsiLocator == NULL)
      {
    	return E_FAIL;
      }
      CComPtr<IOvOWMsiServer> pMsiServer;
      hr = pMsiLocator->connectToMsiServer(&pMsiServer);
      if (FAILED(hr))
      {
    	// MSI Locator returned an error
    	return hr;
      }
      return pMsiServer.CopyTo(ppMsiServer);
    }
    

    You can also use easier and less cryptic ways of instantiating the MSI Locator. Instead of using the CLSID, you can use the ProgId. Instantiation with the ProgId works for all MSI components. For details, refer to the HPOM for Windows server-based MSI API documentation.

  2. Call connectClient(...).

    The following method shows what a generic connectClient(...) call might look like. You may have fixed values (for example, for appName, readWriteMode, and so on) and therefore no need for all the arguments used in this example.

    STDMETHODIMP CComMsiClient::connectClient(BSTR appName,
    										int readWriteMode,
    										IOvOWMsiServer **ppMsiServer,
    										int *interfaceId)
    {
      HRESULT hr;
      if (m_pMsiServer == NULL)
      {
    	m_pMsiServer.Release();
    	hr = this->retrieveMsiServer(&m_pMsiServer);
    	if (FAILED(hr))
    	{
    	return hr;
    }
      }
      hr = m_pMsiServer->connectClient(appName, this,
      readWriteMode, ppMsiServer, interfaceId);
      if (interfaceId != NULL)
      {
    	m_interfaceId = *interfaceId; // remember the interfaceId for the later call to disconnectClient(...)
      }
      return hr;
    }
    

    The interfaceId identifies the connection between your MSI Client and the HPOM for Windows MSI server. You should keep it if you want to call disconnectClient(...) later.

For the exact definition of the MSI client connection modes, refer to the HPOM for Windows COM API documentation.

Registering for Messages

To set up a register condition, you can use code such as the following.

CComPtr<IOvOWRegisterCondition> regCond;
hr = regCond.CoCreateInstance(CLSID_OvOWRegisterCondition);

The register condition does not have any specifics, so it will match all messages. To register for messages with critical severity only, set the severity property to OVEP_C_SEV_CRIT.

hr = regCond->put_MessageSeverity(OVEP_C_SEV_CRIT);

You can register the MSI client at the MSI server with the register condition you just prepared.

STDMETHODIMP CComMsiClient::registerClient(int interfaceId,
								 IOvOWRegisterCondition *condition,
								 int *conditionId)
{
  if (m_pMsiServer == NULL)
  {
	return E_FAIL;
  }
  HRESULT hr = m_pMsiServer->registerClient(interfaceId,
  condition, conditionId);
  m_lastMsiAppEvents.registerClientCallReturn = hr;
  return hr;
}

The returned conditionId identifies this specific registration call. You can use it later to unregister the specific register condition. However, you need to connect to the MSI server before you can register for messages.

Receiving and Processing Messages

After you connect to the MSI server and register your MSI client to receive messages, your client will receive messages sooner or later. For testing, you can use the opcmsg command-line tool to generate HPOM messages that match at least one of your registrations.

When your MSI client is eligible to receive a message, the MSI server calls the receiveMessage(...) method of your MSI client. The argument is the message.

You can now read the properties of the message and, as an example, store them in a file. If the message was diverted to your MSI client, you can also decide not to reinsert it into the MSI server. In that case, the message will not reach the HPOM for Windows Message Server Database, and it will not display in the HPOM for Windows Message Browser.

In the following code sample, an HPOM Message is received and reinserted into the MSI server without any processing.

STDMETHODIMP CComMsiClient::receiveMessage(IOvOWServerMessage *message)
{
  // you can do anything with the Message (for example, read the Message Text property)
  CComBSTR msgText;
  message->get_Text(&msgText);

  // now return the Message to the MSI Server
  if (m_pMsiServer == NULL)
  {
	return E_FAIL;
  }
  HRESULT hr = m_pMsiServer->insertMessage(m_interfaceId, message);
  if (FAILED(hr))
  {
	// maybe trace the hr; something went wrong
	return hr;
  }
  return S_OK;
}

Adding a New Message to the MSI Server

If the MSI Client has connected to the MSI Server with the appropriate MSI Client Connection Mode, you can also add new message to the HPOM for Windows message server.

The following code samples shows a method that creates a message with normal severity and the specified Message Text, and inserts it into the HPOM for Windows message server.

STDMETHODIMP CComMsiClient::feedNormalMessage(BSTR messageText)
{
  if (m_pMsiServer == NULL)
  {
	return E_FAIL;
  }
  if (messageText == NULL)
  {
	return E_INVALIDARG;
  }
  CComPtr pNewMessage;
  HRESULT hr = CoCreateInstance(CLSID_OvOWServerMessage, NULL, CLSCTX_ALL, IID_IOvOWServerMessage, reinterpret_cast<void **>(&pNewMessage));
  if (FAILED(hr))
  {
	// Check for hr; something went wrong
	return hr;
  }
  pNewMessage->put_Text(messageText);
  pNewMessage->put_Severity(OVEP_C_SEV_NORMAL);

return m_pMsiServer->insertMessage(m_interfaceId, pNewMessage);
}

Removing a Specific Registration

If you have stored the ID of the register condition you want to remove, and if m_pMsiServer is not NULL, you can remove the register condition by calling the following.

HRESULT hr = m_pMsiServer->unregisterClient(conditionId);

Removing All Registrations

You can remove all Registrations of your MSI client by calling the following.

HRESULT hr = m_pMsiServer->removeAllRegistrations(interfaceId);

In this example, the interface ID is used because it is easier than remembering all condition IDs.

Disconnecting from the MSI Server

You can disconnect an MSI client from the MSI server by calling the following.

HRESULT hr = m_pMsiServer->disconnectClient(interfaceId);

This call also causes the removal of all registrations made by this MSI client during the last connection. Expect the serverShutdown(...) method to be called instantly by the MSI server.

Calling serverInit() and serverShutdown()

For calls to serverInit() or serverShutdown(), do the following:

Configuring DCOM Security for Your MSI Client

Since HP Operations Manager for Windows 8.10, the Message/Action Server, which hosts the MSI server, runs under a non-admin user account. You must configure MSI COM clients for DCOM access to allow instantiation and communication between server and client.

To configure MSI COM clients for DCOM access, follow these steps:

  1. Start the DCOM Configuration utility dcomcnfg:
    1. In the text field, click StartRun.
    2. Type dcomcnfg.
    3. Press Enter.
  2. Open the following folders:
    • Component Services
    • Computers
    • DCOM Config
    • My Computer
  3. From the list of registered COM applications on your systems, look for your COM application.

    The application name is typically the prefix of your COM client Prog ID. For example, if your client ProgID is MyComApp.MyComClient, you most likely find the entry MyComApp in the list.

  4. On the list item that represents your COM application, right-click and select Properties.
  5. In the Launch and Activation Permissions section of the Security tab, select the Customize radio button.
  6. Click Edit.
  7. Add the user account under which the OvEpMsgActSrv.exe process is running to the list of users.

    By installation default, the user account is HP-OVE-User. If you chose a different user name during installation, add this user to the list instead. If in doubt, open the Task Manager from the Task Bar, and check the User Name entry for the process.

  8. For the newly-added user, select Local Launch (already selected) and Local Activation.

    Note that the Deny fields remain unselected.

  9. Click OK.
  10. Close the Properties Window by clicking OK again.

If you get further errors about insufficient access rights, add Access Permissions for HP-OVE-User (or the user name you chose) to your COM application.

Using Tracing in Your COM Application

It is up to you to chose any trace tool you prefer to instrument your COM MSI Application. The performance of the HPOM for Windows MSI Server will not be affected.

Tracing is generally useful to see what your application is doing and can be helpful to find bugs in early development phases.

To display trace messages of the MSI server, you need to use the built-in trace client of HPOM.

To enable trace messages, follow these steps:

  1. On the command line, execute <InstallDir>\support\ovtrcadm.exe -a localhost, where <InstallDir> is your HPOM Installation Directory.
  2. Execute <InstallDir>\support\ovtrcgui.exe.

    The Trace Client GUI appears.

  3. Cancel the wizard.
  4. Select FileNewTrace Configuration.
  5. Select localhost for the machine to configure.
  6. To create a new configuration, double-click <add application to trace>.
  7. From the list of available applications, select OvEpMsgActSrv.
  8. From the list of available traces, select those starting with OvOWMsi.
  9. Set the attribute mask to Max.
  10. Click OK.
  11. Select FileNewTrace Monitor.
  12. Select localhost for the machine to monitor.

    A list view appears.

New MSI Server traces are shown in the list view. Use EditOptions to configure which attributes should be displayed.

To close the Trace Client GUI, follow these steps:

  1. Do one of the following:
    • Select FileExit
    • Press ALT+F4.
  2. When asked if you want a quick close, select Yes.