/*++ Copyright (c) 1997 Microsoft Corporation Module Name: utils2.c Abstract: utillities to update lnk/msi/... file Author: Xiaofeng Zang (xiaoz) 08-Oct-2001 Created Revision History: --*/ #define NOT_USE_SAFE_STRING #include "clmt.h" #include #include #include #include #include #include #include #define STRSAFE_LIB #include class CServiceHandle { public : CServiceHandle() { _h = 0; } CServiceHandle( SC_HANDLE hSC ) : _h( hSC ) {} ~CServiceHandle() { Free(); } void Set( SC_HANDLE h ) { _h = h; } SC_HANDLE Get() { return _h; } BOOL IsNull() { return ( 0 == _h ); } void Free() { if ( 0 != _h ) CloseServiceHandle( _h ); _h = 0; } private: SC_HANDLE _h; }; //+------------------------------------------------------------------------- // // Function: IsServiceRunning // // Synopsis: Determines if a service is running // // Arguments: pwcServiceName -- The name (short or long) of the service // // Returns: TRUE if the service is running, FALSE otherwise or if the // system is low on resources or the status can't be queried. // // History: 3/22/2002 geoffguo Created // //-------------------------------------------------------------------------- BOOL IsServiceRunning(LPCTSTR pwcServiceName) { CServiceHandle xhSC( OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS ) ); if ( xhSC.IsNull() ) return FALSE; CServiceHandle xhService( OpenService( xhSC.Get(), pwcServiceName, SERVICE_QUERY_STATUS ) ); if ( xhSC.IsNull() ) return FALSE; SERVICE_STATUS svcStatus; if ( QueryServiceStatus( xhService.Get(), &svcStatus ) ) return ( SERVICE_RUNNING == svcStatus.dwCurrentState ); return FALSE; } HRESULT AddNeedUpdateLnkFile( LPTSTR pszShortcutFile, PREG_STRING_REPLACE lpStrList) { HRESULT hr; IShellLink *psl = NULL; TCHAR szGotPath [MAX_PATH]; TCHAR szNewPath [2*MAX_PATH]; TCHAR szArg[INFOTIPSIZE+1],szNewArg[2*INFOTIPSIZE+1]; WIN32_FIND_DATA wfd; IPersistFile *ppf = NULL; int nIcon; LPTSTR lpszOneline = NULL; size_t cchOneline = 0; TCHAR szIndex[MAX_PATH]; LPTSTR lpszAppend = TEXT(""); BOOL bLnkUpdated = FALSE; BOOL bTargetGot = FALSE; BOOL bTargetUpdated = FALSE; DWORD dwAttrib; LPTSTR lpszStrWithExtraQuote; if (!pszShortcutFile || !pszShortcutFile[0] || !lpStrList) { hr = S_FALSE; DPF (INFwar,TEXT("AddNeedUpdateLnkFile: InValid Parameter(s)")); goto Cleanup; } //Allocate memory for "LnkFile,TargetPath,IconPath,Working Dir,Relative Path and Argument" cchOneline = lstrlen(pszShortcutFile) + 5 * MAX_PATH + INFOTIPSIZE+1; if (!(lpszOneline = (LPTSTR)malloc(cchOneline * sizeof(TCHAR)))) { hr = E_OUTOFMEMORY; goto Cleanup; } // Get a pointer to the IShellLink interface. hr = CoCreateInstance (CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl); if (FAILED (hr)) { DPF (INFwar,TEXT("AddNeedUpdateLnkFile: CoCreateInstance CLSID_ShellLink return %d (%#x)\n"), hr, hr); goto Cleanup; } // Get a pointer to the IPersistFile interface. hr = psl->QueryInterface (IID_IPersistFile, (void **)&ppf); if (FAILED(hr)) { DPF (INFwar,TEXT("AddNeedUpdateLnkFile: QueryInterface IID_IPersistFile return %d (%#x)\n"), hr, hr); goto Cleanup; } // Load the shortcut. hr = ppf->Load (pszShortcutFile, STGM_READWRITE ); if (FAILED(hr)) { hr = S_FALSE; DPF (INFwar,TEXT("AddNeedUpdateLnkFile: can not load shortcut file %s"),pszShortcutFile); goto Cleanup; } hr = StringCchPrintf(lpszOneline,cchOneline,TEXT("\"%s\""),pszShortcutFile); if (FAILED(hr)) { DPF (INFwar,TEXT("AddNeedUpdateLnkFile: buffer lpszOneline is too small for %s"),pszShortcutFile); goto Cleanup; } // Get the path to the shortcut target. hr = psl->GetPath (szGotPath, ARRAYSIZE(szGotPath), (WIN32_FIND_DATA *)&wfd, SLGP_RAWPATH); if (SUCCEEDED (hr)) { //Succeeded get the target DWORD dwNum ; DPF (INFinf,TEXT("AddNeedUpdateLnkFile: GetPath %s OK "), szGotPath); //Set bTargetGot so that it cab be used to set relative target path bTargetGot = TRUE; //szGotPath contains LNK's target path, if dwNum >0 , it means szGotPath //contains (localized) path that we renamed dwNum = GetMaxMatchNum(szGotPath,lpStrList); //call ReplaceMultiMatchInString ,to replace szGotPath's localized folder //with english one, and put new path in szNewPath if (dwNum && ReplaceMultiMatchInString(szGotPath,szNewPath,ARRAYSIZE(szNewPath),dwNum,lpStrList, &dwAttrib, TRUE)) { lpszAppend = szNewPath; bTargetUpdated = TRUE; bLnkUpdated = TRUE; } } else { DPF (INFwar,TEXT("AddNeedUpdateLnkFile: GetPath %s Error = %d"), szGotPath,hr); } if (MyStrCmpI(lpszAppend,TEXT(""))) { hr = AddExtraQuoteEtc(lpszAppend,&lpszStrWithExtraQuote); if (SUCCEEDED(hr)) { if (lpszStrWithExtraQuote) { lpszAppend = lpszStrWithExtraQuote; } } } else { lpszStrWithExtraQuote = NULL; } //Append the new quoted target path to lpszOneline hr = StringCchPrintf(lpszOneline,cchOneline,TEXT("%s,\"%s\""),lpszOneline,lpszAppend); FreePointer(lpszStrWithExtraQuote); //check StringCchPrintf here, because we want to free lpszStrWithExtraQuote before //we do a jump (if necessary) if (FAILED(hr)) { DPF (INFwar,TEXT("AddNeedUpdateLnkFile: buffer lpszOneline is too small for %s"),lpszAppend); goto Cleanup; } //if we arrive here , we have succeeded in appeneding target to the lszOneline //we will update relative target path ,which is relative to where the current //lnk resides lpszAppend = TEXT(""); if (bTargetGot) //this means we succeeded get the target path { DWORD dwNum ; //szNewLnkFilePath is the lnk full path with localized folder renamed to english one(if any) TCHAR szNewLnkFilePath[2*MAX_PATH],szCurrTarget[2*MAX_PATH]; TCHAR szExpandedCurrTarget[2*MAX_PATH]; TCHAR szNewTarget[2*MAX_PATH]; //Check to see whether current pszShortcutFile resides a direcory that contains //localized folder we renamed dwNum = GetMaxMatchNum(pszShortcutFile,lpStrList); if (dwNum) { if (!ReplaceMultiMatchInString(pszShortcutFile,szNewLnkFilePath, ARRAYSIZE(szNewLnkFilePath),dwNum,lpStrList, &dwAttrib, TRUE)) { //szNewLnkFilePath now is full path with localized folder renamed to english one //if we fail do ReplaceMultiMatchInString, just clone to szNewLnkFilePath hr = StringCchCopy(szNewLnkFilePath,ARRAYSIZE(szNewLnkFilePath),pszShortcutFile); if (FAILED(hr)) { DPF (INFwar,TEXT("AddNeedUpdateLnkFile: buffer szNewLnkFilePath is too small for %s"),pszShortcutFile); goto Cleanup; } } } else { //If pszShortcutFile does not contains any localized folder we renamed, //just clone to szNewLnkFilePath hr = StringCchCopy(szNewLnkFilePath,ARRAYSIZE(szNewLnkFilePath),pszShortcutFile); if (FAILED(hr)) { DPF (INFwar,TEXT("AddNeedUpdateLnkFile: buffer szNewLnkFilePath is too small for %s"),pszShortcutFile); goto Cleanup; } } if (bTargetUpdated) { if (FAILED(hr = StringCchCopy(szCurrTarget,ARRAYSIZE(szCurrTarget),szNewPath))) { goto Cleanup; } } else { if (FAILED(hr = StringCchCopy(szCurrTarget,ARRAYSIZE(szCurrTarget),szGotPath))) { goto Cleanup; } } //target may contains enviroment variable if (!ExpandEnvironmentStrings(szCurrTarget,szExpandedCurrTarget,ARRAYSIZE(szExpandedCurrTarget))) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Cleanup; } //Check whether target contains the folder we renamed dwNum = GetMaxMatchNum(szExpandedCurrTarget,lpStrList); if (dwNum) { if (!ReplaceMultiMatchInString(szExpandedCurrTarget,szNewTarget,ARRAYSIZE(szNewTarget),dwNum,lpStrList, &dwAttrib, TRUE)) { hr = StringCchCopy(szNewTarget,ARRAYSIZE(szNewTarget),szExpandedCurrTarget); if (FAILED(hr)) { DPF (INFwar,TEXT("AddNeedUpdateLnkFile: buffer szNewTarget is too small for %s"),szExpandedCurrTarget); goto Cleanup; } } } else { hr = StringCchCopy(szNewTarget,ARRAYSIZE(szNewTarget),szExpandedCurrTarget); if (FAILED(hr)) { DPF (INFwar,TEXT("AddNeedUpdateLnkFile: buffer szNewTarget is too small for %s"),szExpandedCurrTarget); goto Cleanup; } } if (PathRelativePathTo(szNewPath,szNewLnkFilePath,0,szNewTarget,0)) { lpszAppend = szNewPath; bLnkUpdated = TRUE; } } if (MyStrCmpI(lpszAppend,TEXT(""))) { hr = AddExtraQuoteEtc(lpszAppend,&lpszStrWithExtraQuote); if (SUCCEEDED(hr)) { if (lpszStrWithExtraQuote) { lpszAppend = lpszStrWithExtraQuote; } } } else { lpszStrWithExtraQuote = NULL; } hr = StringCchPrintf(lpszOneline,cchOneline,TEXT("%s,\"%s\""),lpszOneline,lpszAppend); FreePointer(lpszStrWithExtraQuote); if (FAILED(hr)) { goto Cleanup; } lpszAppend = TEXT(""); hr = psl->GetIconLocation (szGotPath,ARRAYSIZE(szGotPath),&nIcon); if (SUCCEEDED (hr)) { DWORD dwNum ; DPF (INFinf,TEXT("AddNeedUpdateLnkFile: GetIconPath %s OK "), szGotPath); dwNum = GetMaxMatchNum(szGotPath,lpStrList); if (dwNum && ReplaceMultiMatchInString(szGotPath,szNewPath,ARRAYSIZE(szNewPath),dwNum,lpStrList, &dwAttrib, TRUE)) { lpszAppend = szNewPath; bLnkUpdated = TRUE; } } else { DPF (INFwar,TEXT("AddNeedUpdateLnkFile: GetIconPath %s Error = %d"), szGotPath,hr); } if (MyStrCmpI(lpszAppend,TEXT(""))) { hr = AddExtraQuoteEtc(lpszAppend,&lpszStrWithExtraQuote); if (SUCCEEDED(hr)) { if (lpszStrWithExtraQuote) { lpszAppend = lpszStrWithExtraQuote; } } } else { lpszStrWithExtraQuote = NULL; } hr = StringCchPrintf(lpszOneline,cchOneline,TEXT("%s,\"%s\""),lpszOneline,lpszAppend); FreePointer(lpszStrWithExtraQuote); if (FAILED(hr)) { goto Cleanup; } lpszAppend = TEXT(""); hr = psl->GetWorkingDirectory (szGotPath,ARRAYSIZE(szGotPath)); if (SUCCEEDED (hr)) { DWORD dwNum ; DPF (INFinf,TEXT("AddNeedUpdateLnkFile: GetWorkingDirPath %s OK "), szGotPath); dwNum = GetMaxMatchNum(szGotPath,lpStrList); if (dwNum && ReplaceMultiMatchInString(szGotPath,szNewPath,ARRAYSIZE(szNewPath),dwNum,lpStrList, &dwAttrib, TRUE)) { bLnkUpdated = TRUE; lpszAppend = szNewPath; } } else { DPF (INFwar,TEXT("AddNeedUpdateLnkFile: GetWorkingDirPath %s Error = %d"), szGotPath,hr); } if (MyStrCmpI(lpszAppend,TEXT(""))) { hr = AddExtraQuoteEtc(lpszAppend,&lpszStrWithExtraQuote); if (SUCCEEDED(hr)) { if (lpszStrWithExtraQuote) { lpszAppend = lpszStrWithExtraQuote; } } } else { lpszStrWithExtraQuote = NULL; } hr = StringCchPrintf(lpszOneline,cchOneline,TEXT("%s,\"%s\""),lpszOneline,lpszAppend); FreePointer(lpszStrWithExtraQuote); if (FAILED(hr)) { goto Cleanup; } lpszAppend = TEXT(""); hr = psl->GetArguments (szArg,ARRAYSIZE(szArg)); if (SUCCEEDED (hr)) { DWORD dwNum ; DPF (INFinf,TEXT("AddNeedUpdateLnkFile: GetArguments %s OK "), szArg); dwNum = GetMaxMatchNum(szArg,lpStrList); if (dwNum && ReplaceMultiMatchInString(szArg,szNewArg,ARRAYSIZE(szNewArg),dwNum,lpStrList, &dwAttrib, TRUE)) { bLnkUpdated = TRUE; lpszAppend = szNewArg; } } else { DPF (INFwar,TEXT("AddNeedUpdateLnkFile: GetArguments %s Error = %d"), pszShortcutFile,hr); } if (MyStrCmpI(lpszAppend,TEXT(""))) { hr = AddExtraQuoteEtc(lpszAppend,&lpszStrWithExtraQuote); if (SUCCEEDED(hr)) { if (lpszStrWithExtraQuote) { lpszAppend = lpszStrWithExtraQuote; } } } else { lpszStrWithExtraQuote = NULL; } hr = StringCchPrintf(lpszOneline,cchOneline,TEXT("%s,\"%s\""),lpszOneline,lpszAppend); FreePointer(lpszStrWithExtraQuote); if (FAILED(hr)) { goto Cleanup; } if (bLnkUpdated) { g_dwKeyIndex++; _itot(g_dwKeyIndex,szIndex,16); if (!WritePrivateProfileString(TEXT("LNK"),szIndex,lpszOneline,g_szToDoINFFileName)) { hr = HRESULT_FROM_WIN32(GetLastError()); } else { hr = S_OK; } } else { hr = S_OK; } Cleanup: if (psl) { psl->Release (); } if (ppf) { ppf->Release (); } FreePointer(lpszOneline); return hr; } HRESULT BatchFixPathInLink( HINF hInf, LPTSTR lpszSection) { HRESULT hr; IShellLink *psl = NULL; WIN32_FIND_DATA wfd; IPersistFile *ppf = NULL; int nIcon; BOOL bSucceedOnce = FALSE; UINT LineCount,LineNo; INFCONTEXT InfContext; LPTSTR lpszLnkFile = NULL,lpszPath = NULL,lpszIcon = NULL,lpszWorkingDir = NULL, lpszRelPath = NULL,lpszArg = NULL; DWORD cchMaxLnkFile = 0,cchMaxPath = 0,cchMaxIcon = 0,cchMaxWorkingDir = 0, cchMaxRelPath = 0,cchMaxArg = 0; DWORD dwFileAttrib; BOOL bFileAttribChanged ; if ((hInf == INVALID_HANDLE_VALUE) || !lpszSection) { hr = E_INVALIDARG; goto Cleanup; } LineCount = (UINT)SetupGetLineCount(hInf,lpszSection); if ((LONG)LineCount <= 0) { hr = S_FALSE; DPF(INFwar ,TEXT("section name %s is empty failed !"),lpszSection); goto Cleanup; } for(LineNo=0; LineNoQueryInterface (IID_IPersistFile, (void **)&ppf); if (FAILED(hr)) { ppf = NULL; goto Cleanup; } for(LineNo=0; LineNoLoad (lpszLnkFile, STGM_READWRITE ); if (FAILED(hr)) { //but put a waring log here continue; } if (lpszPath && lpszPath[0]) { hr = psl->SetPath (lpszPath); if (SUCCEEDED(hr)) { bSucceededOnce = TRUE; } } if (lpszRelPath && lpszRelPath[0]) { hr = psl->SetRelativePath(lpszRelPath,0); if (SUCCEEDED(hr)) { bSucceededOnce = TRUE; } } if (lpszIcon && lpszIcon[0]) { TCHAR szGotPath[MAX_PATH]; hr = psl->GetIconLocation (szGotPath,ARRAYSIZE(szGotPath),&nIcon); if (SUCCEEDED(hr)) { hr = psl->SetIconLocation (lpszIcon,nIcon); if (SUCCEEDED(hr)) { bSucceededOnce = TRUE; } } } if (lpszWorkingDir && lpszWorkingDir[0]) { hr = psl->SetWorkingDirectory (lpszWorkingDir); if (SUCCEEDED(hr)) { bSucceededOnce = TRUE; } } if (lpszArg && lpszArg[0]) { hr = psl->SetArguments (lpszArg); if (SUCCEEDED(hr)) { bSucceededOnce = TRUE; } } if (bSucceededOnce) { hr = ppf->Save (lpszLnkFile,TRUE); if (! SUCCEEDED (hr)) { DPF (dlError,TEXT("FixPathInLink: Save %s Error = %d"), lpszLnkFile,hr); } else { DPF (dlInfo,TEXT("FixPathInLink: Save %s OK = %d"), lpszLnkFile,hr); } } if (bFileAttribChanged) { SetFileAttributes (lpszLnkFile, dwFileAttrib); } } hr = S_OK; Cleanup: if (psl) { psl->Release (); } if (ppf) { ppf->Release (); } FreePointer(lpszPath); FreePointer(lpszIcon); FreePointer(lpszRelPath); FreePointer(lpszWorkingDir); FreePointer(lpszArg); FreePointer(lpszLnkFile); return hr; } HRESULT RenameRDN( LPTSTR lpContainerPathWithLDAP, LPTSTR lpOldFQDNWithLDAP, LPTSTR lpNewRDNWithCN ) { HRESULT hr; IADsContainer *pContainer = NULL; IDispatch *pDispatch = NULL; BSTR bstrOldFQDNWithLDAP = SysAllocString(lpOldFQDNWithLDAP); BSTR bstrNewRDNWithCN = SysAllocString(lpNewRDNWithCN); if (!bstrOldFQDNWithLDAP || !bstrNewRDNWithCN ) { hr = E_OUTOFMEMORY; goto Cleanup; } hr = ADsGetObject(lpContainerPathWithLDAP, IID_IADsContainer, (VOID **) &pContainer); if (SUCCEEDED(hr)) { // Rename the RDN here hr = pContainer->MoveHere(bstrOldFQDNWithLDAP, bstrNewRDNWithCN, &pDispatch); if (SUCCEEDED(hr)) { pDispatch->Release(); } pContainer->Release(); } Cleanup: if (bstrOldFQDNWithLDAP) { SysFreeString(bstrOldFQDNWithLDAP); } if (bstrNewRDNWithCN) { SysFreeString(bstrNewRDNWithCN); } return hr; } // Pass in the interface ptr to the property value // will return a BSTR value of the data. // The IADsPropertyValue::get_ADsType() is called to retrieve the // ADSTYPE valued enum // This enum is then used to determine which IADsPropertyValue method // to call to receive the actual data // CALLER assumes responsibility for freeing returned BSTR HRESULT GetIADsPropertyValueAsBSTR(BSTR * pbsRet,IADsPropertyEntry *pAdsEntry, IADsPropertyValue * pAdsPV) { HRESULT hr = S_OK; long lAdsType; hr = pAdsPV->get_ADsType(&lAdsType); if (FAILED(hr)) return hr; switch (lAdsType) { case ADSTYPE_INVALID : { *pbsRet = SysAllocString(L""); } break; case ADSTYPE_DN_STRING : { hr = pAdsPV->get_DNString(pbsRet); } break; case ADSTYPE_CASE_EXACT_STRING : { hr = pAdsPV->get_CaseExactString(pbsRet); } break; case ADSTYPE_CASE_IGNORE_STRING : { hr = pAdsPV->get_CaseIgnoreString(pbsRet); } break; case ADSTYPE_PRINTABLE_STRING : { hr = pAdsPV->get_PrintableString(pbsRet); } break; case ADSTYPE_NUMERIC_STRING : { hr = pAdsPV->get_NumericString(pbsRet); } break; case ADSTYPE_BOOLEAN : { long b; hr = pAdsPV->get_Boolean(&b); if (SUCCEEDED(hr)) { if (b) *pbsRet = SysAllocString(L""); else *pbsRet = SysAllocString(L""); } } break; case ADSTYPE_INTEGER : { long lInt; hr = pAdsPV->get_Integer(&lInt); if (SUCCEEDED(hr)) { WCHAR wOut[100]; hr = StringCchPrintf(wOut,ARRAYSIZE(wOut),L"%d",lInt); *pbsRet = SysAllocString(wOut); } } break; case ADSTYPE_OCTET_STRING : { *pbsRet = SysAllocString(L""); BSTR bsName= NULL; VARIANT vOctet; DWORD dwSLBound; DWORD dwSUBound; void HUGEP *pArray; VariantInit(&vOctet); //Get the name of the property to handle //the properties we're interested in. pAdsEntry->get_Name(&bsName); hr = pAdsPV->get_OctetString(&vOctet); //Get a pointer to the bytes in the octet string. if (SUCCEEDED(hr)) { hr = SafeArrayGetLBound( V_ARRAY(&vOctet), 1, (long FAR *) &dwSLBound ); hr = SafeArrayGetUBound( V_ARRAY(&vOctet), 1, (long FAR *) &dwSUBound ); if (SUCCEEDED(hr)) { hr = SafeArrayAccessData( V_ARRAY(&vOctet), &pArray ); if (FAILED(hr)) { break; } } else { break; } /* Since an Octet String has a specific meaning depending on the attribute name, handle two common ones here */ if (0==wcscmp(L"objectGUID", bsName)) { //LPOLESTR szDSGUID = new WCHAR [39]; WCHAR szDSGUID[39]; //Cast to LPGUID LPGUID pObjectGUID = (LPGUID)pArray; //Convert GUID to string. ::StringFromGUID2(*pObjectGUID, szDSGUID, 39); *pbsRet = SysAllocString(szDSGUID); } else if (0==wcscmp(L"objectSid", bsName)) { PSID pObjectSID = (PSID)pArray; //Convert SID to string. LPOLESTR szSID = NULL; ConvertSidToStringSid(pObjectSID, &szSID); *pbsRet = SysAllocString(szSID); LocalFree(szSID); } else { *pbsRet = SysAllocString(L""); } SafeArrayUnaccessData( V_ARRAY(&vOctet) ); VariantClear(&vOctet); } SysFreeString(bsName); } break; case ADSTYPE_LARGE_INTEGER : { *pbsRet = SysAllocString(L""); } break; case ADSTYPE_PROV_SPECIFIC : { *pbsRet = SysAllocString(L""); } break; case ADSTYPE_OBJECT_CLASS : { hr = pAdsPV->get_CaseIgnoreString(pbsRet); } break; case ADSTYPE_PATH : { hr = pAdsPV->get_CaseIgnoreString(pbsRet); } break; case ADSTYPE_NT_SECURITY_DESCRIPTOR : { *pbsRet = SysAllocString(L""); } break; default: *pbsRet = SysAllocString(L""); break; } return hr; } HRESULT PropertyValueHelper( LPTSTR lpObjPathWithLDAP, LPTSTR lpPropName, LPTSTR *lplpValue, LPTSTR lpNewValue) { IADsPropertyList *pList = NULL; IADsPropertyEntry *pEntry = NULL; IADs *pObj = NULL; VARIANT var,varEnrty; long valType = ADSTYPE_PATH; HRESULT hr; BSTR bstrPropName = NULL; BSTR bstrNewValue = NULL; // bind to directory object hr = ADsGetObject(lpObjPathWithLDAP, IID_IADsPropertyList, (void**)&pList); if (S_OK != hr) { pList = NULL; goto exit; } // initialize the property cache hr = pList->QueryInterface(IID_IADs,(void**)&pObj); if (S_OK != hr) { pObj = NULL; goto exit; } pObj->GetInfo(); // get a property entry VariantInit(&varEnrty); bstrPropName = SysAllocString(lpPropName); if (!bstrPropName) { hr = E_OUTOFMEMORY; goto exit; } hr = pList->GetPropertyItem(bstrPropName, valType, &varEnrty); hr = V_DISPATCH(&varEnrty)->QueryInterface(IID_IADsPropertyEntry, (void**)&pEntry); if (S_OK != hr) { pEntry = NULL; goto exit; } VariantInit(&var); hr = pEntry->get_Values(&var); if (S_OK != hr) { goto exit; } LONG dwSLBound = 0; LONG dwSUBound = 0; LONG i; hr = SafeArrayGetLBound(V_ARRAY(&var),1,(long FAR *)&dwSLBound); if (S_OK != hr) { goto exit; } hr = SafeArrayGetUBound(V_ARRAY(&var),1,(long FAR *)&dwSUBound); if (S_OK != hr) { goto exit; } if (dwSLBound || dwSLBound) { //we only interested in one enrty goto exit; } VARIANT v; VariantInit(&v); i = 0; hr = SafeArrayGetElement(V_ARRAY(&var),(long FAR *)&i,&v); if (FAILED(hr)) { goto exit; } IDispatch * pDispEntry = V_DISPATCH(&v); IADsPropertyValue * pAdsPV = NULL; hr = pDispEntry->QueryInterface(IID_IADsPropertyValue,(void **) &pAdsPV); if (SUCCEEDED(hr)) { BSTR bValue; // Get the value as a BSTR hr = GetIADsPropertyValueAsBSTR(&bValue,pEntry,pAdsPV); if (hr == S_OK) { if (lplpValue) { *lplpValue = (LPTSTR)malloc( (lstrlen(bValue)+1)*sizeof(TCHAR)); if (!*lplpValue) { hr = E_OUTOFMEMORY; goto exit; } hr = StringCchCopy(*lplpValue,lstrlen(bValue)+1,bValue); } } } if (lpNewValue) { bstrNewValue = SysAllocString(lpNewValue); if (!bstrNewValue) { hr = E_OUTOFMEMORY; goto exit; } hr = pAdsPV->put_CaseIgnoreString(bstrNewValue); } i = 0; hr = SafeArrayPutElement(V_ARRAY(&var),&i,&v); if (hr != S_OK) { goto exit; } hr = pEntry->put_ControlCode(ADS_PROPERTY_UPDATE); hr = pEntry->put_Values(var); pList->PutPropertyItem(varEnrty); pObj->SetInfo(); hr = S_OK; exit:; if (bstrPropName) { SysFreeString(bstrPropName); } if (bstrNewValue) { SysFreeString(bstrNewValue); } if (pEntry) { pEntry->Release(); } if (pObj) { pObj->Release(); } if (pList) { pList->Release(); } return hr; } BOOL UpdateSecurityTemplatesSection ( LPTSTR lpINFFile, LPTSTR lpNewInf, LPTSTR lpszSection, PREG_STRING_REPLACE lpStrList) { HRESULT hr = S_OK; DWORD cchInSection, CchBufSize, cchOutputSize, cchBufLen; DWORD dwAttrib; BOOL bUpdated = FALSE; LPTSTR lpBuf = NULL; LPTSTR lpNewBuf, lpOldBuf, lpLineBuf, lpEnd, lpOutputBuf, lpTemp; if (lpINFFile && lpszSection) { // // allocate max size of buffer // CchBufSize = 0x7FFFF; do { if (lpBuf) { MEMFREE(lpBuf); CchBufSize *= 2; } lpBuf = (LPTSTR) MEMALLOC(CchBufSize * sizeof(TCHAR)); if (!lpBuf) { hr = E_OUTOFMEMORY; goto Exit; } cchInSection = GetPrivateProfileSection(lpszSection, lpBuf, CchBufSize, lpINFFile); } while (cchInSection == CchBufSize -2); lpEnd = lpBuf; lpOutputBuf = NULL; cchOutputSize = 0; bUpdated = FALSE; while(lpEnd < (lpBuf + cchInSection)) { dwAttrib = 0; lpNewBuf = ReplaceSingleString ( lpEnd, REG_SZ, lpStrList, NULL, &dwAttrib, TRUE); if (!lpNewBuf) { lpNewBuf = ReplaceSingleString ( lpEnd, REG_SZ, lpStrList, NULL, &dwAttrib, FALSE); } if (!lpNewBuf) { lpLineBuf = lpEnd; } else { bUpdated = TRUE; lpLineBuf = lpNewBuf; if (StrStrI(lpEnd, L"ProgramFiles") && StrStrI(lpNewBuf, L"Programs")) { //Correct the wrong string replacement //the difference between "Programs" and "Program Files" is " File" CchBufSize = lstrlen(lpEnd)+6; free(lpNewBuf); lpNewBuf = (LPTSTR)calloc(CchBufSize, sizeof(TCHAR)); if (lpNewBuf) { lpTemp = StrStrI(lpEnd, L"="); if (lpTemp) { *lpTemp = (TCHAR)'\0'; hr = StringCchCopy(lpNewBuf, CchBufSize, lpEnd); *lpTemp = (TCHAR)'='; hr = StringCchCat(lpNewBuf, CchBufSize, L"= Program Files"); lpLineBuf = lpNewBuf; if (hr != S_OK) DPF(REGerr, L"UpdateSecurityTemplatesSection: StringCchCat failed."); } else { free(lpNewBuf); lpLineBuf = lpEnd; lpNewBuf = NULL; bUpdated = FALSE; } } else { hr = E_OUTOFMEMORY; goto Exit; } } } cchBufLen = lstrlen(lpLineBuf); lpOldBuf = NULL; if (lpOutputBuf) { lpOldBuf = lpOutputBuf; lpOutputBuf = (LPTSTR)MEMREALLOC(lpOldBuf, (cchOutputSize+cchBufLen+2)*sizeof(TCHAR)); } else { lpOutputBuf = (LPTSTR)MEMALLOC((cchBufLen+2)*sizeof(TCHAR)); cchOutputSize = 0; } if (lpOutputBuf == NULL) { if (lpOldBuf) MEMFREE(lpOldBuf); if (lpBuf) MEMFREE(lpBuf); if (lpNewBuf) free(lpNewBuf); hr = E_OUTOFMEMORY; goto Exit; } hr = StringCchCopy(&lpOutputBuf[cchOutputSize], cchBufLen+1, lpLineBuf); if (hr != S_OK) DPF(REGerr, L"UpdateSecurityTemplatesSection3: failed."); cchOutputSize += cchBufLen+1; lpEnd += lstrlen(lpEnd)+1; if (lpNewBuf) free(lpNewBuf); } if (lpOutputBuf) lpOutputBuf[cchOutputSize] = (TCHAR)'\0'; //Workarround since the function cannot delete the section: Delete the section WritePrivateProfileSection (lpszSection, NULL, lpNewInf); if (!WritePrivateProfileSection (lpszSection, lpOutputBuf, lpNewInf)) { DPF(INFerr, L"UpdateSecurityTemplatesSection: the section %s in file %s Update failed", lpszSection, lpNewInf); } if (lpOutputBuf) MEMFREE(lpOutputBuf); if (lpBuf) MEMFREE(lpBuf); } Exit: return bUpdated; } HRESULT UpdateSecurityTemplates( LPTSTR lpINFFile, PREG_STRING_REPLACE lpStrList) { HRESULT hr = E_FAIL; DWORD cchRead; DWORD cchBuf = 1024; LPTSTR lpBuf, lpOldBuf; LPTSTR lpSection; BOOL bUpdate; TCHAR szIndex[16]; TCHAR szNewInf[MAX_PATH]; DPF(REGmsg, L"Enter UpdateSecurityTemplates: %s", lpINFFile); lpBuf = (LPTSTR)MEMALLOC(cchBuf * sizeof(TCHAR)); if (lpBuf == NULL) { return E_OUTOFMEMORY; } cchRead = GetPrivateProfileSectionNames(lpBuf, cchBuf, lpINFFile); while (cchRead == (cchBuf - 2)) { // Buffer is too small, reallocate until we have enough lpOldBuf = lpBuf; cchBuf += 1024; lpBuf = (LPTSTR)MEMREALLOC(lpOldBuf, cchBuf * sizeof(TCHAR)); if (lpBuf == NULL) { MEMFREE(lpOldBuf); return E_OUTOFMEMORY; } // Read the data from section again cchRead = GetPrivateProfileSectionNames(lpBuf, cchBuf, lpINFFile); } // At this point we have big enough buffer and data in it if (cchRead > 0) { hr = StringCchPrintf(szNewInf, MAX_PATH, TEXT("%s.clmt"), lpINFFile); CopyFile(lpINFFile, szNewInf, FALSE); lpSection = (LPTSTR)MultiSzTok(lpBuf); bUpdate = FALSE; while (lpSection != NULL) { if (UpdateSecurityTemplatesSection(lpINFFile, szNewInf, lpSection, lpStrList)) { bUpdate = TRUE; DPF(INFmsg, L"UpdateSecurityTemplatesSection: the section %s in file %s Updated", lpSection, lpINFFile); } // Get next section name lpSection = (LPTSTR)MultiSzTok(NULL); } if (bUpdate) { g_dwKeyIndex++; _itot(g_dwKeyIndex,szIndex,16); if (!WritePrivateProfileString(TEXT("INF Update"),szIndex,szNewInf,g_szToDoINFFileName)) { hr = HRESULT_FROM_WIN32(GetLastError()); } } } else { SetLastError(ERROR_NOT_FOUND); } MEMFREE(lpBuf); DPF(REGmsg, L"Exit UpdateSecurityTemplates:"); return hr; } HRESULT BatchINFUpdate(HINF hInf) { HRESULT hr = S_OK; UINT LineCount,LineNo; DWORD dwRequired; INFCONTEXT InfContext; LPTSTR lpTemp; LPTSTR lpszSection = TEXT("INF Update"); TCHAR chTemp; TCHAR szFileNameIn[MAX_PATH]; TCHAR szFileNameOut[MAX_PATH]; DPF(INFmsg ,TEXT("Enter BatchINFUpdate:")); if ((hInf == INVALID_HANDLE_VALUE)) { hr = E_INVALIDARG; goto Exit; } LineCount = (UINT)SetupGetLineCount(hInf,lpszSection); if ((LONG)LineCount <= 0) { hr = S_FALSE; DPF(INFwar ,TEXT("BatchINFUpdate: failed. Section %s is empty!"),lpszSection); goto Exit; } for(LineNo=0; LineNo