|
|
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
Func.cpp
Abstract:
Misc. functions used throughout the application
Notes:
ANSI only - must run on Win9x.
History:
01/30/01 rparsons Created 01/10/02 rparsons Revised
--*/ #include "demoapp.h"
extern APPINFO g_ai;
/*++
Routine Description:
Loads the contents of our 'readme' into the edit box.
Arguments:
None.
Return Value:
None.
--*/ void LoadFileIntoEditBox( void ) { HRESULT hr; HANDLE hFile; DWORD dwFileSize; DWORD cbBytesRead; char szTextFile[MAX_PATH]; char* pszBuffer = NULL;
//
// Set up a path to our file and load it.
//
hr = StringCchPrintf(szTextFile, sizeof(szTextFile), "%hs\\demoapp.txt", g_ai.szCurrentDir);
if (FAILED(hr)) { return; }
hFile = CreateFile(szTextFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hFile) { return; }
dwFileSize = GetFileSize(hFile, 0);
if (0 == dwFileSize) { goto exit; }
pszBuffer = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ++dwFileSize);
if (!pszBuffer) { goto exit; }
if (!ReadFile(hFile, (LPVOID)pszBuffer, dwFileSize, &cbBytesRead, NULL)) { goto exit; }
SetWindowText(g_ai.hWndEdit, pszBuffer);
exit:
CloseHandle(hFile);
if (pszBuffer) { HeapFree(GetProcessHeap(), 0, pszBuffer); } }
/*++
Routine Description:
Centers the specified window.
Arguments:
hWnd - Window to center.
Return Value:
TRUE on success, FALSE otherwise.
--*/ BOOL CenterWindow( IN HWND hWnd ) { RECT rectWindow, rectParent, rectScreen; int nCX, nCY; HWND hParent; POINT ptPoint;
hParent = GetParent(hWnd);
if (hParent == NULL) { hParent = GetDesktopWindow(); }
GetWindowRect(hParent, &rectParent); GetWindowRect(hWnd, &rectWindow); GetWindowRect(GetDesktopWindow(), &rectScreen);
nCX = rectWindow.right - rectWindow.left; nCY = rectWindow.bottom - rectWindow.top;
ptPoint.x = ((rectParent.right + rectParent.left) / 2) - (nCX / 2); ptPoint.y = ((rectParent.bottom + rectParent.top ) / 2) - (nCY / 2);
if (ptPoint.x < rectScreen.left) { ptPoint.x = rectScreen.left; }
if (ptPoint.x > rectScreen.right - nCX) { ptPoint.x = rectScreen.right - nCX; }
if (ptPoint.y < rectScreen.top) { ptPoint.y = rectScreen.top; }
if (ptPoint.y > rectScreen.bottom - nCY) { ptPoint.y = rectScreen.bottom - nCY; }
if (GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD) { ScreenToClient(hParent, (LPPOINT)&ptPoint); }
if (!MoveWindow(hWnd, ptPoint.x, ptPoint.y, nCX, nCY, TRUE)) { return FALSE; }
return TRUE; }
/*++
Routine Description:
Reboots the system properly.
Arguments:
fForceClose - A flag to indicate if apps should be forced to close. fReboot - A flag to indicate if we should reboot after shutdown.
Return Value:
TRUE on success, FALSE otherwise.
--*/ BOOL ShutdownSystem( IN BOOL fForceClose, IN BOOL fReboot ) { BOOL bResult = FALSE;
//
// Attempt to give the user the required privilege.
//
if (!ModifyTokenPrivilege("SeShutdownPrivilege", FALSE)) { return FALSE; }
bResult = InitiateSystemShutdown(NULL, // machinename
NULL, // shutdown message
0, // delay
fForceClose, // force apps close
fReboot // reboot after shutdown
);
ModifyTokenPrivilege("SeShutdownPrivilege", TRUE);
return bResult; }
/*++
Routine Description:
Enables or disables a specified privilege.
Arguments:
pszPrivilege - The name of the privilege. fEnable - A flag to indicate if the privilege should be enabled.
Return Value:
TRUE on success, FALSE otherwise.
--*/ BOOL ModifyTokenPrivilege( IN LPCSTR pszPrivilege, IN BOOL fEnable ) { HANDLE hToken = NULL; LUID luid; BOOL bResult = FALSE; BOOL bReturn; TOKEN_PRIVILEGES tp;
if (!pszPrivilege) { return FALSE; }
__try { //
// Get a handle to the access token associated with the current process.
//
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
if (!hToken) { __leave; }
//
// Obtain a LUID for the specified privilege.
//
if (!LookupPrivilegeValue(NULL, pszPrivilege, &luid)) { __leave; }
tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;
//
// Modify the access token.
//
bReturn = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
if (!bReturn || GetLastError() == ERROR_NOT_ALL_ASSIGNED) { __leave; }
bResult = TRUE;
} // try
__finally {
if (hToken) { CloseHandle(hToken); }
} // finally
return bResult; }
/*++
Routine Description:
Copies the necessary files to the destination.
Arguments:
hWnd - Parent window handle.
Return Value:
TRUE on success, FALSE otherwise.
--*/ BOOL CopyAppFiles( IN HWND hWnd ) { char szSrcPath[MAX_PATH]; char szDestPath[MAX_PATH]; char szError[MAX_PATH]; char szDestDir[MAX_PATH]; UINT nCount; HRESULT hr;
//
// Obtain the location of \Program Files.
//
hr = SHGetFolderPath(hWnd, // HWND for message display
CSIDL_PROGRAM_FILES, // need \Program Files folder
NULL, // no token needed
SHGFP_TYPE_CURRENT, // we want the current location of the folder
szDestDir); // destination buffer
if (FAILED(hr)) { LoadString(g_ai.hInstance, IDS_NO_PROG_FILES, szError, sizeof(szError)); MessageBox(hWnd, szError, 0, MB_ICONERROR); return FALSE; }
hr = StringCchCat(szDestDir, sizeof(szDestDir), "\\"COMPAT_DEMO_DIR);
if (FAILED(hr)) { return FALSE; }
if (GetFileAttributes(szDestDir) == -1) { if (!CreateDirectory(szDestDir, NULL)) { return FALSE; } }
//
// Preserve the path for later use.
//
StringCchCopy(g_ai.szDestDir, sizeof(g_ai.szDestDir), szDestDir);
//
// Now copy our files.
//
for (nCount = 0; nCount < g_ai.cFiles; ++nCount) { //
// Build the source path.
//
hr = StringCchPrintf(szSrcPath, sizeof(szSrcPath), "%hs\\%hs", g_ai.szCurrentDir, g_ai.shortcut[nCount].szFileName);
if (FAILED(hr)) { return FALSE; }
//
// Build the destination path.
//
hr = StringCchPrintf(szDestPath, sizeof(szDestPath), "%hs\\%hs", g_ai.szDestDir, g_ai.shortcut[nCount].szFileName);
if (FAILED(hr)) { return FALSE; }
CopyFile(szSrcPath, szDestPath, FALSE); }
return TRUE; }
/*++
Routine Description:
Create shortcuts for our three entries.
Arguments:
hWnd - Parent window handle.
Return Value:
TRUE on success, FALSE otherwise.
--*/ BOOL CreateShortcuts( IN HWND hWnd ) { char szError[MAX_PATH]; char szDestDir[MAX_PATH]; char szLnkDirectory[MAX_PATH]; char szFileNamePath[MAX_PATH]; char szExplorer[MAX_PATH]; const char szExplorerExe[] = "explorer.exe"; UINT nCount; HRESULT hr; CShortcut cs;
//
// Obtain the location of the Start Menu folder for the
// individual user.
//
hr = SHGetFolderPath(hWnd, CSIDL_PROGRAMS, NULL, SHGFP_TYPE_CURRENT, szDestDir);
if (FAILED(hr)) { LoadString(g_ai.hInstance, IDS_NO_PROGRAMS, szError, sizeof(szError)); MessageBox(hWnd, szError, 0, MB_ICONERROR); return FALSE; }
//
// Create our group - put it in the individual user folder
// so we'll work with Win9x/ME.
//
cs.CreateGroup(COMPAT_DEMO_DIR, FALSE);
//
// Build the start menu directory -
// C:\Documents and Settings\<username>\Start Menu\Programs\Compatibility Demo
//
hr = StringCchCat(szDestDir, sizeof(szDestDir), "\\"COMPAT_DEMO_DIR);
if (FAILED(hr)) { return FALSE; }
hr = StringCchCopy(szLnkDirectory, sizeof(szLnkDirectory), szDestDir);
if (FAILED(hr)) { return FALSE; }
//
// Launch explorer.exe and display the window.
//
hr = StringCchPrintf(szExplorer, sizeof(szExplorer), "%hs %hs", szExplorerExe, szDestDir);
if (FAILED(hr)) { return FALSE; }
//
// We use WinExec to emulate other apps -
// CreateProcess is the proper way.
//
WinExec(szExplorer, SW_SHOWNORMAL);
//
// Give explorer a little time to come up.
//
Sleep(2000);
//
// Now create the shortcuts.
//
for (nCount = 0; nCount < g_ai.cFiles - 1; ++nCount) { //
// Build the file system related path.
//
hr = StringCchPrintf(szFileNamePath, sizeof(szFileNamePath), "%hs\\%hs", g_ai.szDestDir, g_ai.shortcut[nCount].szFileName);
if (FAILED(hr)) { return FALSE; }
cs.CreateShortcut(szLnkDirectory, szFileNamePath, g_ai.shortcut[nCount].szDisplayName, nCount == 1 ? "-runapp" : NULL, g_ai.szDestDir, SW_SHOWNORMAL);
//
// Do it slowly like other apps do.
//
Sleep(3000); }
//
// Now try to create a shortcut to our EXE on the desktop,
// but use a hard-coded path.
//
hr = StringCchPrintf(szFileNamePath, sizeof(szFileNamePath), "%hs\\%hs", g_ai.szDestDir, g_ai.shortcut[1].szFileName);
if (FAILED(hr)) { return FALSE; }
BadCreateShortcut(g_ai.fEnableBadFunc ? FALSE : TRUE, szFileNamePath, g_ai.szDestDir, g_ai.shortcut[1].szDisplayName);
return TRUE; }
/*++
Routine Description:
Performs some basic initialization.
Arguments:
lpCmdLine - Pointer to the command line provided.
Return Value:
None.
--*/ BOOL DemoAppInitialize( IN LPSTR lpCmdLine ) { char szPath[MAX_PATH]; char* pToken = NULL; char* pTemp = NULL; const char szSeps[] = " "; const char szDisable[] = "-disable"; const char szRunApp[] = "-runapp"; const char szExtended[] = "-ext"; const char szInsecure[] = "-enableheap"; const char szInternal[] = "-internal"; DWORD cchReturned; HRESULT hr; UINT cchSize;
g_ai.fEnableBadFunc = TRUE; g_ai.fInsecure = FALSE;
//
// Get paths to %windir% and %windir%\System(32)
//
cchSize = GetSystemWindowsDirectory(g_ai.szWinDir, sizeof(g_ai.szWinDir));
if (cchSize > sizeof(g_ai.szWinDir) || cchSize == 0) { return FALSE; }
cchSize = GetSystemDirectory(g_ai.szSysDir, sizeof(g_ai.szSysDir));
if (cchSize > sizeof(g_ai.szSysDir) || cchSize == 0) { return FALSE; }
//
// Set up information for each of the shortcuts we'll be creating
// and the files we're installing.
//
g_ai.cFiles = NUM_FILES;
hr = StringCchCopy(g_ai.shortcut[0].szDisplayName, sizeof(g_ai.shortcut[0].szDisplayName), "Compatibility Demo Readme");
if (FAILED(hr)) { return FALSE; }
hr = StringCchCopy(g_ai.shortcut[0].szFileName, sizeof(g_ai.shortcut[0].szFileName), "demoapp.txt");
if (FAILED(hr)) { return FALSE; }
hr = StringCchCopy(g_ai.shortcut[1].szDisplayName, sizeof(g_ai.shortcut[1].szDisplayName), "Compatibility Demo");
if (FAILED(hr)) { return FALSE; }
hr = StringCchCopy(g_ai.shortcut[1].szFileName, sizeof(g_ai.shortcut[1].szFileName), "demoapp.exe");
if (FAILED(hr)) { return FALSE; }
hr = StringCchCopy(g_ai.shortcut[2].szDisplayName, sizeof(g_ai.shortcut[2].szDisplayName), "Compatibility Demo Help");
if (FAILED(hr)) { return FALSE; }
hr = StringCchCopy(g_ai.shortcut[2].szFileName, sizeof(g_ai.shortcut[2].szFileName), "demoapp.hlp");
if (FAILED(hr)) { return FALSE; }
hr = StringCchCopy(g_ai.shortcut[3].szFileName, sizeof(g_ai.shortcut[3].szFileName), "demodll.dll");
if (FAILED(hr)) { return FALSE; }
//
// Save away the path that we're running from for later.
//
szPath[sizeof(szPath) - 1] = 0; cchReturned = GetModuleFileName(NULL, szPath, sizeof(szPath));
if (szPath[sizeof(szPath) - 1] != 0 || cchReturned == 0) { return FALSE; }
pTemp = strrchr(szPath, '\\');
if (pTemp) { *pTemp = '\0'; }
StringCchCopy(g_ai.szCurrentDir, sizeof(g_ai.szCurrentDir), szPath);
//
// Check for Win9x - this won't get hooked by any VL.
//
IsWindows9x();
//
// Check for WinXP - this won't get hooked by any VL.
//
IsWindowsXP();
//
// Parse the command line, if one was provided.
//
if (lpCmdLine) { pToken = strtok(lpCmdLine, szSeps);
while (pToken) { if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, pToken, -1, szDisable, -1) == CSTR_EQUAL) { g_ai.fEnableBadFunc = FALSE; }
else if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, pToken, -1, szRunApp, -1) == CSTR_EQUAL) { g_ai.fRunApp = TRUE; }
else if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, pToken, -1, szExtended, -1) == CSTR_EQUAL) { g_ai.fExtended = TRUE; }
else if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, pToken, -1, szInsecure, -1) == CSTR_EQUAL) { g_ai.fInsecure = TRUE; }
else if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, pToken, -1, szInternal, -1) == CSTR_EQUAL) { g_ai.fInternal = TRUE; }
pToken = strtok(NULL, szSeps); } }
return TRUE; }
/*++
Routine Description:
Displays a common font dialog.
Arguments:
None.
Return Value:
None.
--*/ void DisplayFontDlg( IN HWND hWnd ) { CHOOSEFONT cf; static LOGFONT lf; static DWORD rgbCurrent;
ZeroMemory(&cf, sizeof(CHOOSEFONT));
cf.lStructSize = sizeof(CHOOSEFONT); cf.hwndOwner = hWnd; cf.lpLogFont = &lf; cf.rgbColors = rgbCurrent; cf.Flags = CF_SCREENFONTS | CF_EFFECTS;
//
// Display the dialog - user input isn't processed.
//
ChooseFont(&cf); }
/*++
Routine Description:
Determines if we're truly running on Windows 9x. A version lie will not correct this call.
Arguments:
None.
Return Value:
None - sets a global flag.
--*/ void IsWindows9x( void ) { CRegistry creg; LPSTR lpRet = NULL;
//
// Query a part of the registry that's specific to NT/2000/XP.
// We use the result when we're making calls for demo purposes
// that work differently on Win9x/ME (example: creating shortcuts).
//
lpRet = creg.GetString(HKEY_LOCAL_MACHINE, PRODUCT_OPTIONS_KEY, "ProductType");
if (!lpRet) { g_ai.fWin9x = TRUE; } else { g_ai.fWin9x = FALSE; creg.Free(lpRet); } }
/*++
Routine Description:
Determines if we're running on Windows XP. A version lie will not correct this call.
Arguments:
None.
Return Value:
None - sets a global flag.
--*/ void IsWindowsXP( void ) { CRegistry creg; LPSTR lpBuild = NULL; int nBuild = 0, nWin2K = 2195;
//
// This registry key should only exist for
// Windows XP.
//
lpBuild = creg.GetString(HKEY_LOCAL_MACHINE, CURRENT_VERSION_KEY, "CurrentBuildNumber");
//
// Convert the string to an integer.
//
if (lpBuild) { nBuild = atoi(lpBuild);
if (nWin2K < nBuild) { g_ai.fWinXP = TRUE; } else { g_ai.fWinXP = FALSE; } }
if (lpBuild) { creg.Free(lpBuild); } }
/*++
Routine Description:
Adds additional items to our menu.
Arguments:
hWnd - Handle to the parent window.
Return Value:
None.
--*/ void AddExtendedItems( IN HWND hWnd ) { HMENU hMenu, hSubMenu;
//
// Get menu handles, then add additional items.
//
hMenu = GetMenu(hWnd);
if (!hMenu) { return; }
hSubMenu = GetSubMenu(hMenu, 2);
if (!hSubMenu) { return; }
AppendMenu(hSubMenu, MF_ENABLED | MF_SEPARATOR, 1, NULL);
AppendMenu(hSubMenu, MF_ENABLED | MF_STRING, IDM_ACCESS_VIOLATION, "Access Violation");
AppendMenu(hSubMenu, MF_ENABLED | MF_STRING, IDM_EXCEED_BOUNDS, "Exceed Array Bounds");
AppendMenu(hSubMenu, MF_ENABLED | MF_STRING, IDM_FREE_INVALID_MEM, "Free Invalid Memory");
AppendMenu(hSubMenu, MF_ENABLED | MF_STRING, IDM_FREE_MEM_TWICE, "Free Memory Twice");
AppendMenu(hSubMenu, MF_ENABLED | MF_STRING, IDM_HEAP_CORRUPTION, "Heap Corruption");
AppendMenu(hSubMenu, MF_ENABLED | MF_STRING, IDM_PRIV_INSTRUCTION, "Privileged Instruction");
DrawMenuBar(hWnd); }
/*++
Routine Description:
Adds internal items to the menu bar.
Arguments:
hWnd - Handle to the parent window.
Return Value:
None.
--*/ void AddInternalItems( IN HWND hWnd ) { HMENU hMenu, hSubMenu;
//
// Get menu handles, then add additional items.
//
hMenu = GetMenu(hWnd);
if (!hMenu) { return; }
hSubMenu = GetSubMenu(hMenu, 2);
if (!hSubMenu) { return; }
AppendMenu(hSubMenu, MF_ENABLED | MF_SEPARATOR, 1, NULL);
AppendMenu(hSubMenu, MF_ENABLED | MF_STRING, IDM_PROPAGATION_TEST, "Propagation Test");
DrawMenuBar(hWnd); }
/*++
Routine Description:
Obtains an address for an exported function, then calls it. Used to test the include/exclude functionality in QFixApp. Note that is not documented anywhere.
Arguments:
hWnd - Window handle to be passed to the function.
Return Value:
None.
--*/ void TestIncludeExclude( IN HWND hWnd ) { HINSTANCE hInstance; HRESULT hr; char szDll[MAX_PATH]; const char szDemoDll[] = "demodll.dll";
LPFNDEMOAPPMESSAGEBOX DemoAppMessageBox;
hr = StringCchPrintf(szDll, sizeof(szDll), "%hs\\%hs", g_ai.szCurrentDir, szDemoDll);
if (FAILED(hr)) { return; }
hInstance = LoadLibrary(szDll);
if (hInstance) { //
// Get the address of the function.
//
DemoAppMessageBox = (LPFNDEMOAPPMESSAGEBOX)GetProcAddress(hInstance, "DemoAppMessageBox");
if (!DemoAppMessageBox) { FreeLibrary(hInstance); return; }
DemoAppMessageBox(hWnd);
FreeLibrary(hInstance); } }
/*++
Routine Description:
Saves the contents of the edit window to a file specified by the user.
Arguments:
None.
Return Value:
None.
--*/ void SaveContentsToFile( IN LPCSTR pszFileName ) { int nLen = 0; DWORD cbBytesWritten; HANDLE hFile; LPSTR pszData = NULL; char szError[MAX_PATH];
//
// Determine how much space we need for the buffer, then allocate it.
//
nLen = GetWindowTextLength(g_ai.hWndEdit);
if (nLen) {
pszData = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLen);
if (!pszData) { LoadString(g_ai.hInstance, IDS_BUFFER_ALLOC_FAIL, szError, sizeof(szError)); MessageBox(g_ai.hWndMain, szError, MAIN_APP_TITLE, MB_ICONERROR); return; }
//
// Get the text out of the text box and write it out to our file.
//
GetWindowText(g_ai.hWndEdit, pszData, nLen);
hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) { LoadString(g_ai.hInstance, IDS_FILE_CREATE_FAIL, szError, sizeof(szError)); MessageBox(g_ai.hWndMain, szError, MAIN_APP_TITLE, MB_ICONERROR); goto cleanup; }
WriteFile(hFile, pszData, nLen, &cbBytesWritten, NULL);
CloseHandle(hFile);
}
cleanup:
if (pszData) { HeapFree(GetProcessHeap(), 0, pszData); } }
/*++
Routine Description:
Displays a common dialog to the user which allows them to save the contents of the edit box to a file.
Arguments:
None.
Return Value:
None.
--*/ void ShowSaveDialog( void ) { char szFilter[MAX_PATH] = ""; char szTemp[MAX_PATH]; OPENFILENAME ofn = {0};
*szTemp = 0;
LoadString(g_ai.hInstance, IDS_SAVE_FILTER, szFilter, sizeof(szFilter));
ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = g_ai.hWndMain; ofn.hInstance = g_ai.hInstance; ofn.lpstrFilter = szFilter; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 1; ofn.lpstrFile = szTemp; ofn.nMaxFile = sizeof(szTemp); ofn.lpstrTitle = NULL; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = "txt"; ofn.lCustData = 0; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
if (GetSaveFileName(&ofn)) { SaveContentsToFile(szTemp); } }
|