As described in Implementing MI Provider (3), Convert-MofToProvider.exe tool generates a set of code files, including schema.c, module.c, WMIAdapter.c, Provider.DEF, <class name>.h, and <class name>.c. There is one header file for each target class and all of it's ancestor class(es) if have. And one c file for each target class (specified by -ClassList parameter). Header files also get genrated for classes specified by -ExtraClass parameter.

 

<Class name>.h file(s)

Those header files are named with pattern like <class name>.h, which defines the type of <class name> class and a set of helper functions to manipulate the instance of that type. Take MSFT_WindowsProcess.h for example, first of all, it defines the structure of MSFT_WindowsProcess, represents the run-time type of windows process instance defined by MSFT_WindowsProcess schema.

typedef struct _MSFT_WindowsProcess /* extends CIM_Process */
{
MI_Instance __instance;
/* CIM_ManagedElement properties */
MI_ConstStringField InstanceID;
MI_ConstStringField Caption;
MI_ConstStringField Description;
MI_ConstStringField ElementName;
/* CIM_ManagedSystemElement properties */
MI_ConstDatetimeField InstallDate;
MI_ConstStringField Name;
MI_ConstUint16AField OperationalStatus;
MI_ConstStringAField StatusDescriptions;
MI_ConstStringField Status;
MI_ConstUint16Field HealthState;
MI_ConstUint16Field CommunicationStatus;
MI_ConstUint16Field DetailedStatus;
MI_ConstUint16Field OperatingStatus;
MI_ConstUint16Field PrimaryStatus;
/* CIM_LogicalElement properties */
/* CIM_EnabledLogicalElement properties */
MI_ConstUint16Field EnabledState;
MI_ConstStringField OtherEnabledState;
MI_ConstUint16Field RequestedState;
MI_ConstUint16Field EnabledDefault;
MI_ConstDatetimeField TimeOfLastStateChange;
MI_ConstUint16AField AvailableRequestedStates;
MI_ConstUint16Field TransitioningToState;
/* CIM_Process properties */
/*KEY*/ MI_ConstStringField CSCreationClassName;
/*KEY*/ MI_ConstStringField CSName;
/*KEY*/ MI_ConstStringField OSCreationClassName;
/*KEY*/ MI_ConstStringField OSName;
/*KEY*/ MI_ConstStringField CreationClassName;
/*KEY*/ MI_ConstStringField Handle;
MI_ConstUint32Field Priority;
MI_ConstUint16Field ExecutionState;
MI_ConstStringField OtherExecutionDescription;
MI_ConstDatetimeField CreationDate;
MI_ConstDatetimeField TerminationDate;
MI_ConstUint64Field KernelModeTime;
MI_ConstUint64Field UserModeTime;
MI_ConstUint64Field WorkingSetSize;
/* MSFT_WindowsProcess properties */
MI_ConstStringField CommandLine;
}
MSFT_WindowsProcess;

Then, the header file defines a set of functions to manipulate the instance of MSFT_WindowsProcess, following helper funtions set and clear CommandLine property value of the instance.

MI_INLINE MI_Result MI_CALL MSFT_WindowsProcess_Set_CommandLine(
_Inout_ MSFT_WindowsProcess* self,
_In_z_ const MI_Char* str)
{
return self->__instance.ft->SetElementAt(
(MI_Instance*)&self->__instance,
35,
(MI_Value*)&str,
MI_STRING,
0);
}

MI_INLINE MI_Result MI_CALL MSFT_WindowsProcess_SetPtr_CommandLine(
_Inout_ MSFT_WindowsProcess* self,
_In_z_ const MI_Char* str)
{
return self->__instance.ft->SetElementAt(
(MI_Instance*)&self->__instance,
35,
(MI_Value*)&str,
MI_STRING,
MI_FLAG_BORROW);
}

MI_INLINE MI_Result MI_CALL MSFT_WindowsProcess_Clear_CommandLine(
_Inout_ MSFT_WindowsProcess* self)
{
return self->__instance.ft->ClearElementAt(
(MI_Instance*)&self->__instance,
35);
}

 

<Class name>.c file(s)

Based on the type of target class, Convert-MofToProvider.exe generates different stub functions in c file. As mentioned, there are three type of classes, normal class, association class, and indication class.

