/*++

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:

    <alias> <date> <comments>

--*/

#define NOT_USE_SAFE_STRING  
#include "clmt.h"
#include <objbase.h>
#include <shellapi.h>
#include <shlguid.h>
#include <comdef.h>
#include <iads.h>
#include <adsiid.h>
#include <adshlp.h>
#define STRSAFE_LIB
#include <strsafe.h>


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; LineNo<LineCount; LineNo++)
    {
        DWORD cchTmpLnkFile = 0,cchTmpPath = 0,cchTmpIcon = 0,cchTmpWorkingDir = 0,
              cchTmpRelPath = 0,cchTmpArg = 0;          
        if (!SetupGetLineByIndex(hInf,lpszSection,LineNo,&InfContext))
        {
            DPF(INFerr ,TEXT("can not get line %n of section %s !"),LineNo, lpszSection);
            hr = E_FAIL;
            goto Cleanup;
        }
        if (!SetupGetStringField(&InfContext,1,NULL,0,&cchTmpLnkFile))
        {
            DPF(INFerr ,TEXT("get [%s] 's line %d 's Field 1 failed  !"),lpszSection, LineNo);
            hr = E_FAIL;
            goto Cleanup;
        }
        if (!SetupGetStringField(&InfContext,2,NULL,0,&cchTmpPath))
        {
            DPF(INFerr ,TEXT("get [%s] 's line %d 's Field 2 failed  !"),lpszSection, LineNo);
            hr = E_FAIL;
            goto Cleanup;
        }
        if (!SetupGetStringField(&InfContext,3,NULL,0,&cchTmpRelPath))
        {
            DPF(INFerr ,TEXT("get [%s] 's line %d 's Field 3 failed  !"),lpszSection, LineNo);
            hr = E_FAIL;
            goto Cleanup;
        }

        if (!SetupGetStringField(&InfContext,4,NULL,0,&cchTmpIcon))
        {
            DPF(INFerr ,TEXT("get [%s] 's line %d 's Field 4 failed  !"),lpszSection, LineNo);
            hr = E_FAIL;
            goto Cleanup;
        }
        if (!SetupGetStringField(&InfContext,5,NULL,0,&cchTmpWorkingDir))
        {
            DPF(INFerr ,TEXT("get [%s] 's line %d 's Field 5 failed  !"),lpszSection, LineNo);
            hr = E_FAIL;
            goto Cleanup;
        }        
        if (!SetupGetStringField(&InfContext,6,NULL,0,&cchTmpArg))
        {
            DPF(INFerr ,TEXT("get [%s] 's line %d 's Field 6 failed  !"),lpszSection, LineNo);
            hr = E_FAIL;
            goto Cleanup;
        }        
        cchMaxLnkFile  = max(cchMaxLnkFile,cchTmpLnkFile);
        cchMaxPath = max(cchMaxPath,cchTmpPath);
        cchMaxIcon = max(cchMaxIcon,cchTmpIcon);
        cchMaxWorkingDir = max(cchMaxWorkingDir,cchTmpWorkingDir);
        cchMaxRelPath = max(cchMaxRelPath,cchTmpRelPath);
        cchMaxArg = max(cchMaxArg,cchTmpArg);
    }
    if (cchMaxLnkFile)
    {
        if (!(lpszLnkFile = (LPTSTR)malloc(++cchMaxLnkFile * sizeof(TCHAR))))
        {
           hr = E_OUTOFMEMORY;
           goto Cleanup;
        }
    }
    if (cchMaxPath)
    {
        if (!(lpszPath = (LPTSTR)malloc(++cchMaxPath * sizeof(TCHAR))))
        {
           hr = E_OUTOFMEMORY;
           goto Cleanup;
        }
    }
    if (cchMaxIcon)
    {
        if (!(lpszIcon = (LPTSTR)malloc(++cchMaxIcon * sizeof(TCHAR))))
        {
           hr = E_OUTOFMEMORY;
           goto Cleanup;
        }
    }
    if (cchMaxWorkingDir)
    {
        if (!(lpszWorkingDir = (LPTSTR)malloc(++cchMaxWorkingDir * sizeof(TCHAR))))
        {
           hr = E_OUTOFMEMORY;
           goto Cleanup;
        }
    }
    if (cchMaxRelPath)
    {
        if (!(lpszRelPath = (LPTSTR)malloc(++cchMaxRelPath * sizeof(TCHAR))))
        {
           hr = E_OUTOFMEMORY;
           goto Cleanup;
        }
    }
    if (cchMaxArg)
    {
        if (!(lpszArg = (LPTSTR)malloc(++cchMaxArg * sizeof(TCHAR))))
        {
           hr = E_OUTOFMEMORY;
           goto Cleanup;
        }
    }

    hr = CoCreateInstance (CLSID_ShellLink,
                           NULL,
                           CLSCTX_INPROC_SERVER,
                           IID_IShellLink,
                           (void **)&psl);

   if (FAILED (hr)) 
   {
       psl = NULL;
       goto Cleanup;
   }
   // Get a pointer to the IPersistFile interface.
   hr = psl->QueryInterface (IID_IPersistFile, (void **)&ppf);
   if (FAILED(hr)) 
   {
       ppf = NULL;
       goto Cleanup;
   }

   for(LineNo=0; LineNo<LineCount; LineNo++)
    {     
        BOOL bSucceededOnce = FALSE;
        SetupGetLineByIndex(hInf,lpszSection,LineNo,&InfContext);
        if (lpszLnkFile)
        {
            SetupGetStringField(&InfContext,1,lpszLnkFile,cchMaxLnkFile,NULL);
        }        
        if (lpszPath)
        {
            SetupGetStringField(&InfContext,2,lpszPath,cchMaxPath,NULL);
        }
        if (lpszRelPath)
        {
            SetupGetStringField(&InfContext,3,lpszRelPath,cchMaxRelPath,NULL);
        }
        if (lpszIcon)
        {
            SetupGetStringField(&InfContext,4,lpszIcon,cchMaxIcon,NULL);
        }        
        if (lpszWorkingDir)
        {
            SetupGetStringField(&InfContext,5,lpszWorkingDir,cchMaxWorkingDir,NULL);
        }
        if (lpszArg)
        {
            SetupGetStringField(&InfContext,6,lpszArg,cchMaxArg,NULL);
        }
        bFileAttribChanged = FALSE;
        dwFileAttrib = GetFileAttributes(lpszLnkFile);
        if (INVALID_FILE_ATTRIBUTES == dwFileAttrib)
        {
            //but put a waring log here
            continue;
        }

        if ( (dwFileAttrib & FILE_ATTRIBUTE_READONLY) 
             ||(dwFileAttrib & FILE_ATTRIBUTE_SYSTEM) )
        {
            if (!SetFileAttributes(lpszLnkFile,FILE_ATTRIBUTE_NORMAL))
            {
                //but put a waring log here
                continue;
            }
            bFileAttribChanged = TRUE;
        }
        hr = ppf->Load (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"<ADSTYPE_INVALID>"); 
        } 
        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"<TRUE>"); 
                else 
                    *pbsRet = SysAllocString(L"<FALSE>"); 
            } 
        } 
        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"<ADSTYPE_OCTET_STRING>"); 
            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"<Value of type Octet String. No Conversion>"); 

                    } 
                        SafeArrayUnaccessData( V_ARRAY(&vOctet) ); 
                        VariantClear(&vOctet); 
                } 

                SysFreeString(bsName); 
                 

        } 
        break; 
        case ADSTYPE_LARGE_INTEGER : 
        { 
            *pbsRet = SysAllocString(L"<ADSTYPE_LARGE_INTEGER>"); 
        } 
        break; 
        case ADSTYPE_PROV_SPECIFIC : 
        { 
            *pbsRet = SysAllocString(L"<ADSTYPE_PROV_SPECIFIC>"); 
        } 
        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"<ADSTYPE_NT_SECURITY_DESCRIPTOR>"); 
        } 
        break; 
     
        default:  
            *pbsRet = SysAllocString(L"<UNRECOGNIZED>"); 
        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<LineCount; LineNo++)
    {
        if (!SetupGetLineByIndex(hInf,lpszSection,LineNo,&InfContext))
        {
            DPF(INFerr ,TEXT("BatchINFUpdate: can not get line %n of section %s !"),LineNo, lpszSection);
            hr = E_FAIL;
            goto Exit;
        }
        if (!SetupGetStringField(&InfContext,1,szFileNameIn,MAX_PATH,&dwRequired))
        {
            DPF(INFerr ,TEXT("BatchINFUpdate: get [%s] 's line %d 's Field 1 failed  !"),lpszSection, LineNo);
            hr = E_FAIL;
            goto Exit;
        }
        lpTemp = StrStrI(szFileNameIn, TEXT(".clmt"));
        if (lpTemp)
        {
            *lpTemp = (TCHAR)'\0';
            hr = StringCchPrintf(szFileNameOut, MAX_PATH, TEXT("%s.bak"), szFileNameIn);
            MoveFile(szFileNameIn, szFileNameOut);
            hr = StringCchCopy(szFileNameOut, MAX_PATH, szFileNameIn);
            *lpTemp = (TCHAR)'.';
            MoveFile(szFileNameIn, szFileNameOut);
            DPF(INFinf ,TEXT("BatchINFUpdate: %s is updated and backup file is %s.bak"), szFileNameOut, szFileNameOut);
        }
    }
    
Exit:
    DPF(INFmsg ,TEXT("Exit BatchINFUpdate: hr = %d"), hr);
    return hr;
}