Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2393 lines
46 KiB

#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;
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);
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];
HRESULT hr;
POBJECTINFO pObjectInfo = NULL;
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,
CCredentials &Credentials
)
{
switch (dwObjectType) {
case NWCOMPAT_USER_ID:
RRETURN(ValidateUserObject(pObjectInfo, Credentials));
case NWCOMPAT_GROUP_ID:
RRETURN(ValidateGroupObject(pObjectInfo, Credentials));
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;
SYSTEMTIME LocalTime;
//
// Get Time-zone specific local time.
//
fRetval = SystemTimeToTzSpecificLocalTime(
NULL,
&Time,
&LocalTime
);
if(!fRetval){
RRETURN(HRESULT_FROM_WIN32(GetLastError()));
}
//
// System Time To File Time.
//
fRetval = SystemTimeToFileTime(&LocalTime,
&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;
FILETIME lft; //local file time
BOOL fRetval = FALSE;
SYSTEMTIME LocalTime;
USHORT wDosDate;
USHORT wDosTime;
fRetval = VariantTimeToDosDateTime(daDate,
&wDosDate,
&wDosTime );
if(!fRetval){
hr = HRESULT_FROM_WIN32(GetLastError());
RRETURN(hr);
}
fRetval = DosDateTimeToFileTime(wDosDate,
wDosTime,
&lft);
if(!fRetval){
hr = HRESULT_FROM_WIN32(GetLastError());
RRETURN(hr);
}
//
// convert local file time to filetime
//
fRetval = LocalFileTimeToFileTime(&lft,
&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
ConvertNW312DateToSYSTEMTIME(
BYTE byDateTime[],
SYSTEMTIME *pSysTime
)
{
HRESULT hr = S_OK;
WORD wYear;
//
// Subtract 80 from wYear for NWApiMakeSYSTEMTIME.
//
wYear = (WORD)byDateTime[0];
if (wYear != 0) {
wYear -= 80;
}
//
// Convert into SYSTEMTIME.
//
hr = NWApiMakeSYSTEMTIME(
pSysTime,
(WORD)byDateTime[2],
(WORD)byDateTime[1],
wYear,
0,0,0
);
RRETURN(hr);
}
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;
BSTR bstrElement = 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;
hr = SafeArrayGetElement(psa, &lIndices, &vElement);
BAIL_ON_FAILURE(hr);
if(!(V_VT(&vElement) == VT_BSTR)){
RRETURN(E_FAIL);
}
//
// unpack the BSTR in the VARIANT
//
hr = ADsAllocString( vElement.bstrVal, &bstrElement);
BAIL_ON_FAILURE(hr);
ulRequiredLength+= wcslen(bstrElement)+1;
}
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;
hr = SafeArrayGetElement(psa, &lIndices, &vElement);
BAIL_ON_FAILURE(hr);
if(!(V_VT(&vElement) == VT_BSTR)){
RRETURN(E_FAIL);
}
//
// unpack the BSTR in the VARIANT
//
hr = ADsAllocString( vElement.bstrVal, &bstrElement);
wcscpy(pszCurrPos, (LPTSTR)bstrElement);
pszCurrPos += wcslen(bstrElement);
if(i < cElements-1){
*pszCurrPos = Delimiter;
}
pszCurrPos++;
ADsFreeString(bstrElement);
}
*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;
BSTR bstrElement = NULL;
VARIANT vElement;
LPTSTR szCurrPos = NULL;
HRESULT hr = S_OK;
ULONG i;
//
//converts the safearray in a variant to a double nulled 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;
BAIL_ON_FAILURE(hr);
}
//
// We know that this is a valid single dimension array
//
lIndices= 0;
for(i=0; i< cElements; i++){
lIndices = i;
hr = SafeArrayGetElement(psa, &lIndices, &vElement);
BAIL_ON_FAILURE(hr);
if(!(V_VT(&vElement) == VT_BSTR)){
RRETURN(E_FAIL);
}
//
// unpack the BSTR in the VARIANT
//
hr = ADsAllocString( vElement.bstrVal, &bstrElement);
BAIL_ON_FAILURE(hr);
ulRequiredLength+= wcslen(bstrElement)+1;
ADsFreeString(bstrElement);
}
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;
hr = SafeArrayGetElement(psa, &lIndices, &vElement);
BAIL_ON_FAILURE(hr);
if(!(V_VT(&vElement) == VT_BSTR)){
RRETURN(E_FAIL);
}
//
// unpack the BSTR in the VARIANT
//
hr = ADsAllocString( vElement.bstrVal, &bstrElement);
wcscpy(szCurrPos, (LPTSTR)bstrElement);
szCurrPos += wcslen(bstrElement)+1;
ADsFreeString(bstrElement);
}
*szCurrPos = L'\0';
RRETURN(S_OK);
error:
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,
dwNumValues,
pNtDestObjects
);
//
// 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));
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,
dwNumValues,
pNtDestObjects
);
//
// 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);
//
// We're successful so far, now skip by 1
//
pPropertyCache->skip_propindex(
1
);
error:
if (pNtSrcObjects) {
NTTypeFreeNTObjects(
pNtSrcObjects,
dwNumValues
);
}
RRETURN(hr);
}
HRESULT
GenericSkipPropertyManager(
CPropertyCache * pPropertyCache,
ULONG cElements
)
{
pPropertyCache->skip_propindex(
cElements
);
RRETURN(S_OK);
}
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,
dwNumValues,
pNtDestObjects
);
//
// 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;
//
// retrieve data object from cache; if one exis
//
switch (V_VT(&varIndex)) {
case VT_BSTR:
if (dwObjectState == ADS_OBJECT_UNBOUND) {
hr = pPropertyCache->unboundgetproperty(
V_BSTR(&varIndex),
&dwSyntaxId,
&dwNumValues,
&pNtSrcObjects
);
BAIL_ON_FAILURE(hr);
}else {
hr = pPropertyCache->getproperty(
V_BSTR(&varIndex),
&dwSyntaxId,
&dwNumValues,
&pNtSrcObjects
);
BAIL_ON_FAILURE(hr);
}
hr = ConvertNtValuesToVariant(
V_BSTR(&varIndex),
pNtSrcObjects,
dwNumValues,
pVariant
);
BAIL_ON_FAILURE(hr);
break;
case VT_I4:
hr = pPropertyCache->unboundgetproperty(
V_I4(&varIndex),
&dwSyntaxId,
&dwNumValues,
&pNtSrcObjects
);
BAIL_ON_FAILURE(hr);
szPropName = pPropertyCache->get_PropName(V_I4(&varIndex));
hr = ConvertNtValuesToVariant(
szPropName,
pNtSrcObjects,
dwNumValues,
pVariant
);
BAIL_ON_FAILURE(hr);
break;
case VT_I2:
hr = pPropertyCache->unboundgetproperty(
(DWORD)V_I2(&varIndex),
&dwSyntaxId,
&dwNumValues,
&pNtSrcObjects
);
BAIL_ON_FAILURE(hr);
szPropName = pPropertyCache->get_PropName(V_I2(&varIndex));
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
);
HRESULT
CheckAndSetExtendedError(
DWORD dwRetval
)
{
DWORD dwLastError;
WCHAR pszError[MAX_PATH];
WCHAR pszProviderName[MAX_PATH];
INT numChars;
HRESULT hr =S_OK;
wcscpy(pszError, L"");
wcscpy(pszProviderName, L"");
if (NWCCODE_SUCCESS(dwRetval)){
hr = S_OK;
} else {
hr = HRESULT_FROM_WIN32(ERROR_EXTENDED_ERROR);
numChars = LoadString( g_hInst,
NW_PROVIDER_ID,
pszProviderName,
MAX_PATH -1);
//
// Set the default error string
wsprintf (pszError, L"NW ccode = %x", dwRetval);
ADsSetLastError(
dwRetval,
pszError,
pszProviderName
);
}
RRETURN(hr);
}
HRESULT
InitializeNWLibrary(
void
)
{
NWDSCCODE ccode;
HRESULT hr = S_OK;
LCONV lConvInfo;
ccode = NWCallsInit(NULL, NULL);
CHECK_AND_SET_EXTENDED_ERROR(ccode, hr);
ccode = NWCLXInit(NULL, NULL);
CHECK_AND_SET_EXTENDED_ERROR(ccode, hr);
error:
RRETURN(hr);
}