For MSFT_WindowsProcess class, following are the generated stub functions,

#include <MI.h>
#include "MSFT_WindowsProcess.h"

void MI_CALL MSFT_WindowsProcess_Load(
_Outptr_result_maybenull_ MSFT_WindowsProcess_Self** self,
_In_opt_ MI_Module_Self* selfModule,
_In_ MI_Context* context)
{
MI_UNREFERENCED_PARAMETER(selfModule);

*self = NULL;
MI_Context_PostResult(context, MI_RESULT_OK);
}

void MI_CALL MSFT_WindowsProcess_Unload(
_In_opt_ MSFT_WindowsProcess_Self* self,
_In_ MI_Context* context)
{
MI_UNREFERENCED_PARAMETER(self);

MI_Context_PostResult(context, MI_RESULT_OK);
}

void MI_CALL MSFT_WindowsProcess_EnumerateInstances(
_In_opt_ MSFT_WindowsProcess_Self* self,
_In_ MI_Context* context,
_In_opt_z_ const MI_Char* nameSpace,
_In_opt_z_ const MI_Char* className,
_In_opt_ const MI_PropertySet* propertySet,
_In_ MI_Boolean keysOnly,
_In_opt_ const MI_Filter* filter)
{
MI_Result result = MI_RESULT_OK;

MI_UNREFERENCED_PARAMETER(self);
MI_UNREFERENCED_PARAMETER(nameSpace);
MI_UNREFERENCED_PARAMETER(className);
MI_UNREFERENCED_PARAMETER(propertySet);
MI_UNREFERENCED_PARAMETER(filter);

MI_Context_PostResult(context, MI_RESULT_NOT_SUPPORTED);
}

void MI_CALL MSFT_WindowsProcess_GetInstance(
_In_opt_ MSFT_WindowsProcess_Self* self,
_In_ MI_Context* context,
_In_opt_z_ const MI_Char* nameSpace,
_In_opt_z_ const MI_Char* className,
_In_ const MSFT_WindowsProcess* instanceName,
_In_opt_ const MI_PropertySet* propertySet)
{
MI_UNREFERENCED_PARAMETER(self);
MI_UNREFERENCED_PARAMETER(nameSpace);
MI_UNREFERENCED_PARAMETER(className);
MI_UNREFERENCED_PARAMETER(instanceName);
MI_UNREFERENCED_PARAMETER(propertySet);

MI_Context_PostResult(context, MI_RESULT_NOT_SUPPORTED);
}

void MI_CALL MSFT_WindowsProcess_CreateInstance(
_In_opt_ MSFT_WindowsProcess_Self* self,
_In_ MI_Context* context,
_In_opt_z_ const MI_Char* nameSpace,
_In_opt_z_ const MI_Char* className,
_In_ const MSFT_WindowsProcess* newInstance)
{
MI_UNREFERENCED_PARAMETER(self);
MI_UNREFERENCED_PARAMETER(nameSpace);
MI_UNREFERENCED_PARAMETER(className);
MI_UNREFERENCED_PARAMETER(newInstance);

MI_Context_PostResult(context, MI_RESULT_NOT_SUPPORTED);
}

void MI_CALL MSFT_WindowsProcess_ModifyInstance(
_In_opt_ MSFT_WindowsProcess_Self* self,
_In_ MI_Context* context,
_In_opt_z_ const MI_Char* nameSpace,
_In_opt_z_ const MI_Char* className,
_In_ const MSFT_WindowsProcess* modifiedInstance,
_In_opt_ const MI_PropertySet* propertySet)
{
MI_UNREFERENCED_PARAMETER(self);
MI_UNREFERENCED_PARAMETER(nameSpace);
MI_UNREFERENCED_PARAMETER(className);
MI_UNREFERENCED_PARAMETER(propertySet);

MI_Context_PostResult(context, MI_RESULT_NOT_SUPPORTED);
}

void MI_CALL MSFT_WindowsProcess_DeleteInstance(
_In_opt_ MSFT_WindowsProcess_Self* self,
_In_ MI_Context* context,
_In_opt_z_ const MI_Char* nameSpace,
_In_opt_z_ const MI_Char* className,
_In_ const MSFT_WindowsProcess* instanceName)
{
MI_UNREFERENCED_PARAMETER(self);
MI_UNREFERENCED_PARAMETER(nameSpace);
MI_UNREFERENCED_PARAMETER(className);

MI_Context_PostResult(context, MI_RESULT_NOT_SUPPORTED);
}

