513 lines
15 KiB
C++
513 lines
15 KiB
C++
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1992 - 2000.
|
||
|
//
|
||
|
// File: umi.cxx
|
||
|
//
|
||
|
// Contents: Contains miscellaneous UMI routines.
|
||
|
//
|
||
|
// History: 02-28-00 SivaramR Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include "winnt.hxx"
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Function: IsPreDefinedErrorCode
|
||
|
//
|
||
|
// Synopsis: Returns TRUE if the error code passed in is a valid UMI error
|
||
|
// code i.e one that can be returned by a UMI method. Returns
|
||
|
// FALSE otherwise.
|
||
|
//
|
||
|
// Arguments: Self explanatory
|
||
|
//
|
||
|
// Returns: TRUE/FALSE as mentioned above
|
||
|
//
|
||
|
// Modifies: Nothing
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
BOOL IsPreDefinedErrorCode(HRESULT hr)
|
||
|
{
|
||
|
switch(hr) {
|
||
|
case E_UNEXPECTED:
|
||
|
case E_NOTIMPL:
|
||
|
case E_OUTOFMEMORY:
|
||
|
case E_INVALIDARG:
|
||
|
case E_NOINTERFACE:
|
||
|
case E_POINTER:
|
||
|
case E_HANDLE:
|
||
|
case E_ABORT:
|
||
|
case E_FAIL:
|
||
|
case E_ACCESSDENIED:
|
||
|
case E_PENDING:
|
||
|
case UMI_E_TYPE_MISMATCH:
|
||
|
case UMI_E_NOT_FOUND:
|
||
|
case UMI_E_INVALID_FLAGS:
|
||
|
case UMI_E_UNSUPPORTED_OPERATION:
|
||
|
case UMI_E_UNSUPPORTED_FLAGS:
|
||
|
case UMI_E_SYNCHRONIZATION_REQUIRED:
|
||
|
case UMI_E_UNBOUND_OBJECT:
|
||
|
|
||
|
RRETURN(TRUE);
|
||
|
|
||
|
default:
|
||
|
|
||
|
RRETURN(FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Function: MapHrToUmiError
|
||
|
//
|
||
|
// Synopsis: This function returns the UMI error corresponding to a HRESULT
|
||
|
// returned by the WinNT provider. The HRESULT can be retrieved
|
||
|
// using GetLastStatus(), if required.
|
||
|
//
|
||
|
// Arguments: Self explanatory
|
||
|
//
|
||
|
// Returns: UMI error corresponding to the HRESULT
|
||
|
//
|
||
|
// Modifies: Nothing
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
HRESULT MapHrToUmiError(HRESULT hr)
|
||
|
{
|
||
|
if(SUCCEEDED(hr)) {
|
||
|
if(S_FALSE == hr) // may be returned by end of cursor enumeration
|
||
|
RRETURN(UMI_S_FALSE);
|
||
|
else
|
||
|
RRETURN(UMI_S_NO_ERROR);
|
||
|
}
|
||
|
|
||
|
// we had a failure
|
||
|
if(TRUE == IsPreDefinedErrorCode(hr))
|
||
|
RRETURN(hr); // OK to return this as a UMI error
|
||
|
|
||
|
// Try to map ADSI errors to appropriate UMI errors. Default is to
|
||
|
// map to E_FAIL.
|
||
|
switch(hr) {
|
||
|
case E_ADS_INVALID_DOMAIN_OBJECT:
|
||
|
case E_ADS_INVALID_USER_OBJECT:
|
||
|
case E_ADS_INVALID_COMPUTER_OBJECT:
|
||
|
case E_ADS_UNKNOWN_OBJECT:
|
||
|
|
||
|
RRETURN(UMI_E_OBJECT_NOT_FOUND);
|
||
|
|
||
|
case E_ADS_PROPERTY_NOT_FOUND:
|
||
|
RRETURN(UMI_E_PROPERTY_NOT_FOUND);
|
||
|
|
||
|
case E_ADS_BAD_PARAMETER:
|
||
|
RRETURN(UMI_E_INVALIDARG);
|
||
|
|
||
|
case E_ADS_CANT_CONVERT_DATATYPE:
|
||
|
RRETURN(UMI_E_TYPE_MISMATCH);
|
||
|
|
||
|
case E_ADS_BAD_PATHNAME:
|
||
|
RRETURN(UMI_E_INVALIDARG);
|
||
|
|
||
|
case E_ADS_OBJECT_UNBOUND:
|
||
|
RRETURN(UMI_E_UNBOUND_OBJECT);
|
||
|
|
||
|
case HRESULT_FROM_WIN32(NERR_UserNotFound):
|
||
|
case HRESULT_FROM_WIN32(NERR_GroupNotFound):
|
||
|
case HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN):
|
||
|
case HRESULT_FROM_WIN32(ERROR_BAD_NETPATH):
|
||
|
|
||
|
RRETURN(UMI_E_OBJECT_NOT_FOUND);
|
||
|
|
||
|
default:
|
||
|
RRETURN(UMI_E_FAIL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Function: ValidateUrl
|
||
|
//
|
||
|
// Synopsis: This function checks to see if a UMI path has the correct
|
||
|
// namespace and server.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// pURL Pointer to URL interface containing the UMI path
|
||
|
//
|
||
|
// Returns: S_OK on success. Error code otherwise.
|
||
|
//
|
||
|
// Modifies: Nothing
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
static HRESULT ValidateUrl(
|
||
|
IUmiURL *pURL
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
WCHAR pszTmpArray[MAX_URL+1];
|
||
|
ULONG ulTmpArraySize = 0;
|
||
|
ULONGLONG PathType = 0;
|
||
|
|
||
|
hr = pURL->GetPathInfo(0, &PathType);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
if(PathType & UMIPATH_INFO_RELATIVE_PATH)
|
||
|
// relative paths cannot be converted to a WinNT path
|
||
|
BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
|
||
|
|
||
|
// Make sure server name is empty. WinNT does not support servername
|
||
|
// in UMI path.
|
||
|
ulTmpArraySize = MAX_URL;
|
||
|
hr = pURL->GetLocator(
|
||
|
&ulTmpArraySize,
|
||
|
pszTmpArray
|
||
|
);
|
||
|
if(WBEM_E_BUFFER_TOO_SMALL == hr)
|
||
|
// Locator is not an empty string
|
||
|
hr = UMI_E_INVALID_PATH;
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
if(wcscmp(pszTmpArray, L""))
|
||
|
BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
|
||
|
|
||
|
// Make sure namespace is WinNT
|
||
|
ulTmpArraySize = MAX_URL;
|
||
|
hr = pURL->GetRootNamespace(
|
||
|
&ulTmpArraySize,
|
||
|
pszTmpArray
|
||
|
);
|
||
|
if(WBEM_E_BUFFER_TOO_SMALL == hr)
|
||
|
// Namespace is not WinNT
|
||
|
hr = UMI_E_INVALID_PATH;
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
if(_wcsicmp(pszTmpArray, L"WinNT"))
|
||
|
BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
|
||
|
|
||
|
error:
|
||
|
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Function: UmiToWinNTPath
|
||
|
//
|
||
|
// Synopsis: This function converts a UMI path into a native path.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// pURL Pointer to URL interface containing the UMI path
|
||
|
// ppszWinNTPath Returns the WinNT path
|
||
|
// pdwNumComps Returns the number of components in the UMI path
|
||
|
// pppszClasses Returns the class of each component in the UMI path
|
||
|
//
|
||
|
// Returns: S_OK on success. Error code otherwise.
|
||
|
//
|
||
|
// Modifies: *ppszWinNTPath to return the WinNT path
|
||
|
// *pdwNumComps to return the number of components
|
||
|
// *pppszClasses to return the class of each component
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
HRESULT UmiToWinNTPath(
|
||
|
IUmiURL *pURL,
|
||
|
WCHAR **ppszWinNTPath,
|
||
|
DWORD *pdwNumComps,
|
||
|
LPWSTR **pppszClasses
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
WCHAR *pszWinNTPath = NULL;
|
||
|
WCHAR pszTmpArray[MAX_URL+1], pszValueArray[MAX_URL+1];
|
||
|
WCHAR *pszValuePtr = NULL, pszClassArray[MAX_URL+1];
|
||
|
ULONG ulTmpArraySize = 0, ulNumComponents = 0, ulIndex = 0;
|
||
|
ULONG ulKeyCount = 0, ulValueArraySize = 0, ulClassArraySize = 0;
|
||
|
IUmiURLKeyList *pKeyList = NULL;
|
||
|
LPWSTR *ppszClasses = NULL;
|
||
|
|
||
|
ADsAssert( (pURL != NULL) && (ppszWinNTPath != NULL) &&
|
||
|
(pdwNumComps != NULL) && (pppszClasses != NULL) );
|
||
|
|
||
|
*ppszWinNTPath = NULL;
|
||
|
*pdwNumComps = 0;
|
||
|
*pppszClasses = NULL;
|
||
|
|
||
|
hr = ValidateUrl(pURL);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
// Get the total length needed for the WinNT path
|
||
|
ulTmpArraySize = MAX_URL;
|
||
|
hr = pURL->Get(0, &ulTmpArraySize, pszTmpArray);
|
||
|
if(hr != WBEM_E_BUFFER_TOO_SMALL)
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
pszWinNTPath = (WCHAR *) AllocADsMem(ulTmpArraySize * sizeof(WCHAR));
|
||
|
if(NULL == pszWinNTPath)
|
||
|
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
|
||
|
|
||
|
wsprintf(pszWinNTPath, L"%s", L"WinNT:");
|
||
|
|
||
|
hr = pURL->GetComponentCount(&ulNumComponents);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
if(0 == ulNumComponents) {
|
||
|
// umi:///winnt translates to WinNT: . Nothing more to do
|
||
|
*ppszWinNTPath = pszWinNTPath;
|
||
|
RRETURN(S_OK);
|
||
|
}
|
||
|
|
||
|
ppszClasses = (LPWSTR *) AllocADsMem(ulNumComponents * sizeof(LPWSTR *));
|
||
|
if(NULL == ppszClasses) {
|
||
|
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
|
||
|
}
|
||
|
memset(ppszClasses, 0, ulNumComponents * sizeof(LPWSTR *));
|
||
|
|
||
|
// we have at least one component in the path
|
||
|
wcscat(pszWinNTPath, L"/");
|
||
|
|
||
|
for(ulIndex = 0; ulIndex < ulNumComponents; ulIndex++) {
|
||
|
ulClassArraySize = MAX_URL;
|
||
|
pKeyList = NULL;
|
||
|
|
||
|
hr = pURL->GetComponent(
|
||
|
ulIndex,
|
||
|
&ulClassArraySize,
|
||
|
pszClassArray,
|
||
|
&pKeyList
|
||
|
);
|
||
|
if(WBEM_E_BUFFER_TOO_SMALL == hr)
|
||
|
// none of the WinNT classes is so long, so this has to be a bad path.
|
||
|
hr = UMI_E_INVALID_PATH;
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
// WinNT does not supports components with an empty class name
|
||
|
if(!wcscmp(pszClassArray, L""))
|
||
|
BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
|
||
|
|
||
|
ppszClasses[ulIndex] = AllocADsStr(pszClassArray);
|
||
|
if(NULL == ppszClasses[ulIndex]) {
|
||
|
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
|
||
|
}
|
||
|
|
||
|
ADsAssert(pKeyList != NULL);
|
||
|
|
||
|
// make sure there is only one key
|
||
|
hr = pKeyList->GetCount(&ulKeyCount);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
if(ulKeyCount != 1)
|
||
|
BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
|
||
|
|
||
|
ulValueArraySize = MAX_URL;
|
||
|
ulTmpArraySize = MAX_URL;
|
||
|
pszValuePtr = pszValueArray;
|
||
|
hr = pKeyList->GetKey(
|
||
|
0,
|
||
|
0,
|
||
|
&ulTmpArraySize,
|
||
|
pszTmpArray,
|
||
|
&ulValueArraySize,
|
||
|
pszValueArray
|
||
|
);
|
||
|
if( (WBEM_E_BUFFER_TOO_SMALL == hr) && (ulValueArraySize > MAX_URL) ) {
|
||
|
pszValuePtr = (WCHAR *) AllocADsMem(ulValueArraySize);
|
||
|
if(NULL == pszValuePtr)
|
||
|
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
|
||
|
|
||
|
hr = pKeyList->GetKey(
|
||
|
0,
|
||
|
0,
|
||
|
&ulTmpArraySize,
|
||
|
pszTmpArray,
|
||
|
&ulValueArraySize,
|
||
|
pszValuePtr
|
||
|
);
|
||
|
}
|
||
|
if(WBEM_E_BUFFER_TOO_SMALL == hr)
|
||
|
// Key is always "Name" in WinNT. So, if the size required if so
|
||
|
// high, it indicates a bad path
|
||
|
hr = UMI_E_INVALID_PATH;
|
||
|
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
// Key has to be "Name" or empty in WinNT
|
||
|
if( _wcsicmp(pszTmpArray, WINNT_KEY_NAME) && wcscmp(pszTmpArray, L"") )
|
||
|
BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
|
||
|
|
||
|
// append the value to the WinNT path
|
||
|
wcscat(pszWinNTPath, L"/");
|
||
|
wcscat(pszWinNTPath, pszValuePtr);
|
||
|
|
||
|
if(pszValuePtr != pszValueArray)
|
||
|
FreeADsMem(pszValuePtr);
|
||
|
|
||
|
pKeyList->Release();
|
||
|
} // for
|
||
|
|
||
|
// append the class to the WInNT path
|
||
|
wcscat(pszWinNTPath, L",");
|
||
|
wcscat(pszWinNTPath, pszClassArray);
|
||
|
|
||
|
*ppszWinNTPath = pszWinNTPath;
|
||
|
*pdwNumComps = ulNumComponents;
|
||
|
*pppszClasses = ppszClasses;
|
||
|
|
||
|
RRETURN(S_OK);
|
||
|
|
||
|
error:
|
||
|
|
||
|
if(pszWinNTPath != NULL)
|
||
|
FreeADsMem(pszWinNTPath);
|
||
|
|
||
|
if( (pszValuePtr != NULL) && (pszValuePtr != pszValueArray) )
|
||
|
FreeADsMem(pszValuePtr);
|
||
|
|
||
|
if(ppszClasses != NULL) {
|
||
|
for(ulIndex = 0; ulIndex < ulNumComponents; ulIndex++) {
|
||
|
if(ppszClasses[ulIndex] != NULL)
|
||
|
FreeADsStr(ppszClasses[ulIndex]);
|
||
|
}
|
||
|
|
||
|
FreeADsMem(ppszClasses);
|
||
|
}
|
||
|
|
||
|
if(pKeyList != NULL)
|
||
|
pKeyList->Release();
|
||
|
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Function: ADsToUmiPath
|
||
|
//
|
||
|
// Synopsis: This function converts an ADsPath to a UMI path (full, short or
|
||
|
// relative depending on a flag).
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// bstrADsPath ADsPath to be converted
|
||
|
// pObjectInfo Contains the values of each component in the ADsPath
|
||
|
// CompClasses Array containing the classes of each component of the ADsPath
|
||
|
// dwNumComponents Number of classes(components) in the ADsPath
|
||
|
// dwUmiPathType Specifies the format of the UMI path to be returned
|
||
|
// ppszUmiPath Returns UMI path in the requested format
|
||
|
//
|
||
|
// Returns: S_OK on success. Error code otherwise.
|
||
|
//
|
||
|
// Modifies: *ppszUmiPath to return the UMI path
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
HRESULT ADsToUmiPath(
|
||
|
BSTR bstrADsPath,
|
||
|
OBJECTINFO *pObjectInfo,
|
||
|
LPWSTR CompClasses[],
|
||
|
DWORD dwNumComponents,
|
||
|
DWORD dwUmiPathType,
|
||
|
LPWSTR *ppszUmiPath
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
DWORD dwBufferLen = 0, dwIndex = 0;
|
||
|
LPWSTR pszUmiPath = NULL, *pszComponents = NULL;
|
||
|
|
||
|
ADsAssert( (bstrADsPath != NULL) && (CompClasses != NULL) &&
|
||
|
(pObjectInfo != NULL) && (ppszUmiPath != NULL) );
|
||
|
*ppszUmiPath = NULL;
|
||
|
|
||
|
// calculate approximate length of buffer required to return the UMI path
|
||
|
// Each component is of the form "class.name=value". "value" is already
|
||
|
// part of the ADSI path. Include the size of each class and add 6 to
|
||
|
// account for "Name" and '.' and '='.
|
||
|
dwBufferLen = wcslen(L"umi:///winnt/") + wcslen(bstrADsPath) +
|
||
|
dwNumComponents * (MAX_CLASS + 6) + 1;
|
||
|
|
||
|
pszUmiPath = (LPWSTR) AllocADsMem(dwBufferLen * sizeof(WCHAR));
|
||
|
if(NULL == pszUmiPath)
|
||
|
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
|
||
|
|
||
|
// if ADsPath is empty and it is not a namespace object, then this must be
|
||
|
// a session, resource or printjob object. Return an empty path for these.
|
||
|
// Namespace objects have no components in the ADsPath, but they have a
|
||
|
// non-empty ADsPath ("WinNT:")
|
||
|
if( (0 == dwNumComponents) && _wcsicmp(CompClasses[0], L"Namespace") ) {
|
||
|
wcscpy(pszUmiPath, L"");
|
||
|
*ppszUmiPath = pszUmiPath;
|
||
|
|
||
|
RRETURN(S_OK);
|
||
|
}
|
||
|
|
||
|
if( (RELATIVE_UMI_PATH == dwUmiPathType) ||
|
||
|
(FULL_RELATIVE_UMI_PATH == dwUmiPathType) ) {
|
||
|
// return the last component, if any
|
||
|
|
||
|
if(0 == dwNumComponents) {
|
||
|
*pszUmiPath = '\0';
|
||
|
}
|
||
|
else {
|
||
|
wcscpy(pszUmiPath,
|
||
|
CompClasses[dwNumComponents - 1]
|
||
|
);
|
||
|
if(FULL_RELATIVE_UMI_PATH == dwUmiPathType)
|
||
|
wcscat(pszUmiPath, L".Name=");
|
||
|
else
|
||
|
wcscat(pszUmiPath, L"=");
|
||
|
|
||
|
pszComponents = pObjectInfo->DisplayComponentArray;
|
||
|
|
||
|
wcscat(pszUmiPath, pszComponents[dwNumComponents - 1]);
|
||
|
}
|
||
|
|
||
|
*ppszUmiPath = pszUmiPath;
|
||
|
|
||
|
RRETURN(S_OK);
|
||
|
}
|
||
|
|
||
|
wcscpy(pszUmiPath, L"umi:///winnt");
|
||
|
|
||
|
// for namespace objects, there are no components and hence the umi path
|
||
|
// is completely constructed at this point.
|
||
|
if(0 == dwNumComponents) {
|
||
|
*ppszUmiPath = pszUmiPath;
|
||
|
RRETURN(S_OK);
|
||
|
}
|
||
|
|
||
|
wcscat(pszUmiPath, L"/");
|
||
|
|
||
|
pszComponents = pObjectInfo->DisplayComponentArray;
|
||
|
|
||
|
for(dwIndex = 0; dwIndex < dwNumComponents; dwIndex++) {
|
||
|
wcscat(pszUmiPath, CompClasses[dwIndex]);
|
||
|
if(FULL_UMI_PATH == dwUmiPathType)
|
||
|
wcscat(pszUmiPath, L".Name=");
|
||
|
else if(SHORT_UMI_PATH == dwUmiPathType)
|
||
|
wcscat(pszUmiPath, L"=");
|
||
|
|
||
|
wcscat(pszUmiPath, pszComponents[dwIndex]);
|
||
|
if(dwIndex != (dwNumComponents - 1))
|
||
|
wcscat(pszUmiPath, L"/");
|
||
|
}
|
||
|
|
||
|
*ppszUmiPath = pszUmiPath;
|
||
|
|
||
|
RRETURN(S_OK);
|
||
|
|
||
|
error:
|
||
|
|
||
|
if(pszUmiPath != NULL)
|
||
|
FreeADsMem(pszUmiPath);
|
||
|
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|