#include "nwcompat.hxx" #pragma hdrstop FILTERS Filters[] = { {L"computer", NWCOMPAT_COMPUTER_ID}, {L"user", NWCOMPAT_USER_ID}, {L"group", NWCOMPAT_GROUP_ID}, {L"service", NWCOMPAT_SERVICE_ID}, {L"printqueue", NWCOMPAT_PRINTER_ID}, {L"fileshare", NWCOMPAT_FILESHARE_ID}, {L"class", NWCOMPAT_CLASS_ID}, {L"syntax", NWCOMPAT_SYNTAX_ID}, {L"property", NWCOMPAT_PROPERTY_ID} }; #define MAX_FILTERS (sizeof(Filters)/sizeof(FILTERS)) HRESULT CreatePropEntry( LPWSTR szPropName, ADSTYPE dwADsType, VARIANT varData, REFIID riid, LPVOID * ppDispatch ); PFILTERS gpFilters = Filters; DWORD gdwMaxFilters = MAX_FILTERS; extern WCHAR * szProviderName; //+------------------------------------------------------------------------ // // Class: Common // // Purpose: Contains NWCOMPAT routines and properties that are common to // all NWCOMPAT objects. NWCOMPAT objects get the routines and // properties through C++ inheritance. // //------------------------------------------------------------------------- HRESULT MakeUncName( LPWSTR szSrcBuffer, LPWSTR szTargBuffer ) { ADsAssert(szSrcBuffer && *szSrcBuffer); wcscpy(szTargBuffer, L"\\\\"); wcscat(szTargBuffer, szSrcBuffer); RRETURN(S_OK); } HRESULT ValidateOutParameter( BSTR * retval ) { if (!retval) { RRETURN(E_ADS_BAD_PARAMETER); } RRETURN(S_OK); } HRESULT BuildADsPath( BSTR Parent, BSTR Name, BSTR *pADsPath ) { WCHAR ADsPath[MAX_PATH]; WCHAR ProviderName[MAX_PATH]; HRESULT hr = S_OK; LPWSTR pszDisplayName = NULL; // // We will assert if bad parameters are passed to us. // This is because this should never be the case. This // is an internal call // ADsAssert(Parent && Name); ADsAssert(pADsPath); hr = GetDisplayName( Name, &pszDisplayName ); BAIL_ON_FAILURE(hr); // // Special case the Namespace object; if // the parent is L"ADs:", then Name = ADsPath // if (!_wcsicmp(Parent, L"ADs:")) { hr = ADsAllocString(Name, pADsPath); BAIL_ON_FAILURE(hr); goto cleanup; } // // The rest of the cases we expect valid data, // Path, Parent and Name are read-only, the end-user // cannot modify this data // // // For the first object, the domain object we do not add // the first backslash; so we examine that the parent is // L"NWCOMPAT:" and skip the slash otherwise we start with // the slash // wsprintf(ProviderName, L"%s:", szProviderName); wcscpy(ADsPath, Parent); if (_wcsicmp(ADsPath, ProviderName)) { wcscat(ADsPath, L"/"); } else { wcscat(ADsPath, L"//"); } wcscat(ADsPath, Name); hr = ADsAllocString(ADsPath, pADsPath); cleanup: error: if (pszDisplayName) { FreeADsMem(pszDisplayName); } RRETURN(hr); } HRESULT BuildSchemaPath( BSTR Parent, BSTR Name, BSTR Schema, BSTR *pSchemaPath ) { WCHAR SchemaPath[MAX_PATH]; WCHAR ProviderName[MAX_PATH]; HRESULT hr = S_OK; long i; ULONG cchSchemaPath = 0; OBJECTINFO ObjectInfo; POBJECTINFO pObjectInfo = &ObjectInfo; CLexer Lexer(Parent); memset(pObjectInfo, 0, sizeof(OBJECTINFO)); // // We will assert if bad parameters are passed to us. // This is because this should never be the case. This // is an internal call // ADsAssert(Parent); ADsAssert(pSchemaPath); // // If no schema name is passed in, then there is no schema path // if ( Schema == NULL || *Schema == 0 ){ RRETURN(ADsAllocString(L"", pSchemaPath)); } memset(pObjectInfo, 0, sizeof(OBJECTINFO)); hr = Object(&Lexer, pObjectInfo); BAIL_ON_FAILURE(hr); cchSchemaPath += wcslen(szProviderName) + 3; cchSchemaPath += ((!pObjectInfo->NumComponents) ? wcslen(Name) : wcslen(pObjectInfo->DisplayComponentArray[0])); cchSchemaPath += 2; cchSchemaPath += wcslen(SCHEMA_NAME); cchSchemaPath += wcslen(Schema); if (cchSchemaPath >= MAX_PATH) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } wsprintf(SchemaPath, L"%s://", szProviderName); if (!pObjectInfo->NumComponents) { wcscat(SchemaPath, Name); }else{ wcscat(SchemaPath, pObjectInfo->DisplayComponentArray[0]); } wcscat( SchemaPath, L"/"); wcscat( SchemaPath, SCHEMA_NAME ); wcscat( SchemaPath, L"/"); wcscat( SchemaPath, Schema ); hr = ADsAllocString(SchemaPath, pSchemaPath); error: FreeObjectInfo( &ObjectInfo, TRUE ); RRETURN(hr); } HRESULT BuildADsGuid( REFCLSID clsid, BSTR *pADsClass ) { WCHAR ADsClass[MAX_PATH]; if (!StringFromGUID2(clsid, ADsClass, MAX_PATH)) { // // MAX_PATH should be more than enough for the GUID. // ADsAssert(!"GUID too big !!!"); RRETURN(E_FAIL); } RRETURN(ADsAllocString(ADsClass, pADsClass)); } HRESULT BuildObjectInfo( BSTR ADsParent, BSTR Name, POBJECTINFO * ppObjectInfo ) { WCHAR szBuffer[MAX_PATH]; ULONG cchBuffer = 0; HRESULT hr; POBJECTINFO pObjectInfo = NULL; memset(szBuffer, 0, sizeof(szBuffer)); cchBuffer += (wcslen(ADsParent) + 1 + wcslen(Name)); if (cchBuffer >= MAX_PATH) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } else { wcscpy(szBuffer, ADsParent); wcscat(szBuffer, L"/"); wcscat(szBuffer, Name); CLexer Lexer(szBuffer); pObjectInfo = (POBJECTINFO)AllocADsMem(sizeof(OBJECTINFO)); if (!pObjectInfo) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } memset(pObjectInfo, 0, sizeof(OBJECTINFO)); hr = Object(&Lexer, pObjectInfo); BAIL_ON_FAILURE(hr); *ppObjectInfo = pObjectInfo; RRETURN(hr); } error: if (pObjectInfo) { FreeObjectInfo(pObjectInfo); } *ppObjectInfo = NULL; RRETURN(hr); } HRESULT BuildObjectInfo( BSTR ADsPath, POBJECTINFO * ppObjectInfo ) { HRESULT hr; POBJECTINFO pObjectInfo = NULL; CLexer Lexer(ADsPath); pObjectInfo = (POBJECTINFO)AllocADsMem(sizeof(OBJECTINFO)); if (!pObjectInfo) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } memset(pObjectInfo, 0, sizeof(OBJECTINFO)); hr = Object(&Lexer, pObjectInfo); BAIL_ON_FAILURE(hr); *ppObjectInfo = pObjectInfo; RRETURN(hr); error: if (pObjectInfo) { FreeObjectInfo(pObjectInfo); } *ppObjectInfo = NULL; RRETURN(hr); } VOID FreeObjectInfo( POBJECTINFO pObjectInfo, BOOL fStatic ) { DWORD i = 0; if (!pObjectInfo) { return; } FreeADsStr(pObjectInfo->ProviderName); for (i = 0; i < pObjectInfo->NumComponents; i++ ) { FreeADsStr(pObjectInfo->ComponentArray[i]); FreeADsStr(pObjectInfo->DisplayComponentArray[i]); } if ( !fStatic ) { FreeADsMem(pObjectInfo); } } HRESULT ValidateObject( DWORD dwObjectType, POBJECTINFO pObjectInfo ) { switch (dwObjectType) { case NWCOMPAT_USER_ID: RRETURN(ValidateUserObject(pObjectInfo)); case NWCOMPAT_GROUP_ID: RRETURN(ValidateGroupObject(pObjectInfo)); case NWCOMPAT_PRINTER_ID: RRETURN(ValidatePrinterObject(pObjectInfo)); default: RRETURN(E_FAIL); } } HRESULT GetObjectType( PFILTERS pFilters, DWORD dwMaxFilters, BSTR ClassName, PDWORD pdwObjectType ) { DWORD i = 0; ADsAssert(pdwObjectType); for (i = 0; i < dwMaxFilters; i++) { if (!_wcsicmp(ClassName, (pFilters + i)->szObjectName)) { *pdwObjectType = (pFilters + i)->dwFilterId; RRETURN(S_OK); } } *pdwObjectType = 0; RRETURN(E_FAIL); } HRESULT ValidateProvider( POBJECTINFO pObjectInfo ) { // // The provider name is case-sensitive. This is a restriction that OLE // has put on us. // if (!(wcscmp(pObjectInfo->ProviderName, szProviderName))) { RRETURN(S_OK); } RRETURN(E_FAIL); } HRESULT ConvertSystemTimeToDATE( SYSTEMTIME Time, DATE * pdaTime ) { FILETIME ft; BOOL fRetval = FALSE; USHORT wDosDate; USHORT wDosTime; // // System Time To File Time. // fRetval = SystemTimeToFileTime(&Time, &ft); if(!fRetval){ RRETURN(HRESULT_FROM_WIN32(GetLastError())); } // // File Time to DosDateTime. // fRetval = FileTimeToDosDateTime(&ft, &wDosDate, &wDosTime); if(!fRetval){ RRETURN(HRESULT_FROM_WIN32(GetLastError())); } // // DosDateTime to VariantTime. // fRetval = DosDateTimeToVariantTime(wDosDate, wDosTime, pdaTime ); if(!fRetval){ RRETURN(HRESULT_FROM_WIN32(GetLastError())); } RRETURN(S_OK); } HRESULT ConvertDATEToSYSTEMTIME( DATE daDate, SYSTEMTIME *pSysTime ) { HRESULT hr; FILETIME ft; BOOL fRetval = FALSE; USHORT wDosDate; USHORT wDosTime; fRetval = VariantTimeToDosDateTime(daDate, &wDosDate, &wDosTime ); if(!fRetval){ hr = HRESULT_FROM_WIN32(GetLastError()); RRETURN(hr); } fRetval = DosDateTimeToFileTime(wDosDate, wDosTime, &ft); if(!fRetval){ hr = HRESULT_FROM_WIN32(GetLastError()); RRETURN(hr); } fRetval = FileTimeToSystemTime(&ft, pSysTime ); if(!fRetval){ hr = HRESULT_FROM_WIN32(GetLastError()); RRETURN(hr); } RRETURN(S_OK); } HRESULT ConvertDATEToDWORD( DATE daDate, DWORD *pdwDate ) { BOOL fBool = TRUE; WORD wDOSDate = 0; WORD wDOSTime = 0; WORD wHour = 0; WORD wMinute = 0; // // Break up Variant date. // fBool = VariantTimeToDosDateTime( (DOUBLE) daDate, &wDOSDate, &wDOSTime ); if (fBool == FALSE) { goto error; } // // Convert DOS time into DWORD time which expresses time as the number of // minutes elapsed since mid-night. // wHour = wDOSTime >> 11; wMinute = (wDOSTime >> 5) - (wHour << 6); // // Return. // *pdwDate = wHour * 60 + wMinute; error: RRETURN(S_OK); } HRESULT ConvertDWORDToDATE( DWORD dwTime, DATE * pdaTime ) { BOOL fBool = TRUE; DOUBLE vTime = 0; SYSTEMTIME SysTime = {1980,1,0,1,0,0,0,0}; SYSTEMTIME LocalTime = {1980,1,0,1,0,0,0,0}; WORD wDOSDate = 0; WORD wDOSTime = 0; WORD wHour = 0; WORD wMinute = 0; WORD wSecond = 0; // // Get Hour and Minute from DWORD. // SysTime.wHour = (WORD) (dwTime / 60); SysTime.wMinute = (WORD) (dwTime % 60); // // Get Time-zone specific local time. // fBool = SystemTimeToTzSpecificLocalTime( NULL, &SysTime, &LocalTime ); if (fBool == FALSE) { RRETURN(HRESULT_FROM_WIN32(GetLastError())); } wHour = LocalTime.wHour; wMinute = LocalTime.wMinute; wSecond = LocalTime.wSecond; // // Set a dummy date. // wDOSDate = DATE_1980_JAN_1; // // Shift data to correct bit as required by the DOS date & time format. // wHour = wHour << 11; wMinute = wMinute << 5; // // Put them in DOS format. // wDOSTime = wHour | wMinute | wSecond; // // Convert into VariantTime. // fBool = DosDateTimeToVariantTime( wDOSDate, wDOSTime, &vTime ); // // Return. // if (fBool == TRUE) { *pdaTime = vTime; RRETURN(S_OK); } else { RRETURN(E_FAIL); } } HRESULT DelimitedStringToVariant( LPTSTR pszString, VARIANT *pvar, TCHAR Delimiter ) { SAFEARRAYBOUND sabound[1]; DWORD dwElements; LPTSTR pszCurrPos = pszString; LPTSTR *rgszStrings = NULL; SAFEARRAY *psa = NULL; VARIANT v; HRESULT hr = S_OK; LONG i; // // This function converts a delimited string into a VARIANT of // safe arrays. // // Assumption: a valid string are passed to this function // note that the input string gets destroyed in the process // // // scan the delimited string once to find out the dimension // // // in order to filter for NULL input values do a sanity check for // length of input string. // // // take care of null case first for sanity's sake // if (!pszString){ sabound[0].cElements = 0; sabound[0].lLbound = 0; psa = SafeArrayCreate(VT_VARIANT, 1, sabound); if (psa == NULL){ hr = E_OUTOFMEMORY; goto error; } VariantInit(pvar); V_VT(pvar) = VT_ARRAY|VT_VARIANT; V_ARRAY(pvar) = psa; goto error; } dwElements = (wcslen(pszString) == 0) ? 0: 1 ; while(!(*pszCurrPos == TEXT('\0'))){ if(*pszCurrPos == Delimiter){ dwElements++; *pszCurrPos = TEXT('\0'); } pszCurrPos++; } rgszStrings = (LPTSTR *)AllocADsMem(sizeof(LPTSTR)*dwElements); if(!rgszStrings){ hr = E_OUTOFMEMORY; goto error; } // // scan string again and put the appropriate pointers // pszCurrPos = pszString; if(rgszStrings != NULL){ (*rgszStrings) = pszCurrPos; } i = 1; while(i < (LONG)dwElements){ if(*pszCurrPos == TEXT('\0')){ *(rgszStrings+i) = ++pszCurrPos; i++; } pszCurrPos++; } // // create the safearray // sabound[0].cElements = dwElements; sabound[0].lLbound = 0; psa = SafeArrayCreate(VT_VARIANT, 1, sabound); if (psa == NULL){ hr = E_OUTOFMEMORY; goto error; } for(i=0; i<(LONG)dwElements; i++){ VariantInit(&v); V_VT(&v) = VT_BSTR; hr = ADsAllocString(*(rgszStrings+i), &(V_BSTR(&v))); BAIL_ON_FAILURE(hr); // // Stick the caller provided data into the end of the SafeArray // hr = SafeArrayPutElement(psa, &i, &v); VariantClear(&v); BAIL_ON_FAILURE(hr); } // // convert this safearray into a VARIANT // VariantInit(pvar); V_VT(pvar) = VT_ARRAY|VT_VARIANT; V_ARRAY(pvar) = psa; error: if(rgszStrings && dwElements != 0){ FreeADsMem(rgszStrings); } RRETURN(hr); } HRESULT VariantToDelimitedString( VARIANT var, LPTSTR *ppszString, TCHAR Delimiter ) { LONG lIndices; ULONG cElements; ULONG ulRequiredLength=0; SAFEARRAY *psa = NULL; VARIANT vElement; LPTSTR pszCurrPos = NULL; HRESULT hr = S_OK; ULONG i; // // converts the safearray in a variant to a delimited string // *ppszString = NULL; if(!(V_VT(&var) == (VT_VARIANT|VT_ARRAY))) { RRETURN(E_FAIL); } psa = V_ARRAY(&var); // // Check that there is only one dimension in this array // if (psa->cDims != 1) { hr = E_FAIL; BAIL_ON_FAILURE(hr); } // // Check that there is atleast one element in this array // cElements = psa->rgsabound[0].cElements; if (cElements == 0){ hr = E_FAIL; goto error; } // // We know that this is a valid single dimension array // lIndices= 0; for(i=0; i< cElements; i++){ lIndices = i; VariantInit(&vElement); hr = SafeArrayGetElement(psa, &lIndices, &vElement); BAIL_ON_FAILURE(hr); if(!(V_VT(&vElement) == VT_BSTR)){ RRETURN(E_FAIL); } // // unpack the BSTR in the VARIANT // ulRequiredLength+= wcslen(vElement.bstrVal)+1; VariantClear(&vElement); } ulRequiredLength +=2; *ppszString = (LPTSTR)AllocADsMem( ulRequiredLength*sizeof(TCHAR)); if(*ppszString == NULL){ hr = E_OUTOFMEMORY; goto error; } lIndices= 0; pszCurrPos = *ppszString; for(i=0; i< cElements; i++){ lIndices = i; VariantInit(&vElement); hr = SafeArrayGetElement(psa, &lIndices, &vElement); BAIL_ON_FAILURE(hr); if(!(V_VT(&vElement) == VT_BSTR)){ RRETURN(E_FAIL); } // // unpack the BSTR in the VARIANT // wcscpy(pszCurrPos, (LPTSTR)vElement.bstrVal); pszCurrPos += wcslen(vElement.bstrVal); if(i < cElements-1){ *pszCurrPos = Delimiter; } pszCurrPos++; VariantClear(&vElement); } *pszCurrPos = L'\0'; RRETURN(S_OK); error: RRETURN(hr); } HRESULT VariantToNulledString( VARIANT var, LPTSTR *ppszString ) { LONG lIndices; ULONG cElements; ULONG ulRequiredLength=0; SAFEARRAY *psa = NULL; VARIANT vElement; LPTSTR szCurrPos = NULL; HRESULT hr = S_OK; ULONG i; // //converts the safearray in a variant to a double nulled string // VariantInit(&vElement); *ppszString = NULL; if (!(V_VT(&var) == (VT_VARIANT|VT_ARRAY))) { RRETURN(E_FAIL); } psa = V_ARRAY(&var); // // Check that there is only one dimension in this array // if (psa->cDims != 1) { hr = E_FAIL; BAIL_ON_FAILURE(hr); } // // Check that there is atleast one element in this array // cElements = psa->rgsabound[0].cElements; if (cElements == 0){ hr = E_FAIL; BAIL_ON_FAILURE(hr); } // // We know that this is a valid single dimension array // lIndices= 0; for(i=0; i< cElements; i++){ lIndices = i; VariantInit(&vElement); hr = SafeArrayGetElement(psa, &lIndices, &vElement); BAIL_ON_FAILURE(hr); if(!(V_VT(&vElement) == VT_BSTR)){ RRETURN(E_FAIL); } // // unpack the BSTR in the VARIANT // ulRequiredLength+= wcslen(vElement.bstrVal)+1; VariantClear(&vElement); } ulRequiredLength +=2; *ppszString = (LPTSTR)AllocADsMem( ulRequiredLength*sizeof(TCHAR)); if(*ppszString == NULL){ hr = E_OUTOFMEMORY; goto error; } lIndices= 0; szCurrPos = *ppszString; for(i=0; i< cElements; i++){ lIndices = i; VariantInit(&vElement); hr = SafeArrayGetElement(psa, &lIndices, &vElement); BAIL_ON_FAILURE(hr); if(!(V_VT(&vElement) == VT_BSTR)){ RRETURN(E_FAIL); } // // unpack the BSTR in the VARIANT // wcscpy(szCurrPos, (LPTSTR)vElement.bstrVal); szCurrPos += wcslen(vElement.bstrVal)+1; VariantClear(&vElement); } *szCurrPos = L'\0'; RRETURN(S_OK); error: VariantClear(&vElement); RRETURN(hr); } HRESULT NulledStringToVariant( LPTSTR pszString, VARIANT *pvar ) { SAFEARRAYBOUND sabound[1]; DWORD dwElements = 0; LPTSTR pszCurrPos = pszString; BOOL foundNULL = FALSE; LPTSTR *rgszStrings = NULL; SAFEARRAY *psa = NULL; VARIANT v; HRESULT hr = S_OK; LONG i; // // This function converts a double nulled string into a VARIANT of // safe arrays. // // Assumption: Valid double nulled strings are passed to this function // // // scan the double nulled string once to find out the dimension // while(!(*pszCurrPos == L'\0' && foundNULL)){ if(*pszCurrPos == L'\0'){ dwElements++; foundNULL = TRUE; } else{ foundNULL = FALSE; } pszCurrPos++; } if(dwElements){ rgszStrings = (LPTSTR *)AllocADsMem(sizeof(LPTSTR)*dwElements); } // // scan string again and put the appropriate pointers // pszCurrPos = pszString; if(rgszStrings != NULL){ (*rgszStrings) = pszCurrPos; } foundNULL = FALSE; i = 1; while(i < (LONG)dwElements){ if(foundNULL){ *(rgszStrings+i) = pszCurrPos; i++; } if(*pszCurrPos == L'\0'){ foundNULL = TRUE; } else{ foundNULL = FALSE; } pszCurrPos++; } // // create the safearray // sabound[0].cElements = dwElements; sabound[0].lLbound = 0; psa = SafeArrayCreate(VT_VARIANT, 1, sabound); if (psa == NULL){ hr = E_OUTOFMEMORY; goto error; } for(i=0; i<(LONG)dwElements; i++){ VariantInit(&v); V_VT(&v) = VT_BSTR; hr = ADsAllocString(*(rgszStrings+i), &(V_BSTR(&v))); BAIL_ON_FAILURE(hr); // // Stick the caller provided data into the end of the SafeArray // hr = SafeArrayPutElement(psa, &i, &v); VariantClear(&v); BAIL_ON_FAILURE(hr); } // // convert this safearray into a VARIANT // VariantInit(pvar); V_VT(pvar) = VT_ARRAY|VT_VARIANT; V_ARRAY(pvar) = psa; error: if(rgszStrings){ FreeADsMem(rgszStrings); } RRETURN(hr); } STDMETHODIMP GenericGetPropertyManager( CPropertyCache * pPropertyCache, THIS_ BSTR bstrName, VARIANT FAR* pvProp ) { HRESULT hr = S_OK; DWORD dwSyntaxId; DWORD dwNumValues; DWORD dwInfoLevel; LPNTOBJECT pNtSrcObjects = NULL; // // retrieve data object from cache; if one exists hr = pPropertyCache->getproperty( bstrName, &dwSyntaxId, &dwNumValues, &pNtSrcObjects ); BAIL_ON_FAILURE(hr); // // translate the Nt objects to variants // if (dwNumValues == 1) { hr = NtTypeToVarTypeCopy( pNtSrcObjects, pvProp ); }else { hr = NtTypeToVarTypeCopyConstruct( pNtSrcObjects, dwNumValues, pvProp ); } BAIL_ON_FAILURE(hr); error: if (pNtSrcObjects) { NTTypeFreeNTObjects( pNtSrcObjects, dwNumValues ); } RRETURN(hr); } STDMETHODIMP GenericPutPropertyManager( CPropertyCache * pPropertyCache, PPROPERTYINFO pSchemaProps, DWORD dwSchemaPropSize, THIS_ BSTR bstrName, VARIANT vProp ) { HRESULT hr = S_OK; DWORD dwSyntaxId = 0; DWORD dwIndex = 0; LPNTOBJECT pNtDestObjects = NULL; // // Issue: How do we handle multi-valued support // DWORD dwNumValues = 1; // // check if this is a legal property for this object, // // hr = ValidatePropertyinSchemaClass( pSchemaProps, dwSchemaPropSize, bstrName, &dwSyntaxId ); BAIL_ON_FAILURE(hr); // // check if this is a writeable property // hr = ValidateIfWriteableProperty( pSchemaProps, dwSchemaPropSize, bstrName ); BAIL_ON_FAILURE(hr); // // check if the variant maps to the syntax of this property // hr = VarTypeToNtTypeCopyConstruct( dwSyntaxId, &vProp, 1, &pNtDestObjects ); BAIL_ON_FAILURE(hr); // // Find this property in the cache // hr = pPropertyCache->findproperty( bstrName, &dwIndex ); // // If this property does not exist in the // cache, add this property into the cache. // if (FAILED(hr)) { hr = pPropertyCache->addproperty( bstrName, dwSyntaxId ); // // If the operation fails for some reason // move on to the next property // BAIL_ON_FAILURE(hr); } // // Now update the property in the cache // Should use putproperty, not updateproperty -> unmarshalling from svr only // hr = pPropertyCache->putproperty( bstrName, dwSyntaxId, dwNumValues, pNtDestObjects ); BAIL_ON_FAILURE(hr); error: if (pNtDestObjects) { NTTypeFreeNTObjects( pNtDestObjects, dwNumValues ); } RRETURN(hr); } HRESULT BuildPrinterNameFromADsPath( LPWSTR pszADsParent, LPWSTR pszPrinterName, LPWSTR pszUncPrinterName ) { POBJECTINFO pObjectInfo = NULL; CLexer Lexer(pszADsParent); HRESULT hr; pObjectInfo = (POBJECTINFO)AllocADsMem(sizeof(OBJECTINFO)); if (!pObjectInfo) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); memset(pObjectInfo, 0, sizeof(OBJECTINFO)); hr = Object(&Lexer, pObjectInfo); BAIL_ON_FAILURE(hr); wsprintf( pszUncPrinterName, L"\\\\%s\\%s", pObjectInfo->ComponentArray[0], pszPrinterName ); error: if(pObjectInfo){ FreeObjectInfo(pObjectInfo); } RRETURN(hr); } STDMETHODIMP GenericGetExPropertyManager( DWORD dwObjectState, CPropertyCache * pPropertyCache, THIS_ BSTR bstrName, VARIANT FAR* pvProp ) { HRESULT hr = S_OK; DWORD dwSyntaxId; DWORD dwNumValues; LPNTOBJECT pNtSrcObjects = NULL; // // retrieve data object from cache; if one exis // if (dwObjectState == ADS_OBJECT_UNBOUND) { hr = pPropertyCache->unboundgetproperty( bstrName, &dwSyntaxId, &dwNumValues, &pNtSrcObjects ); BAIL_ON_FAILURE(hr); }else { hr = pPropertyCache->getproperty( bstrName, &dwSyntaxId, &dwNumValues, &pNtSrcObjects ); BAIL_ON_FAILURE(hr); } // // translate the Nds objects to variants // hr = NtTypeToVarTypeCopyConstruct( pNtSrcObjects, dwNumValues, pvProp ); BAIL_ON_FAILURE(hr); error: if (pNtSrcObjects) { NTTypeFreeNTObjects( pNtSrcObjects, dwNumValues ); } RRETURN(hr); } STDMETHODIMP GenericPutExPropertyManager( CPropertyCache * pPropertyCache, PPROPERTYINFO pSchemaProps, DWORD dwSchemaPropSize, THIS_ BSTR bstrName, VARIANT vProp ) { HRESULT hr = S_OK; DWORD dwSyntaxId = 0; DWORD dwIndex = 0; DWORD dwNumValues = 0; LPNTOBJECT pNtDestObjects = NULL; VARIANT * pVarArray = NULL; VARIANT * pvProp = NULL; // // Issue: How do we handle multi-valued support // // // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY. // We should dereference a VT_BYREF|VT_VARIANT once and see // what's inside. // pvProp = &vProp; if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) { pvProp = V_VARIANTREF(&vProp); } if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY)) || (V_VT(&vProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF))) { hr = ConvertByRefSafeArrayToVariantArray( *pvProp, &pVarArray, &dwNumValues ); BAIL_ON_FAILURE(hr); pvProp = pVarArray; }else { hr = E_FAIL; BAIL_ON_FAILURE(hr); } // // check if this is a legal property for this object, // // hr = ValidatePropertyinSchemaClass( pSchemaProps, dwSchemaPropSize, bstrName, &dwSyntaxId ); BAIL_ON_FAILURE(hr); // // check if this is a writeable property // hr = ValidateIfWriteableProperty( pSchemaProps, dwSchemaPropSize, bstrName ); BAIL_ON_FAILURE(hr); // // check if the variant maps to the syntax of this property // hr = VarTypeToNtTypeCopyConstruct( dwSyntaxId, pvProp, dwNumValues, &pNtDestObjects ); BAIL_ON_FAILURE(hr); // // Find this property in the cache // hr = pPropertyCache->findproperty( bstrName, &dwIndex ); // // If this property does not exist in the // cache, add this property into the cache. // if (FAILED(hr)) { hr = pPropertyCache->addproperty( bstrName, dwSyntaxId ); // // If the operation fails for some reason // move on to the next property // BAIL_ON_FAILURE(hr); } // // Now update the property in the cache // hr = pPropertyCache->putproperty( bstrName, dwSyntaxId, dwNumValues, pNtDestObjects ); BAIL_ON_FAILURE(hr); error: if (pNtDestObjects) { NTTypeFreeNTObjects( pNtDestObjects, dwNumValues ); } if (pVarArray) { DWORD i = 0; for (i = 0; i < dwNumValues; i++) { VariantClear(pVarArray + i); } FreeADsMem(pVarArray); } RRETURN(hr); } HRESULT GenericPropCountPropertyManager( CPropertyCache * pPropertyCache, PLONG plCount ) { HRESULT hr = E_FAIL; if (pPropertyCache) { hr = pPropertyCache->get_PropertyCount((PDWORD)plCount); } RRETURN(hr); } HRESULT GenericNextPropertyManager( CPropertyCache * pPropertyCache, VARIANT FAR *pVariant ) { HRESULT hr = E_FAIL; DWORD dwSyntaxId = 0; DWORD dwNumValues = 0; LPNTOBJECT pNtSrcObjects = NULL; VARIANT varData; IDispatch * pDispatch = NULL; VariantInit(&varData); hr = pPropertyCache->unboundgetproperty( pPropertyCache->get_CurrentIndex(), &dwSyntaxId, &dwNumValues, &pNtSrcObjects ); BAIL_ON_FAILURE(hr); // // translate the Nt objects to variants // hr = ConvertNtValuesToVariant( pPropertyCache->get_CurrentPropName(), pNtSrcObjects, dwNumValues, pVariant ); BAIL_ON_FAILURE(hr); error: // // - goto next one even if error to avoid infinite looping at a property // which we cannot convert (e.g. schemaless server property.) // - do not return the result of Skip() as current operation does not // depend on the sucess of Skip(). // pPropertyCache->skip_propindex( 1 ); if (pNtSrcObjects) { NTTypeFreeNTObjects( pNtSrcObjects, dwNumValues ); } RRETURN(hr); } HRESULT GenericSkipPropertyManager( CPropertyCache * pPropertyCache, ULONG cElements ) { HRESULT hr = E_FAIL; hr = pPropertyCache->skip_propindex( cElements ); RRETURN(hr); } HRESULT GenericResetPropertyManager( CPropertyCache * pPropertyCache ) { pPropertyCache->reset_propindex(); RRETURN(S_OK); } HRESULT GenericDeletePropertyManager( CPropertyCache * pPropertyCache, VARIANT varEntry ) { HRESULT hr = S_OK; DWORD dwIndex = 0; switch (V_VT(&varEntry)) { case VT_BSTR: hr = pPropertyCache->findproperty( V_BSTR(&varEntry), &dwIndex ); BAIL_ON_FAILURE(hr); break; case VT_I4: dwIndex = V_I4(&varEntry); break; case VT_I2: dwIndex = V_I2(&varEntry); break; default: hr = E_FAIL; BAIL_ON_FAILURE(hr); } hr = pPropertyCache->deleteproperty( dwIndex ); error: RRETURN(hr); } HRESULT GenericPutPropItemPropertyManager( CPropertyCache * pPropertyCache, PPROPERTYINFO pSchemaProps, DWORD dwSchemaPropSize, VARIANT varData ) { HRESULT hr = S_OK; DWORD dwSyntaxId = 0; DWORD dwIndex = 0; WCHAR szPropertyName[MAX_PATH]; LPNTOBJECT pNtDestObjects = NULL; DWORD dwNumValues = 0; DWORD dwControlCode = 0; hr = ConvertVariantToNtValues( varData, pSchemaProps, dwSchemaPropSize, szPropertyName, &pNtDestObjects, &dwNumValues, &dwSyntaxId, &dwControlCode ); BAIL_ON_FAILURE(hr); if (dwControlCode != ADS_PROPERTY_UPDATE) { RRETURN(E_ADS_BAD_PARAMETER); } // // Find this property in the cache // hr = pPropertyCache->findproperty( szPropertyName, &dwIndex ); // // If this property does not exist in the // cache, add this property into the cache. // if (FAILED(hr)) { hr = pPropertyCache->addproperty( szPropertyName, dwSyntaxId ); // // If the operation fails for some reason // move on to the next property // BAIL_ON_FAILURE(hr); } // // Now update the property in the cache // hr = pPropertyCache->putproperty( szPropertyName, dwSyntaxId, dwNumValues, pNtDestObjects ); BAIL_ON_FAILURE(hr); error: if (pNtDestObjects) { NTTypeFreeNTObjects( pNtDestObjects, dwNumValues ); } RRETURN(hr); } HRESULT GenericGetPropItemPropertyManager( CPropertyCache * pPropertyCache, DWORD dwObjectState, BSTR bstrName, LONG lnADsType, VARIANT * pVariant ) { HRESULT hr = S_OK; DWORD dwSyntaxId; DWORD dwNumValues; LPNTOBJECT pNtSrcObjects = NULL; // // retrieve data object from cache; if one exis // if (dwObjectState == ADS_OBJECT_UNBOUND) { hr = pPropertyCache->unboundgetproperty( bstrName, &dwSyntaxId, &dwNumValues, &pNtSrcObjects ); BAIL_ON_FAILURE(hr); }else { hr = pPropertyCache->getproperty( bstrName, &dwSyntaxId, &dwNumValues, &pNtSrcObjects ); BAIL_ON_FAILURE(hr); } // // translate the Nds objects to variants // hr = ConvertNtValuesToVariant( bstrName, pNtSrcObjects, dwNumValues, pVariant ); BAIL_ON_FAILURE(hr); error: if (pNtSrcObjects) { NTTypeFreeNTObjects( pNtSrcObjects, dwNumValues ); } RRETURN(hr); } HRESULT GenericItemPropertyManager( CPropertyCache * pPropertyCache, DWORD dwObjectState, VARIANT varIndex, VARIANT *pVariant ) { HRESULT hr = S_OK; DWORD dwSyntaxId; DWORD dwNumValues; LPNTOBJECT pNtSrcObjects = NULL; LPWSTR szPropName = NULL; VARIANT *pvVar = &varIndex; // // retrieve data object from cache; if one exis // if (V_VT(pvVar) == (VT_BYREF|VT_VARIANT)) { // // The value is being passed in byref so we need to // deref it for vbs stuff to work // pvVar = V_VARIANTREF(&varIndex); } switch (V_VT(pvVar)) { case VT_BSTR: if (dwObjectState == ADS_OBJECT_UNBOUND) { hr = pPropertyCache->unboundgetproperty( V_BSTR(pvVar), &dwSyntaxId, &dwNumValues, &pNtSrcObjects ); BAIL_ON_FAILURE(hr); }else { hr = pPropertyCache->getproperty( V_BSTR(pvVar), &dwSyntaxId, &dwNumValues, &pNtSrcObjects ); BAIL_ON_FAILURE(hr); } hr = ConvertNtValuesToVariant( V_BSTR(pvVar), pNtSrcObjects, dwNumValues, pVariant ); BAIL_ON_FAILURE(hr); break; case VT_I4: hr = pPropertyCache->unboundgetproperty( V_I4(pvVar), &dwSyntaxId, &dwNumValues, &pNtSrcObjects ); BAIL_ON_FAILURE(hr); szPropName = pPropertyCache->get_PropName(V_I4(pvVar)); hr = ConvertNtValuesToVariant( szPropName, pNtSrcObjects, dwNumValues, pVariant ); BAIL_ON_FAILURE(hr); break; case VT_I2: hr = pPropertyCache->unboundgetproperty( (DWORD)V_I2(pvVar), &dwSyntaxId, &dwNumValues, &pNtSrcObjects ); BAIL_ON_FAILURE(hr); szPropName = pPropertyCache->get_PropName(V_I2(pvVar)); hr = ConvertNtValuesToVariant( szPropName, pNtSrcObjects, dwNumValues, pVariant ); BAIL_ON_FAILURE(hr); break; default: hr = E_FAIL; BAIL_ON_FAILURE(hr); } error: if (pNtSrcObjects) { NTTypeFreeNTObjects( pNtSrcObjects, dwNumValues ); } RRETURN(hr); } HRESULT GenericPurgePropertyManager( CPropertyCache * pPropertyCache ) { pPropertyCache->flushpropcache(); RRETURN(S_OK); } HRESULT CreatePropEntry( LPWSTR szPropName, ADSTYPE dwADsType, VARIANT varData, REFIID riid, LPVOID * ppDispatch ) { HRESULT hr = S_OK; IADsPropertyEntry * pPropEntry = NULL; hr = CoCreateInstance( CLSID_PropertyEntry, NULL, CLSCTX_INPROC_SERVER, IID_IADsPropertyEntry, (void **)&pPropEntry ); BAIL_ON_FAILURE(hr); hr = pPropEntry->put_Name(szPropName); BAIL_ON_FAILURE(hr); hr = pPropEntry->put_Values(varData); BAIL_ON_FAILURE(hr); hr = pPropEntry->put_ADsType(dwADsType); BAIL_ON_FAILURE(hr); hr = pPropEntry->QueryInterface( riid, ppDispatch ); BAIL_ON_FAILURE(hr); error: if (pPropEntry) { pPropEntry->Release(); } RRETURN(hr); } HRESULT ConvertNtValuesToVariant( LPWSTR szPropertyName, PNTOBJECT pNtSrcObject, DWORD dwNumValues, PVARIANT pVariant ) { HRESULT hr = S_OK; VARIANT varData; IDispatch * pDispatch = NULL; PADSVALUE pAdsValues = NULL; ADSTYPE dwADsType = ADSTYPE_INVALID; VariantInit(&varData); VariantInit(pVariant); if (dwNumValues>0) { hr = NTTypeToAdsTypeCopyConstruct( pNtSrcObject, dwNumValues, &pAdsValues ); if (SUCCEEDED(hr)){ hr = AdsTypeToPropVariant( pAdsValues, dwNumValues, &varData ); BAIL_ON_FAILURE(hr); dwADsType = pAdsValues->dwType; } else if (hr==E_OUTOFMEMORY) { BAIL_ON_FAILURE(hr); } // failed because of NTType is not supported yet (e.g. NulledString) // in NTTypeToAdsTypeCopyConstruct() conversion yet // -> use empty variant now. else { VariantInit(&varData); } } hr = CreatePropEntry( szPropertyName, dwADsType, varData, IID_IDispatch, (void **)&pDispatch ); BAIL_ON_FAILURE(hr); V_DISPATCH(pVariant) = pDispatch; V_VT(pVariant) = VT_DISPATCH; error: VariantClear(&varData); if (pAdsValues) { AdsFreeAdsValues( pAdsValues, dwNumValues ); FreeADsMem( pAdsValues); } RRETURN(hr); } HRESULT ConvertVariantToVariantArray( VARIANT varData, VARIANT ** ppVarArray, DWORD * pdwNumValues ) { DWORD dwNumValues = 0; VARIANT * pVarArray = NULL; HRESULT hr = S_OK; VARIANT * pVarData = NULL; *ppVarArray = NULL; *pdwNumValues = 0; // // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY. // We should dereference a VT_BYREF|VT_VARIANT once and see // what's inside. // pVarData = &varData; if (V_VT(pVarData) == (VT_BYREF|VT_VARIANT)) { pVarData = V_VARIANTREF(&varData); } if ((V_VT(pVarData) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) || (V_VT(pVarData) == (VT_VARIANT|VT_ARRAY))) { hr = ConvertSafeArrayToVariantArray( varData, &pVarArray, &dwNumValues ); BAIL_ON_FAILURE(hr); } else { pVarArray = NULL; dwNumValues = 0; } *ppVarArray = pVarArray; *pdwNumValues = dwNumValues; error: RRETURN(hr); } void FreeVariantArray( VARIANT * pVarArray, DWORD dwNumValues ) { if (pVarArray) { DWORD i = 0; for (i = 0; i < dwNumValues; i++) { VariantClear(pVarArray + i); } FreeADsMem(pVarArray); } } HRESULT ConvertVariantToNtValues( VARIANT varData, PPROPERTYINFO pSchemaProps, DWORD dwSchemaPropSize, LPWSTR szPropertyName, PNTOBJECT *ppNtDestObjects, PDWORD pdwNumValues, PDWORD pdwSyntaxId, PDWORD pdwControlCode ) { HRESULT hr = S_OK; IADsPropertyEntry * pPropEntry = NULL; IDispatch * pDispatch = NULL; BSTR bstrPropName = NULL; DWORD dwControlCode = 0; DWORD dwAdsType = 0; VARIANT varValues; VARIANT * pVarArray = NULL; DWORD dwNumValues = 0; PADSVALUE pAdsValues = NULL; DWORD dwAdsValues = 0; PNTOBJECT pNtDestObjects = 0; DWORD dwNumNtObjects = 0; DWORD dwNtSyntaxId = 0; if (V_VT(&varData) != VT_DISPATCH) { RRETURN (hr = DISP_E_TYPEMISMATCH); } pDispatch = V_DISPATCH(&varData); hr = pDispatch->QueryInterface( IID_IADsPropertyEntry, (void **)&pPropEntry ); BAIL_ON_FAILURE(hr); VariantInit(&varValues); VariantClear(&varValues); hr = pPropEntry->get_Name(&bstrPropName); BAIL_ON_FAILURE(hr); wcscpy(szPropertyName, bstrPropName); hr = pPropEntry->get_ControlCode((long *)&dwControlCode); BAIL_ON_FAILURE(hr); *pdwControlCode = dwControlCode; hr = pPropEntry->get_ADsType((long *)&dwAdsType); BAIL_ON_FAILURE(hr); hr = pPropEntry->get_Values(&varValues); BAIL_ON_FAILURE(hr); hr = ConvertVariantToVariantArray( varValues, &pVarArray, &dwNumValues ); BAIL_ON_FAILURE(hr); if (dwNumValues) { hr = PropVariantToAdsType( pVarArray, dwNumValues, &pAdsValues, &dwAdsValues ); BAIL_ON_FAILURE(hr); hr = AdsTypeToNTTypeCopyConstruct( pAdsValues, dwAdsValues, &pNtDestObjects, &dwNumNtObjects, &dwNtSyntaxId ); BAIL_ON_FAILURE(hr); } *pdwNumValues = dwNumValues; *ppNtDestObjects = pNtDestObjects; *pdwSyntaxId = dwNtSyntaxId; error: if (pVarArray) { FreeVariantArray( pVarArray, dwNumValues ); } RRETURN(hr); } HRESULT ConvertNtValuesToVariant( BSTR bstrName, LPNTOBJECT pNtSrcObjects, DWORD dwNumValues, VARIANT * pVariant ); HRESULT ConvertVariantToVariantArray( VARIANT varData, VARIANT ** ppVarArray, DWORD * pdwNumValues ); void FreeVariantArray( VARIANT * pVarArray, DWORD dwNumValues ); HRESULT ConvertVariantToNtValues( VARIANT varData, PPROPERTYINFO pSchemaProps, DWORD dwSchemaPropSize, LPWSTR szPropertyName, PNTOBJECT *ppNtDestObjects, PDWORD pdwNumValues, PDWORD pdwSyntaxId );