void MI_CALL MSFT_WindowsProcess_Invoke_RequestStateChange(
_In_opt_ MSFT_WindowsProcess_Self* self,
_In_ MI_Context* context,
_In_opt_z_ const MI_Char* nameSpace,
_In_opt_z_ const MI_Char* className,
_In_opt_z_ const MI_Char* methodName,
_In_ const MSFT_WindowsProcess* instanceName,
_In_opt_ const MSFT_WindowsProcess_RequestStateChange* in)
{
MI_UNREFERENCED_PARAMETER(self);
MI_UNREFERENCED_PARAMETER(nameSpace);
MI_UNREFERENCED_PARAMETER(className);
MI_UNREFERENCED_PARAMETER(methodName);
MI_UNREFERENCED_PARAMETER(instanceName);
MI_UNREFERENCED_PARAMETER(in);

MI_Context_PostResult(context, MI_RESULT_NOT_SUPPORTED);
}

void MI_CALL MSFT_WindowsProcess_Invoke_SetPriority(
_In_opt_ MSFT_WindowsProcess_Self* self,
_In_ MI_Context* context,
_In_opt_z_ const MI_Char* nameSpace,
_In_opt_z_ const MI_Char* className,
_In_opt_z_ const MI_Char* methodName,
_In_ const MSFT_WindowsProcess* instanceName,
_In_opt_ const MSFT_WindowsProcess_SetPriority* in)
{
MI_UNREFERENCED_PARAMETER(self);
MI_UNREFERENCED_PARAMETER(nameSpace);
MI_UNREFERENCED_PARAMETER(className);
MI_UNREFERENCED_PARAMETER(methodName);

MI_Context_PostResult(context, MI_RESULT_NOT_SUPPORTED);
}

void MI_CALL MSFT_WindowsProcess_Invoke_Create(
_In_opt_ MSFT_WindowsProcess_Self* self,
_In_ MI_Context* context,
_In_opt_z_ const MI_Char* nameSpace,
_In_opt_z_ const MI_Char* className,
_In_opt_z_ const MI_Char* methodName,
_In_ const MSFT_WindowsProcess* instanceName,
_In_opt_ const MSFT_WindowsProcess_Create* in)
{
MI_UNREFERENCED_PARAMETER(self);
MI_UNREFERENCED_PARAMETER(nameSpace);
MI_UNREFERENCED_PARAMETER(className);
MI_UNREFERENCED_PARAMETER(methodName);
MI_UNREFERENCED_PARAMETER(instanceName);
MI_UNREFERENCED_PARAMETER(in);

MI_Context_PostResult(context, MI_RESULT_NOT_SUPPORTED);
}

There are two categories of the generated methods insides one c file, intrinsic methods and extrinsic methods. Intrinsic methods are standard operations while extrinsic methods are methods defined within the class's schema (mof file).

Intrinsic Methods

Extrinsic methods

MSFT_WindowsProcess_EnumerateInstances

MSFT_WindowsProcess_Invoke_SetPriority

MSFT_WindowsProcess_GetInstance

MSFT_WindowsProcess_Invoke_RequestStateChange

MSFT_WindowsProcess_ModifyInstance

MSFT_WindowsProcess_Invoke_Create

MSFT_WindowsProcess_CreateInstance

 

MSFT_WindowsProcess_DeleteInstance

 

For each extrinsic method definition, there is also a type generated in the corresponding header file, for example, structure MSFT_WindowsProcess_Create was defined for Create method of MSFT_WindowsProcess class in MSFT_WindowsProcess.h file. Through this type, provider may access values of input parameters from client (who invoke the method) and output values of parameters to client.

For each class, there are two functions always generated within <class name>.c file, called load/unload functions. <class name>_Load function is invoked by CIMOM server to initialize the class before invoking any method, the class may initialize any resources which could live across class loading time and are used to during operations of the class. <class name>_Unload function is invoked by server to finalize the class, the class should finalize all resources initialized within load function.

 

Module.c 

Module.c file defines and implements entry function (MI_Main) of the MI provider. As shown below, there are three functions defined, Load, Unload, MI_Main.

