767 lines
25 KiB
C++
767 lines
25 KiB
C++
/*++
|
||
|
||
Copyright (c) 2000-2002 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
PopulateDefaultHKCUSettings.cpp
|
||
|
||
Abstract:
|
||
|
||
Populate HKCU with default values if they do not exist. Some apps installs HKCU values
|
||
for only the user that ran setup on that app. In this case, if another users tries to use the
|
||
application they will be unable to due to missing HKCU regkeys.
|
||
|
||
To shim around this, we check for the existance of a regkey and if it does not exist, we then read
|
||
a pre-defined .reg file our of our resource section and exec regedit on it to add the necessary
|
||
registry keys. For example:
|
||
|
||
COMMAND_LINE("Software\Lotus\SmartCenter\97.0!SmartCenter97")
|
||
|
||
would mean that if the regkey 'HKCU\Software\Lotus\SmartCenter\97.0' does NOT exist, then we should
|
||
read the named resource 'SmartCenter97' out of our dll and write it to a temp .reg file and then
|
||
execute 'regedit.exe /s tempfile.reg' to properly populate the registry with the defaul HKCU values.
|
||
|
||
Notes:
|
||
|
||
This is an general shim. (Actually, its a Admiral shim, since its in the navy, hehe).
|
||
|
||
History:
|
||
|
||
01/31/2001 reiner Created
|
||
03/30/2001 amarp Added %__AppSystemDir_% and %__AppLocalOrCDDir<Param1><Param2><Param3>_%
|
||
(documented below)
|
||
03/14/2002 mnikkel changed to use strsafe.h
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#include "stdio.h"
|
||
|
||
|
||
IMPLEMENT_SHIM_BEGIN(PopulateDefaultHKCUSettings)
|
||
#include "ShimHookMacro.h"
|
||
|
||
APIHOOK_ENUM_BEGIN
|
||
APIHOOK_ENUM_ENTRY(RegOpenKeyA)
|
||
APIHOOK_ENUM_ENTRY(RegOpenKeyW)
|
||
APIHOOK_ENUM_ENTRY(RegOpenKeyExA)
|
||
APIHOOK_ENUM_ENTRY(RegOpenKeyExW)
|
||
APIHOOK_ENUM_END
|
||
|
||
const DWORD g_MAX = MAX_PATH * 2;
|
||
|
||
BOOL ParseCommandLine(
|
||
const char* pszCmdLine,
|
||
char* pszRegKeyName,
|
||
DWORD cchRegKeyName,
|
||
char* pszResourceName,
|
||
DWORD cchResourceName)
|
||
{
|
||
BOOL bRet = FALSE;
|
||
|
||
CSTRING_TRY
|
||
{
|
||
CString csCmdLine(pszCmdLine);
|
||
int cchKey = csCmdLine.Find(L"!");
|
||
|
||
if (cchKey >= 0)
|
||
{
|
||
// Resource length = Command line length - Key length - exclamation
|
||
DWORD cchResource = csCmdLine.GetLength() - cchKey - 1;
|
||
|
||
if ((cchRegKeyName >= (DWORD)(cchKey + 1)) &&
|
||
(cchResourceName >= (cchResource + 1)))
|
||
{
|
||
CString csKey = csCmdLine.Left(cchKey);
|
||
CString csResource = csCmdLine.Right(cchResource);
|
||
|
||
// we have enough space in the output buffers to fit the strings
|
||
if (S_OK == StringCchCopyA(pszRegKeyName, cchRegKeyName, csKey.GetAnsi()) &&
|
||
S_OK == StringCchCopyA(pszResourceName, cchResourceName, csResource.GetAnsi()))
|
||
{
|
||
bRet = TRUE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
CSTRING_CATCH
|
||
{
|
||
// do nothing
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
|
||
//
|
||
// This actually creates the tempfile (0 bytes) and returns
|
||
// the filename.
|
||
//
|
||
BOOL CreateTempName(char* szFileName)
|
||
{
|
||
char szTempPath[MAX_PATH];
|
||
BOOL bRet = FALSE;
|
||
|
||
DWORD dwLen = GetTempPathA(MAX_PATH, szTempPath);
|
||
|
||
if (dwLen > 0 && dwLen < MAX_PATH)
|
||
{
|
||
if (GetTempFileNameA(szTempPath,
|
||
"AcGenral",
|
||
0,
|
||
szFileName))
|
||
{
|
||
bRet = TRUE;
|
||
}
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
|
||
//
|
||
// Exec's "regedit /s" with the given file
|
||
//
|
||
BOOL SpawnRegedit(char* szFile)
|
||
{
|
||
STARTUPINFOA si = {0};
|
||
PROCESS_INFORMATION pi = {0};
|
||
char szApp[g_MAX];
|
||
BOOL bRet = FALSE;
|
||
|
||
if (S_OK == StringCchCopyA(szApp, g_MAX, "regedit.exe /s ") &&
|
||
S_OK == StringCchCatA(szApp, g_MAX, szFile))
|
||
{
|
||
si.cb = sizeof(si);
|
||
si.dwFlags = STARTF_USESHOWWINDOW;
|
||
si.wShowWindow = SW_HIDE;
|
||
|
||
bRet = CreateProcessA(NULL,
|
||
szApp,
|
||
NULL,
|
||
NULL,
|
||
FALSE,
|
||
0,
|
||
NULL,
|
||
NULL,
|
||
&si,
|
||
&pi);
|
||
|
||
if (bRet)
|
||
{
|
||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||
|
||
CloseHandle(pi.hProcess);
|
||
CloseHandle(pi.hThread);
|
||
}
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
|
||
//
|
||
// this function is used to change a path from:
|
||
//
|
||
// "C:\Lotus\Smartsuite" -> "C:\\Lotus\\Smartsuite"
|
||
//
|
||
// (.reg files use escaped backslashes)
|
||
//
|
||
BOOL DoubleUpBackslashes(WCHAR* pwszPath, DWORD cchPath)
|
||
{
|
||
BOOL bRet = FALSE;
|
||
|
||
CSTRING_TRY
|
||
{
|
||
CString csTemp(pwszPath);
|
||
|
||
csTemp.Replace(L"\\",L"\\\\");
|
||
|
||
if (cchPath >= (DWORD)(csTemp.GetLength()+1) &&
|
||
S_OK == StringCchCopyW(pwszPath, cchPath, csTemp))
|
||
{
|
||
bRet = TRUE;
|
||
}
|
||
}
|
||
CSTRING_CATCH
|
||
{
|
||
// do nothing
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
|
||
//
|
||
// This fuction calculates the application dir (pszAppDir) and the application
|
||
// parent dir (pszAppParentDir) based on the return from GetModuleFileName
|
||
//
|
||
BOOL InitAppDir(WCHAR* pwszSystemDir, DWORD cchSystemDir,
|
||
WCHAR* pwszAppDir, DWORD cchAppDir,
|
||
WCHAR* pwszAppParentDir, DWORD cchAppParentDir
|
||
)
|
||
{
|
||
DWORD dwLen = 0;
|
||
WCHAR wszExePath[MAX_PATH];
|
||
|
||
dwLen = GetSystemDirectoryW(pwszSystemDir,cchSystemDir);
|
||
if(dwLen <= 0 || dwLen >= MAX_PATH)
|
||
return FALSE;
|
||
|
||
BOOL bRet = DoubleUpBackslashes(pwszSystemDir,cchSystemDir);
|
||
if( !bRet )
|
||
return FALSE;
|
||
|
||
if (GetModuleFileNameW(NULL, wszExePath, sizeof(wszExePath)/sizeof(wszExePath[0])))
|
||
{
|
||
CSTRING_TRY
|
||
{
|
||
CString csPath;
|
||
CString csPath2;
|
||
CString csTemp(wszExePath);
|
||
|
||
csTemp.GetNotLastPathComponent(csPath);
|
||
csPath.GetNotLastPathComponent(csPath2);
|
||
|
||
if (!csPath.IsEmpty())
|
||
{
|
||
if (cchAppDir >= (DWORD)(csPath.GetLength()+1) &&
|
||
S_OK == StringCchCopyW(pwszAppDir, cchAppDir, csPath))
|
||
{
|
||
bRet = DoubleUpBackslashes(pwszAppDir, cchAppDir);
|
||
|
||
if (bRet)
|
||
{
|
||
if (!csPath2.IsEmpty())
|
||
{
|
||
if(cchAppParentDir >= (DWORD)(csPath2.GetLength()+1) &&
|
||
S_OK == StringCchCopyW(pwszAppParentDir, cchAppParentDir, csPath2))
|
||
{
|
||
bRet = DoubleUpBackslashes(pwszAppParentDir, cchAppParentDir);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// if there is not another '\' then just use the same path as pwszAppDir
|
||
if (S_OK == StringCchCopyW(pwszAppParentDir, cchAppParentDir, pwszAppDir))
|
||
bRet = TRUE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
CSTRING_CATCH
|
||
{
|
||
// do nothing
|
||
}
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
|
||
//
|
||
// This function is called to actually write stuff out to the file
|
||
//
|
||
BOOL WriteToFile(HANDLE hFile, void* pv, DWORD cb)
|
||
{
|
||
DWORD dwBytesWritten;
|
||
BOOL bWriteSucceeded = FALSE;
|
||
|
||
if (WriteFile(hFile, pv, cb, &dwBytesWritten, NULL) &&
|
||
(dwBytesWritten == cb))
|
||
{
|
||
bWriteSucceeded = TRUE;
|
||
}
|
||
|
||
return bWriteSucceeded;
|
||
}
|
||
|
||
BOOL PathIsNonEmptyDirectory(WCHAR* pwszPath)
|
||
{
|
||
WCHAR wszSearchFilter[MAX_PATH+1];
|
||
DWORD dwAttr = GetFileAttributesW(pwszPath);
|
||
BOOL bRet = FALSE;
|
||
if( (-1 != dwAttr) && (FILE_ATTRIBUTE_DIRECTORY & dwAttr ) )
|
||
{
|
||
if (S_OK != StringCchPrintfW(wszSearchFilter, MAX_PATH, L"%s\\*.*", pwszPath))
|
||
{
|
||
return bRet;
|
||
}
|
||
|
||
|
||
WIN32_FIND_DATAW FindData;
|
||
HANDLE hSearch = FindFirstFileW(wszSearchFilter,&FindData);
|
||
if( INVALID_HANDLE_VALUE == hSearch )
|
||
return bRet;
|
||
do
|
||
{
|
||
if(L'.' != FindData.cFileName[0])
|
||
{
|
||
bRet = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
while( FindNextFileW(hSearch,&FindData) );
|
||
FindClose(hSearch);
|
||
}
|
||
return bRet;
|
||
}
|
||
|
||
BOOL FindCDDriveContainingDirectory(WCHAR* pwchCDDriveLetter, WCHAR* pwszCheckPath)
|
||
{
|
||
// Find out cd drive (looks for app cd in drive, else just chooses first cd drive found)
|
||
// NOTE: This function only actually does anything the first time its called (to avoid
|
||
// thrashing CD drive, or bringing up excessive dialogs if no CD in drive).
|
||
// The assumption is that once a good CD drive is found, any other times you need
|
||
// a CD drive in this shim, it will be the same one, so this function will just return
|
||
// that drive.
|
||
|
||
static BOOL s_bFoundDrive = FALSE;
|
||
static BOOL s_bTriedOnce = FALSE;
|
||
static WCHAR s_wchCDDriveLetter = L'\0';
|
||
|
||
if( s_bTriedOnce )
|
||
{
|
||
*pwchCDDriveLetter = s_wchCDDriveLetter;
|
||
return s_bFoundDrive;
|
||
}
|
||
s_bTriedOnce = TRUE;
|
||
|
||
DWORD dwLogicalDrives = GetLogicalDrives();
|
||
WCHAR wchCurrDrive = L'a';
|
||
WCHAR wszPath[MAX_PATH];
|
||
|
||
while( dwLogicalDrives )
|
||
{
|
||
if( dwLogicalDrives & 1 )
|
||
{
|
||
wszPath[0] = wchCurrDrive;
|
||
wszPath[1] = L':';
|
||
wszPath[2] = L'\0';
|
||
|
||
if( DRIVE_CDROM == GetDriveTypeW( wszPath ) )
|
||
{
|
||
if( L'\0' == s_wchCDDriveLetter )
|
||
{
|
||
s_bFoundDrive = TRUE;
|
||
s_wchCDDriveLetter = wchCurrDrive;
|
||
}
|
||
|
||
if (wcslen(pwszCheckPath) > MAX_PATH-3)
|
||
{
|
||
return FALSE;
|
||
}
|
||
if (S_OK != StringCchCatW(wszPath, MAX_PATH, pwszCheckPath))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
DWORD dwAttr = GetFileAttributesW(wszPath);
|
||
if( (-1 != dwAttr) && (FILE_ATTRIBUTE_DIRECTORY & dwAttr ) )
|
||
{
|
||
// this drive seems to have the app cd in it based on
|
||
// a very primitive heuristic... so lets use this as our cd drive.
|
||
s_wchCDDriveLetter = wchCurrDrive;
|
||
*pwchCDDriveLetter = s_wchCDDriveLetter;
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
dwLogicalDrives >>= 1;
|
||
wchCurrDrive++;
|
||
}
|
||
*pwchCDDriveLetter = s_wchCDDriveLetter; //may be L'\0' if we didn't find anything.
|
||
return s_bFoundDrive;
|
||
}
|
||
|
||
BOOL GrabNParameters( UINT uiNumParameters,
|
||
WCHAR* pwszStart, WCHAR** ppwszEnd,
|
||
WCHAR pwszParam[][MAX_PATH] )
|
||
{
|
||
WCHAR* pwszEnd;
|
||
UINT uiLength;
|
||
*ppwszEnd = NULL;
|
||
|
||
for( UINT i = 0; i < uiNumParameters; i++ )
|
||
{
|
||
if( L'<' != *(pwszStart++) )
|
||
return FALSE;
|
||
|
||
pwszEnd = pwszStart;
|
||
|
||
while( (L'\0' != *pwszEnd) )
|
||
{
|
||
if( L'>' != *pwszEnd )
|
||
{
|
||
pwszEnd++;
|
||
continue;
|
||
}
|
||
uiLength = (pwszEnd - pwszStart);
|
||
if( uiLength >= MAX_PATH )
|
||
return FALSE;
|
||
if( S_OK != StringCchCopyW(pwszParam[i], MAX_PATH, pwszStart))
|
||
return FALSE;
|
||
break;
|
||
}
|
||
|
||
if( L'>' != *pwszEnd )
|
||
return FALSE;
|
||
|
||
pwszStart = pwszEnd + 1;
|
||
}
|
||
*ppwszEnd = pwszStart;
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// As we write out the resource to a temp file, we need to scan through looking
|
||
// for the env variables:
|
||
//
|
||
// %__AppDir_%
|
||
// %__AppParentDir_%
|
||
//
|
||
// and replace them with the proper path (the dir of the current .exe or its parent,
|
||
// respectively).
|
||
//
|
||
// Additional vars (added by amarp):
|
||
//
|
||
// %__AppSystemDir_%
|
||
// - Maps to GetSystemDir() (i.e. c:\windows\system32)
|
||
//
|
||
// %__AppLocalOrCDDir<Param1><Param2><Param3>_%
|
||
//
|
||
// - The three parameters are just paths (should start with a \\).
|
||
// Any/all may be empty. They are defined as follows:
|
||
// Param1 = a relative path under the app<70>s install directory (i.e. under AppDir)
|
||
// Param2 = a relative path under the app<70>s CD drive (where CD Drive = "drive:")
|
||
// Param3 = a relative path/filename under Param1 or Param2 (in most cases this will be empty)
|
||
//
|
||
// When this var is encountered, it is replaced as follows:
|
||
// a) if AppDirParam1Param3 is a *nonempty* directory, output AppDirParam1Param3
|
||
// b) else, if there is a CDDrive for which directory CDDrive:Param2 exists, output CDDrive:Param2Param3
|
||
// c) else, output CDDrive:Param2Param3 for the first enumerated CD drive.
|
||
//
|
||
// Example: %__AppLocalOrCDDir<\\content\\clipart><\\clipart><\\index.dat>_% maps does the following:
|
||
// (lets assume AppDir is c:\app, and there are cd drives d: and e:, neither of which have the app's CD inserted)
|
||
// a) Is c:\app\content a directory? Yes! -> Is it nonempty (at least one file or directory that doesn't start with '.')?
|
||
// yes! -> output c:\app\content\index.dat
|
||
// <end>
|
||
//
|
||
// Or, this example could pan out to the following scenario:
|
||
// a) Is c:\app\content a directory? Yes! -> Is it nonempty? No!
|
||
// b) Is d:\clipart a directory? No! Is e:\clipart a directory? No!
|
||
// c) The first cd drive we found was d: -> output d:\clipart\index.dat
|
||
// <end>
|
||
//
|
||
// Anoter example: %__AppLocalOrCDDir<__UNUSED__><\\clipart><>_% maps does the following:
|
||
// (lets assume AppDir is c:\app and app CD is in drive d:)
|
||
// a) Is c:\app__UNUSED__ a directory? PROBABLY NOT! (thus we can essentially ignore this parameter by doing this)
|
||
// b) Is d:\clipart a directory? Yes! --> output d:\clipart
|
||
// <end>
|
||
//
|
||
//
|
||
//
|
||
// NOTE: cbResourceSize holds the size of the original resource (which is the 2 WCHAR's
|
||
// smaller than pvData). We use this to set eof after we are done writing everything
|
||
// out.
|
||
//
|
||
BOOL WriteResourceFile(HANDLE hFile, void* pvData, DWORD /*cbResourceSize*/)
|
||
{
|
||
WCHAR* pwszEndOfLastWrite = (WCHAR*)pvData;
|
||
WCHAR wszAppDir[MAX_PATH];
|
||
WCHAR wszAppParentDir[MAX_PATH];
|
||
WCHAR wszSystemDir[MAX_PATH];
|
||
BOOL bRet = FALSE;
|
||
bRet = InitAppDir(wszSystemDir, sizeof(wszSystemDir)/sizeof(wszSystemDir[0]),
|
||
wszAppDir, sizeof(wszAppDir)/sizeof(wszAppDir[0]),
|
||
wszAppParentDir, sizeof(wszAppParentDir)/sizeof(wszAppParentDir[0]));
|
||
if (!bRet)
|
||
return bRet;
|
||
|
||
do
|
||
{
|
||
WCHAR* pwsz = wcsstr(pwszEndOfLastWrite, L"%__App");
|
||
if (pwsz)
|
||
{
|
||
// first, write out anything before the tag we found
|
||
bRet = WriteToFile(hFile, pwszEndOfLastWrite, (DWORD)((BYTE*)pwsz - (BYTE*)pwszEndOfLastWrite));
|
||
|
||
if(!bRet)
|
||
break;
|
||
|
||
pwszEndOfLastWrite = pwsz;
|
||
|
||
// found a tag that we need to replace. See which one it is
|
||
if (wcsncmp(pwsz, L"%__AppDir_%", lstrlenW(L"%__AppDir_%")) == 0)
|
||
{
|
||
bRet = WriteToFile(hFile, wszAppDir, lstrlenW(wszAppDir) * sizeof(WCHAR));
|
||
pwszEndOfLastWrite += lstrlenW(L"%__AppDir_%");
|
||
}
|
||
else if (wcsncmp(pwsz, L"%__AppParentDir_%", lstrlenW(L"%__AppParentDir_%")) == 0)
|
||
{
|
||
bRet = WriteToFile(hFile, wszAppParentDir, lstrlenW(wszAppParentDir) * sizeof(WCHAR));
|
||
pwszEndOfLastWrite += lstrlenW(L"%__AppParentDir_%");
|
||
}
|
||
else if (wcsncmp(pwsz, L"%__AppSystemDir_%", lstrlenW(L"%__AppSystemDir_%")) == 0)
|
||
{
|
||
bRet = WriteToFile(hFile, wszSystemDir, lstrlenW(wszSystemDir) * sizeof(WCHAR));
|
||
pwszEndOfLastWrite += lstrlenW(L"%__AppSystemDir_%");
|
||
}
|
||
else if (wcsncmp(pwsz, L"%__AppLocalOrCDDir", lstrlenW(L"%__AppLocalOrCDDir")) == 0)
|
||
{
|
||
WCHAR wszParams[3][MAX_PATH];
|
||
WCHAR* pwszStart = pwsz + lstrlenW(L"%__AppLocalOrCDDir");
|
||
WCHAR* pwszEnd;
|
||
WCHAR wszDesiredPath[MAX_PATH];
|
||
|
||
if (!GrabNParameters(3,pwszStart,&pwszEnd,wszParams))
|
||
{
|
||
pwszEndOfLastWrite += lstrlenW(L"%__AppLocalOrCDDir");
|
||
continue;
|
||
}
|
||
|
||
if (0 != wcsncmp(pwszEnd, L"_%", lstrlenW(L"_%")))
|
||
{
|
||
pwszEndOfLastWrite = pwszEnd;
|
||
continue;
|
||
}
|
||
|
||
if (S_OK == StringCchPrintfW(wszDesiredPath,MAX_PATH, L"%s%s", wszAppDir, wszParams[0]))
|
||
{
|
||
if( PathIsNonEmptyDirectory(wszDesiredPath) )
|
||
{
|
||
if (S_OK == StringCchPrintfW(wszDesiredPath,MAX_PATH,L"%s%s%s",wszAppDir, wszParams[0], wszParams[2]))
|
||
bRet = WriteToFile(hFile, wszDesiredPath, lstrlenW(wszDesiredPath) * sizeof(WCHAR));
|
||
}
|
||
else
|
||
{
|
||
WCHAR wchDrive;
|
||
UINT uiOffset;
|
||
if( L'\\' == wszParams[1][0] && L'\\' == wszParams[1][1] )
|
||
uiOffset = sizeof(WCHAR);
|
||
else
|
||
uiOffset = 0;
|
||
if( FindCDDriveContainingDirectory(&wchDrive,wszParams[1]+uiOffset))
|
||
{
|
||
if (S_OK == StringCchPrintfW(wszDesiredPath,MAX_PATH,L"%c:%s%s",wchDrive,wszParams[1],wszParams[2]))
|
||
bRet = WriteToFile(hFile, wszDesiredPath, lstrlenW(wszDesiredPath) * sizeof(WCHAR));
|
||
}
|
||
}
|
||
}
|
||
|
||
pwszEndOfLastWrite= pwszEnd + lstrlenW(L"_%");
|
||
}
|
||
else
|
||
{
|
||
// Strange... we found a string that started w/ "%__App" that wasen't one we are
|
||
// intersted in. Just skip over it and keep going.
|
||
bRet = WriteToFile(hFile, pwsz, lstrlenW(L"%__App") * sizeof(WCHAR));
|
||
pwszEndOfLastWrite += lstrlenW(L"%__App");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// didn't find anymore strings to replace
|
||
|
||
// using lstrlenW should give us the size of the string w/out the null, which is what we
|
||
// want since we added on the space for the null when we created the buffer
|
||
bRet = WriteToFile(hFile, pwszEndOfLastWrite, lstrlenW(pwszEndOfLastWrite) * sizeof(WCHAR));
|
||
|
||
// break out of the loop, as we are finished
|
||
break;
|
||
}
|
||
|
||
} while (bRet);
|
||
|
||
return bRet;
|
||
}
|
||
|
||
|
||
//
|
||
// The job of this function is to read the specified string resource our
|
||
// of our own DLL and write it to a temp file, and then to spawn regedit on
|
||
// the file
|
||
//
|
||
BOOL ExecuteRegFileFromResource(char* pszResourceName)
|
||
{
|
||
// lame, but we aren't passed our hinst in our pseudo dllmain,
|
||
// so we have to hardcode the dllname
|
||
HMODULE hmod = GetModuleHandleA("AcGenral");
|
||
BOOL bRet = FALSE;
|
||
|
||
if (hmod)
|
||
{
|
||
HRSRC hrsrc = FindResourceA(hmod, pszResourceName, MAKEINTRESOURCEA(10)/* RT_RCDATA */);
|
||
|
||
if (hrsrc)
|
||
{
|
||
DWORD dwSize;
|
||
void* pvData;
|
||
|
||
dwSize = SizeofResource(hmod, hrsrc);
|
||
|
||
if (dwSize > 0)
|
||
{
|
||
// allocate enough room for the entire resource including puting a null terminator on
|
||
// the end since we will be treating it like huge LPWSTR.
|
||
pvData = LocalAlloc(LPTR, dwSize + sizeof(WCHAR));
|
||
|
||
if (pvData)
|
||
{
|
||
HGLOBAL hGlobal = LoadResource(hmod, hrsrc);
|
||
|
||
if (hGlobal)
|
||
{
|
||
void* pv = LockResource(hGlobal);
|
||
|
||
if (pv)
|
||
{
|
||
char szTempFile[MAX_PATH];
|
||
|
||
// copy the resource into our buffer
|
||
memcpy(pvData, pv, dwSize);
|
||
|
||
if (CreateTempName(szTempFile))
|
||
{
|
||
// we use OPEN_EXISTING since the tempfile should always exist as it
|
||
// was created in the call to CreateTempName()
|
||
HANDLE hFile = CreateFileA(szTempFile,
|
||
GENERIC_WRITE,
|
||
FILE_SHARE_READ,
|
||
NULL,
|
||
OPEN_EXISTING,
|
||
FILE_ATTRIBUTE_TEMPORARY,
|
||
NULL);
|
||
|
||
if (hFile != INVALID_HANDLE_VALUE)
|
||
{
|
||
BOOL bWriteSucceeded = WriteResourceFile(hFile, pvData, dwSize);
|
||
|
||
CloseHandle(hFile);
|
||
|
||
if (bWriteSucceeded)
|
||
{
|
||
bRet = SpawnRegedit(szTempFile);
|
||
}
|
||
}
|
||
|
||
DeleteFileA(szTempFile);
|
||
}
|
||
}
|
||
}
|
||
LocalFree(pvData);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
|
||
BOOL PopulateHKCUValues()
|
||
{
|
||
static BOOL s_fAlreadyPopulated = FALSE;
|
||
|
||
if (!s_fAlreadyPopulated)
|
||
{
|
||
char szRegKeyName[MAX_PATH];
|
||
char szResourceName[64];
|
||
|
||
UINT uiOldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); // stop dialogs from coming up when we enumerate CD drives that are empty.
|
||
|
||
// set this to true so we only do this check once
|
||
s_fAlreadyPopulated = TRUE;
|
||
|
||
if (ParseCommandLine(COMMAND_LINE,
|
||
szRegKeyName,
|
||
ARRAYSIZE(szRegKeyName),
|
||
szResourceName,
|
||
ARRAYSIZE(szResourceName)))
|
||
{
|
||
DWORD dwError;
|
||
HKEY hkCU;
|
||
|
||
// check to see if the HKCU registry key is already present
|
||
dwError = RegOpenKeyExA(HKEY_CURRENT_USER,
|
||
szRegKeyName,
|
||
0,
|
||
KEY_QUERY_VALUE,
|
||
&hkCU);
|
||
|
||
if (dwError == ERROR_SUCCESS)
|
||
{
|
||
// yep, its already there. Nothing to do.
|
||
RegCloseKey(hkCU);
|
||
}
|
||
else if (dwError == ERROR_FILE_NOT_FOUND)
|
||
{
|
||
// the regkey is missing, we will assume that this is the first time
|
||
// the user has run the app and populate HKCU with the proper stuff
|
||
ExecuteRegFileFromResource(szResourceName);
|
||
}
|
||
}
|
||
|
||
SetErrorMode(uiOldErrorMode);
|
||
}
|
||
|
||
|
||
return s_fAlreadyPopulated;
|
||
}
|
||
|
||
|
||
//
|
||
// Its lame that we have to hook RegOpenKey/Ex but since we need to call
|
||
// the advapi32 registry apis we can't do this as a straight NOTIFY_FUNCTION
|
||
// because we need to wait for advapi to have its DLL_PROCESS_ATTACH called.
|
||
//
|
||
LONG
|
||
APIHOOK(RegOpenKeyA)(HKEY hkey, LPCSTR pszSubKey, HKEY* phkResult)
|
||
{
|
||
PopulateHKCUValues();
|
||
return ORIGINAL_API(RegOpenKeyA)(hkey, pszSubKey, phkResult);
|
||
}
|
||
|
||
|
||
LONG
|
||
APIHOOK(RegOpenKeyW)(HKEY hkey, LPCWSTR pszSubKey, HKEY* phkResult)
|
||
{
|
||
PopulateHKCUValues();
|
||
return ORIGINAL_API(RegOpenKeyW)(hkey, pszSubKey, phkResult);
|
||
}
|
||
|
||
LONG
|
||
APIHOOK(RegOpenKeyExA)(HKEY hkey, LPCSTR pszSubKey, DWORD ulOptions, REGSAM samDesired, HKEY* phkResult)
|
||
{
|
||
PopulateHKCUValues();
|
||
return ORIGINAL_API(RegOpenKeyExA)(hkey, pszSubKey, ulOptions, samDesired, phkResult);
|
||
}
|
||
|
||
LONG
|
||
APIHOOK(RegOpenKeyExW)(HKEY hkey, LPCWSTR pszSubKey, DWORD ulOptions, REGSAM samDesired, HKEY* phkResult)
|
||
{
|
||
PopulateHKCUValues();
|
||
return ORIGINAL_API(RegOpenKeyExW)(hkey, pszSubKey, ulOptions, samDesired, phkResult);
|
||
}
|
||
|
||
|
||
/*++
|
||
|
||
Register hooked functions
|
||
|
||
--*/
|
||
|
||
HOOK_BEGIN
|
||
|
||
APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyA)
|
||
APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyW)
|
||
APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyExA)
|
||
APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyExW)
|
||
|
||
HOOK_END
|
||
|
||
|
||
IMPLEMENT_SHIM_END
|