Figure 1 WMI vs. Database
WMI Term |
Database Term |
Namespace |
Database |
Class |
Table |
Instance |
Row |
Property |
Column |
Key |
Primary Key |
Association |
Foreign Key |
Figure 4 MSJSampProvClasses.mof
//*************************************************************************
// 2000 Kevin Hughes and David Wohlferd
// File: MSJSampProvClasses.mof
//*************************************************************************
#pragma namespace("\\\\.\\Root")
[Locale(1033) : ToInstance]
Instance of __Namespace
{
Name = "MSJ";
};
#pragma namespace("\\\\.\\Root\\MSJ")
//*************************************************************
//*** Registers Framework Provider ***
//*************************************************************
instance of __Win32Provider as $P
{
Name = "MSJSampProv";
ClsId = "{e70b8934-aab3-11d3-9c2d-006008b088ce}";
};
instance of __InstanceProviderRegistration
{
Provider = $P;
SupportsGet = TRUE;
SupportsPut = TRUE;
SupportsDelete = TRUE;
SupportsEnumeration = TRUE;
QuerySupportLevels = {"WQL:UnarySelect"};
};
instance of __MethodProviderRegistration
{
Provider = $P;
};
//*************************************************************************
//* Class: MSJ_Account
//* Derived from:
//*************************************************************************
[Description("The MSJ_Account is an abstract base class for Win32 "
"accounts"): ToSubClass,
UUID("{5B1018A4-FC9E-45e9-9563-5319D2B91884}"): ToInstance]
class MSJ_Account
{
[key, write,
Description("The domain on which the account is defined"): ToSubClass,
read: ToSubClass] string Domain;
[key, write,
Description("The name of the account"): ToSubClass,
read: ToSubClass]
string Name;
};
//*************************************************************************
//* Class: MSJ_Group
//* Derived from: MSJ_Account
//*************************************************************************
[Description("The MSJ_Group class represents a group defined on a "
"particular domain"): ToSubClass,
dynamic: ToInstance ToSubClass,
provider("MSJSampProv"): ToInstance ToSubClass,
UUID("{93EE6BD7-DD60-4e09-BE29-9B5C3A809E25}"): ToInstance]
class MSJ_Group : MSJ_Account
{
[Description("The domain on which the group is defined"): ToSubClass]
string Domain;
[Description("The name of the group"): ToSubClass]
string Name;
[Description("The security identifier associated with this "
"account"): ToSubClass,
read: ToSubClass]
string SID;
};
//*************************************************************************
//* Class: MSJ_User
//* Derived from: MSJ_Account
//*************************************************************************
[Description("The MSJ_User class represents user accounts belonging to a "
"given domain"): ToSubClass,
dynamic: ToInstance ToSubClass,
provider("MSJSampProv"): ToInstance ToSubClass,
UUID("{6E5A57A0-6944-44f0-8140-0D70C2021439}"): ToInstance]
class MSJ_User : MSJ_Account
{
[Description("The name of the user account"): ToSubClass]
string Name;
[Description("The domain on which the user account is "
"defined"): ToSubClass]
string Domain;
[Description("The security identifier associated with the "
"account"): ToSubClass,
read: ToSubClass]
string SID;
[Description("Specifies the logon script path for this user "
"account"): ToSubClass,
read: ToSubClass,
write: ToSubClass]
string LogonScriptPath;
[Implemented, Description("The Rename method allows one to change the "
"name of a user account"): ToInstance ToSubClass]
uint32 Rename([IN] string NewName);
};
//*************************************************************************
//* Class: MSJ_GroupMembership
//* Derived from:
//*************************************************************************
[Aggregation: ToSubClass,
Association: DisableOverride ToInstance ToSubClass,
Description("The MSJ_GroupMembership class models which groups different "
"user accounts belong to"): ToSubClass,
dynamic: ToInstance ToSubClass,
provider("MSJSampProv"): ToInstance ToSubClass,
UUID("{774F3FE3-2531-41ca-A440-615E73D96949}"): ToInstance]
class MSJ_GroupMembership
{
[key,
Description("Refers to the group that the user account belongs "
"to"): ToSubClass,
read: ToSubClass]
MSJ_Group ref Group;
[key,
Description("Refers to the user that belongs to the group"):
ToSubClass,
read: ToInstance ToSubClass]
MSJ_User ref User;
};
//* EOF MSJSampProvClasses.mof
Figure 5 GetObject for Association Classes
HRESULT CMSJ_GroupMembership::GetObject ( CInstance* pInstance,
long lFlags,
CFrameworkQuery& Query)
{
HRESULT hr = WBEM_S_NO_ERROR;
CInstancePtr pGroupInst, pUserInst;
MethodContext *pMethodContext = pInstance->GetMethodContext();
// The User property contains an object path that points to a user. The
// Group property contains an object path that points to a Group.
// Let's do a GetObject on these two and make sure they point to
// valid users and groups.
hr = ValidateEndPoints(pMethodContext, pInstance, pUserInst, pGroupInst);
if (SUCCEEDED(hr))
{
// Ok, the group and the user both exist. Now, is this
// user a member of this group?
if (AreAssociated(pUserInst, pGroupInst))
{
hr = WBEM_S_NO_ERROR;
}
else
{
hr = WBEM_E_NOT_FOUND;
}
}
return hr;
}
Figure 6 Framework Callback Functions
Framework Instance Retrieval Function |
Description |
|
Used to synchronously retrieve all instances of the class specified by pszClassName in the namespace specified by pszNamespace. The resulting set of instances are stored in pList. |
|
Used to asynchronously retrieve all instances of the class specified by pszClassName, in the namespace specified by pszNamespace. Using this function allows the provider calling it to supply its own instances one at a time. |
|
This function is the same as GetAllInstancesAsynch,except that it retrieves all instances of a base class as well as instances of all of that class's children. |
|
Synchronous version of GetAllDerivedInstancesAsynch. |
|
Used to retrieve a single instance of a class by specifying the instance's object path. |
|
Same as GetInstanceByPath, but is used to only retrieve the key properties of the requested instance. |
|
Same as GetInstanceByPath, but with this function you can specify, via the csaProperties parameter, which properties you want populated. |
|
Retrieves instances based on a WQL query specified in the query parameter. The set of instances returned is stored in pList. |
|
Same as GetInstancesByQuery, but allows the calling provider to process instances of the query result set one at a time. |
Figure 7 Revised GetObject
HRESULT CMSJ_User::GetObject(CInstance* pInstance, long lFlags,
CFrameworkQuery& Query)
{
HRESULT hr = WBEM_E_NOT_FOUND;
DWORD dwRequestedProperties;
dwRequestedProperties = GetRequestedProps(Query);
CHString sLogonScriptPath;
hr = FindSingleInstance(pInstance, sLogonScriptPath,
dwRequestedProperties);
if (SUCCEEDED(hr))
{
hr = LoadPropertyValues(pInstance, sLogonScriptPath,
dwRequestedProperties);
}
return hr ;
}
Figure 8 Basic Implementation of Enumerate
HRESULT CMSJ_User::Enumerate(MethodContext* pMethodContext,
DWORD dwPropsRequired)
{
HRESULT hr = WBEM_S_NO_ERROR;
bool fDone = false;
PUSER_INFO_1 pInfo = NULL;
DWORD dwEntriesRead;
DWORD dwTotalEntries;
DWORD dwResumeHandle = 0;
NET_API_STATUS status = NERR_Success;
CHString sLogonScriptPath;
const CHString sComputerName = GetLocalComputerName();
// The only domain we consider for this sample is the local computer...
while(!fDone && SUCCEEDED(hr))
{
// Get a set of entries...
status = ::NetUserEnum(NULL, 1, FILTER_NORMAL_ACCOUNT,
(LPBYTE*) &pInfo, MAX_PREFERRED_LENGTH,
&dwEntriesRead, &dwTotalEntries,
&dwResumeHandle);
if (status == NERR_Success || status == ERROR_MORE_DATA)
{
for (long m = 0; m < dwEntriesRead && SUCCEEDED(hr); m++)
{
// Create a new instance based on the passed-in
// MethodContext.
CInstance pInstance = CreateNewInstance(pMethodContext);
if(pInstance)
{
// Set the key properties (if requested)
if (dwPropsRequired & PROP_DOMAIN)
{
pInstance->SetCHString(pDomain, sComputerName);
}
if (dwPropsRequired & PROP_NAME)
{
pInstance->SetWCHARSplat(pName, pInfo[m].usri1_name);
}
// Obtain all other properties as necessary...
if (dwPropsRequired & PROP_LOGSCRIPTPATH)
{
if (pInfo->usri1_script_path != NULL)
{
sLogonScriptPath = pInfo->usri1_script_path;
}
}
// Set all the other properties...
hr = LoadPropertyValues(pInstance, sLogonScriptPath,
dwPropsRequired);
if (SUCCEEDED(hr))
{
hr = pInstance->Commit();
}
pInstance->Release();
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
}
if (pInfo != NULL)
{
::NetApiBufferFree(pInfo);
pInfo = NULL;
}
// Processed the last entry
if (status == NERR_Success)
{
fDone = true;
}
}
else
{
fDone = true;
}
}
return hr;
}
Figure 9 Advanced Implementation of Enumerate
HRESULT CMSJ_User::Enumerate(MethodContext* pMethodContext,
DWORD dwPropsRequired)
{
HRESULT hr = WBEM_S_NO_ERROR;
bool fDone = false;
PUSER_INFO_1 pInfo = NULL;
DWORD dwEntriesRead;
DWORD dwTotalEntries;
DWORD dwResumeHandle = 0;
NET_API_STATUS status = NERR_Success;
CHString sLogonScriptPath;
const CHString sComputerName = GetLocalComputerName();
// The only domain we consider for this sample is the local computer...
while(!fDone && SUCCEEDED(hr))
{
// Get a set of entries...
status = ::NetUserEnum(NULL, 1, FILTER_NORMAL_ACCOUNT,
(LPBYTE*) &pInfo, MAX_PREFERRED_LENGTH,
&dwEntriesRead, &dwTotalEntries,
&dwResumeHandle);
if (status == NERR_Success || status == ERROR_MORE_DATA)
{
// We need this 'try' because several of the functions
// in this section could throw. If they do, we need
// to release pInfo, or else it would leak.
try
{
// Process each entry in the set...
for (long m = 0; m < dwEntriesRead && SUCCEEDED(hr); m++)
{
// Create a new instance based on the passed-in
// MethodContext. Note that CreateNewInstance
// may throw, but will never return NULL.
CInstancePtr pInstance(CreateNewInstance(pMethodContext),
false);
// Set the key properties (if requested)
if (dwPropsRequired & PROP_DOMAIN)
{
pInstance->SetCHString(pDomain, sComputerName);
}
if (dwPropsRequired & PROP_NAME)
{
pInstance->SetWCHARSplat(pName, pInfo[m].usri1_name);
}
// Obtain all other properties as necessary...
if (dwPropsRequired & PROP_LOGSCRIPTPATH)
{
if (pInfo->usri1_script_path != NULL)
{
sLogonScriptPath = pInfo->usri1_script_path;
}
}
// Set all the other properties...
hr = LoadPropertyValues(pInstance, sLogonScriptPath,
dwPropsRequired);
if (SUCCEEDED(hr))
{
hr = pInstance->Commit();
}
}
}
catch(...)
{
if (pInfo != NULL)
{
::NetApiBufferFree(pInfo);
pInfo = NULL;
}
throw;
}
if (pInfo != NULL)
{
::NetApiBufferFree(pInfo);
pInfo = NULL;
}
// Processed the last entry
if (status == NERR_Success)
{
fDone = true;
}
}
else
{
fDone = true;
}
}
return hr;
}