Load function is used to initialize the provider wide resources, live during provider's life cycle. For example, inside Load function, a provider may initialize a critical section, which was used to protect shared data structures accessed by multiple threads simultaneously.

Unload function is used to finalize the provider resources. For example, the provider could delete the critical section inside Unload function.

MI_Main function exchanges information between the provider and its host. Usually provider manager calls MI_Main function of a MI provider to get the MI_Module information of a provider, which contains the flags, charsize, version, generator version, all supported schema, and load unload function pointer. Meanwhile, provider manager tells the provider server information by input parameter MI_Server. Provider could call MI_Server_GetVersion and MI_Server_GetSystemName to read current CIMOM server version and system name.

 #include <MI.h>

MI_EXTERN_C MI_SchemaDecl schemaDecl;

void MI_CALL Load(_Outptr_result_maybenull_ MI_Module_Self** self, _In_ struct _MI_Context* context)
{
*self = NULL;
MI_Context_PostResult(context, MI_RESULT_OK);
}

void MI_CALL Unload(_In_opt_ MI_Module_Self* self, _In_ struct _MI_Context* context)
{
MI_UNREFERENCED_PARAMETER(self);
MI_UNREFERENCED_PARAMETER(context);

MI_Context_PostResult(context, MI_RESULT_OK);
}

MI_EXTERN_C MI_EXPORT MI_Module* MI_MAIN_CALL MI_Main(_In_ MI_Server* server)
{
/* WARNING: THIS FUNCTION AUTOMATICALLY GENERATED. PLEASE DO NOT EDIT. */
static MI_Module module;
MI_EXTERN_C MI_Server* __mi_server;
__mi_server = server;
module.flags |= MI_MODULE_FLAG_DESCRIPTIONS;
module.flags |= MI_MODULE_FLAG_VALUES;
module.flags |= MI_MODULE_FLAG_BOOLEANS;
module.charSize = sizeof(MI_Char);
module.version = MI_VERSION;
module.generatorVersion = MI_MAKE_VERSION(1,0,0);
module.schemaDecl = &schemaDecl;
module.Load = Load;
module.Unload = Unload;
return &module;
}

 

 

Schema.c

schema.c file contains the schema of all related classes, and the schema of each class is represented by a set of embedded structures. Schema.c file defines two MI server functions as well. Schema file could be viewed as a binary format of the schema (mof) file. This file must *NOT* be modified, otherwise could break provider’s functionality. To change the schema, modify the original MOF (in this case sample.mof) and re-generate the code.

To explain the structure of the schema file, a set of snippets are copied below.

(1) schemaDecl is of type MI_SchemaDecl, which defines the schema structure of the provider, which contains all qualifiers declarations and all classes declarations.

 MI_SchemaDecl schemaDecl =
{
qualifierDecls, /* qualifierDecls */
MI_COUNT(qualifierDecls), /* numQualifierDecls */
classes, /* classDecls */
MI_COUNT(classes), /* classDecls */
};

(2) classes property is an array of MI_ClassDecl objects, which contains a list of all classes schema, which was named with <class name>_rtti. For example, MSFT_WindowsProcess_rtti is the schema of MSFT_WindowsProcess class.

 static MI_ClassDecl MI_CONST* MI_CONST classes[] =
{
&CIM_ConcreteJob_rtti,
&CIM_EnabledLogicalElement_rtti,
&CIM_Error_rtti,
&CIM_Job_rtti,
&CIM_LogicalElement_rtti,
&CIM_ManagedElement_rtti,
&CIM_ManagedSystemElement_rtti,
&CIM_Process_rtti,
&CIM_Service_rtti,
&CIM_ServiceProcess_rtti,
&MSFT_WindowsProcess_rtti,
&MSFT_WindowsServiceProcess_rtti,
};

(3) MSFT_WindowsProcess_rtti defines as following, which contains a set of qualifiers, a set of properties, a set of methods, a set of generated stub functions, and other information of the class.

 /* class MSFT_WindowsProcess */
