Share via


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
  
HRESULT WINAPI GetAllInstances(
  LPCWSTR pszClassName, 
  TRefPointerCollection<CInstance> *pList,
  LPCWSTR pszNamespace,
  MethodContext *pMethodContext)

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.
  
HRESULT WINAPI GetAllInstancesAsynch( 
  LPCWSTR pszClassName,
  Provider *pRequester,
  LPProviderInstanceCallback pCallback,
  LPCWSTR pszNamespace,
  MethodContext *pMethodContext, void *pUserData )

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.
  
HRESULT WINAPI GetAllDerivedInstancesAsynch( 
  LPCWSTR pszBaseClassName,
  Provider *pRequester,
  LPProviderInstanceCallback pCallback,
  LPCWSTR pszNamespace,
  MethodContext *pMethodContext, void *pUserData )

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.
  
HRESULT WINAPI GetAllDerivedInstances( 
  LPCWSTR pszBaseClassName,
  TRefPointerCollection<CInstance> *pList,
  MethodContext *pMethodContext,
  LPCWSTR pszNamespace = NULL)

Synchronous version of GetAllDerivedInstancesAsynch.
  
static HRESULT WINAPI GetInstanceByPath(
  LPCWSTR pszObjectPath, 
  CInstance **ppInstance, 
  MethodContext *pMethodContext = NULL )

Used to retrieve a single instance of a class by specifying the instance's object path.
  
static HRESULT WINAPI GetInstanceKeysByPath( 
  LPCWSTR pszInstancePath,
  CInstance **ppInstance,
  MethodContext *pMethodContext)

Same as GetInstanceByPath, but is used to only retrieve the key properties of the requested instance.
  
static HRESULT WINAPI GetInstancePropertiesByPath(
  LPCWSTR pszInstancePath, CInstance **ppInstance,
  MethodContext *pMethodContext,
  CHStringArray &csaProperties)

Same as GetInstanceByPath, but with this function you can specify, via the csaProperties parameter, which properties you want populated.
  
static HRESULT WINAPI GetInstancesByQuery( 
  LPCWSTR query,
  TRefPointerCollection<CInstance> *pList, 
  MethodContext *pMethodContext,  
  LPCWSTR pszNamespace = NULL)

Retrieves instances based on a WQL query specified in the query parameter. The set of instances returned is stored in pList.
  
static HRESULT WINAPI GetInstancesByQueryAsynch( 
  LPCWSTR query, 
  Provider *pRequester, 
  LPProviderInstanceCallback pCallback, 
  LPCWSTR pszNamespace, 
  MethodContext *pMethodContext, 
  void *pUserData )

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;
}