MI_CONST MI_ClassDecl MSFT_WindowsProcess_rtti =
{
MI_FLAG_CLASS, /* flags */
0x006D7313, /* code */
MI_T("MSFT_WindowsProcess"), /* name */
MSFT_WindowsProcess_quals, /* qualifiers */
MI_COUNT(MSFT_WindowsProcess_quals), /* numQualifiers */
MSFT_WindowsProcess_props, /* properties */
MI_COUNT(MSFT_WindowsProcess_props), /* numProperties */
sizeof(MSFT_WindowsProcess), /* size */
MI_T("CIM_Process"), /* superClass */
&CIM_Process_rtti, /* superClassDecl */
MSFT_WindowsProcess_meths, /* methods */
MI_COUNT(MSFT_WindowsProcess_meths), /* numMethods */
&schemaDecl, /* schema */
&MSFT_WindowsProcess_funcs, /* functions */
NULL /* owningClass */
};

(4) MSFT_WindowsProcess_quals is an array of class qualifiers, and MSFT_WindowsProcess_ClassVersion_qual defines one of the qualifier as below.

 static MI_CONST MI_Char* MSFT_WindowsProcess_ClassVersion_qual_value = MI_T("1.0.0");

static MI_CONST MI_Qualifier MSFT_WindowsProcess_ClassVersion_qual =
{
MI_T("ClassVersion"),
MI_STRING,
MI_FLAG_ENABLEOVERRIDE|MI_FLAG_RESTRICTED,
&MSFT_WindowsProcess_ClassVersion_qual_value
};

static MI_Qualifier MI_CONST* MI_CONST MSFT_WindowsProcess_quals[] =
{
&MSFT_WindowsProcess_UMLPackagePath_qual,
&MSFT_WindowsProcess_Description_qual,
&MSFT_WindowsProcess_ClassVersion_qual,
};

(5) MSFT_WindowsProcess_props defines the array of all its properties, including the properties inherited from ancestor classes. One example of the property is MSFT_WindowsProcess_CommandLine_prop.

 static MI_PropertyDecl MI_CONST* MI_CONST MSFT_WindowsProcess_props[] =
{
&CIM_ManagedElement_InstanceID_prop,
&CIM_ManagedElement_Caption_prop,
&CIM_ManagedElement_Description_prop,
&CIM_ManagedElement_ElementName_prop,
&CIM_ManagedSystemElement_InstallDate_prop,
&CIM_Process_Name_prop,
&CIM_ManagedSystemElement_OperationalStatus_prop,
&CIM_ManagedSystemElement_StatusDescriptions_prop,
&CIM_ManagedSystemElement_Status_prop,
&CIM_ManagedSystemElement_HealthState_prop,
&CIM_ManagedSystemElement_CommunicationStatus_prop,
&CIM_ManagedSystemElement_DetailedStatus_prop,
&CIM_ManagedSystemElement_OperatingStatus_prop,
&CIM_ManagedSystemElement_PrimaryStatus_prop,
&CIM_EnabledLogicalElement_EnabledState_prop,
&CIM_EnabledLogicalElement_OtherEnabledState_prop,
&CIM_EnabledLogicalElement_RequestedState_prop,
&CIM_EnabledLogicalElement_EnabledDefault_prop,
&CIM_EnabledLogicalElement_TimeOfLastStateChange_prop,
&CIM_EnabledLogicalElement_AvailableRequestedStates_prop,
&CIM_EnabledLogicalElement_TransitioningToState_prop,
&CIM_Process_CSCreationClassName_prop,
&CIM_Process_CSName_prop,
&CIM_Process_OSCreationClassName_prop,
&CIM_Process_OSName_prop,
&CIM_Process_CreationClassName_prop,
&CIM_Process_Handle_prop,
&CIM_Process_Priority_prop,
&CIM_Process_ExecutionState_prop,
&CIM_Process_OtherExecutionDescription_prop,
&CIM_Process_CreationDate_prop,
&CIM_Process_TerminationDate_prop,
&CIM_Process_KernelModeTime_prop,
&CIM_Process_UserModeTime_prop,
&CIM_Process_WorkingSetSize_prop,
&MSFT_WindowsProcess_CommandLine_prop,
};
……
/* property MSFT_WindowsProcess.CommandLine */
static MI_CONST MI_PropertyDecl MSFT_WindowsProcess_CommandLine_prop =
{
MI_FLAG_PROPERTY|MI_FLAG_READONLY, /* flags */
0x0063650B, /* code */
MI_T("CommandLine"), /* name */
NULL, /* qualifiers */
0, /* numQualifiers */
MI_STRING, /* type */
NULL, /* className */
0, /* subscript */
offsetof(MSFT_WindowsProcess, CommandLine), /* offset */
MI_T("MSFT_WindowsProcess"), /* origin */
MI_T("MSFT_WindowsProcess"), /* propagator */
NULL,
};

(6) MSFT_WindowsProcess_meths defines an array of the schema of all extrinsic methods, while MSFT_WindowsProcess_funcs defines an array of function pointers, which are intrinsic methods.

Due to an extrinsic method might contain a set of input and output parameters, and a set off qualifiers for the method itself as well as all parameters, such that it requires a MI_MethodDecl structure to store all related information. Intrinsic methods do not have qualifiers and it has a fix set of parameters, such that is represented by a function pointer.

/* method MSFT_WindowsProcess.Create() */
MI_CONST MI_MethodDecl MSFT_WindowsProcess_Create_rtti =
{
MI_FLAG_METHOD|MI_FLAG_STATIC, /* flags */
0x00636506, /* code */
MI_T("Create"), /* name */
MSFT_WindowsProcess_Create_quals, /* qualifiers */
MI_COUNT(MSFT_WindowsProcess_Create_quals), /* numQualifiers */
MSFT_WindowsProcess_Create_params, /* parameters */
MI_COUNT(MSFT_WindowsProcess_Create_params), /* numParameters */
sizeof(MSFT_WindowsProcess_Create), /* size */
MI_UINT32, /* returnType */
MI_T("MSFT_WindowsProcess"), /* origin */
MI_T("MSFT_WindowsProcess"), /* propagator */
&schemaDecl, /* schema */
(MI_ProviderFT_Invoke)MSFT_WindowsProcess_Invoke_Create, /* method */
};

static MI_MethodDecl MI_CONST* MI_CONST MSFT_WindowsProcess_meths[] =
{
&MSFT_WindowsProcess_RequestStateChange_rtti,
&MSFT_WindowsProcess_SetPriority_rtti,
&MSFT_WindowsProcess_Create_rtti,
};
……

static MI_CONST MI_ProviderFT MSFT_WindowsProcess_funcs =
{
(MI_ProviderFT_Load)MSFT_WindowsProcess_Load,
(MI_ProviderFT_Unload)MSFT_WindowsProcess_Unload,
(MI_ProviderFT_GetInstance)MSFT_WindowsProcess_GetInstance,
(MI_ProviderFT_EnumerateInstances)MSFT_WindowsProcess_EnumerateInstances,
(MI_ProviderFT_CreateInstance)MSFT_WindowsProcess_CreateInstance,
(MI_ProviderFT_ModifyInstance)MSFT_WindowsProcess_ModifyInstance,
(MI_ProviderFT_DeleteInstance)MSFT_WindowsProcess_DeleteInstance,
(MI_ProviderFT_AssociatorInstances)NULL,
(MI_ProviderFT_ReferenceInstances)NULL,
(MI_ProviderFT_EnableIndications)NULL,
(MI_ProviderFT_DisableIndications)NULL,
(MI_ProviderFT_Subscribe)NULL,
(MI_ProviderFT_Unsubscribe)NULL,
(MI_ProviderFT_Invoke)NULL,
};

typedef void (MI_CALL *MI_ProviderFT_EnumerateInstances)(
_In_opt_ void* self,
_In_ MI_Context* context,
_In_z_ const MI_Char* nameSpace,
_In_z_ const MI_Char* className,
_In_opt_ const MI_PropertySet* propertySet,
MI_Boolean keysOnly,
_In_opt_ const MI_Filter* filter);

 

WMIAdapter.c

In order to host MI provider(s) within WMI, an adapter layer is necessary since WMI host process only supports COM based provider interface. WMIAdapter.c is a file to enable the MI provider running with WMI service. This file must *NOT* be modified.

 

Provider.DEF

Provider.DEF defines list of exported APIs from the provider DLL. Usually, this file name was specified in visual studio project linker options ‘/DEF:"Provider.DEF"’ (see following picture), in order to tell the linker to export a set of functions from target DLL.


 

Happy holidays! Next blog will discuss how to implement instance (normal) class.

 

Haowei Qin

Senior SDE

Standards Based Management