|
|
//////////////////////////////////////////////////////////////////////////////
//
// STARTUP.CPP / Tuneup
//
// Microsoft Confidential
// Copyright (c) Microsoft Corporation 1998
// All rights reserved
//
// Functions for the startup startmenu group wizard page.
//
// 7/98 - Jason Cohen (JCOHEN)
//
//////////////////////////////////////////////////////////////////////////////
//
// Include file(s).
//
#include "main.h"
#include <shellapi.h>
#include "startup.h"
#include <lm.h>
//
// Internal defined values.
//
#define WM_REPLACEPROC WM_APP + 1
//
// Internal structure(s).
//
typedef struct _STARTUPLINK { BOOL bSelected; HICON hIcon; HICON hIconSelected; TCHAR szFileName[MAX_PATH]; TCHAR szDisplayName[MAX_PATH]; struct _STARTUPLINK *lpNext; } STARTUPLINK, *PSTARTUPLINK, *LPSTARTUPLINK;
typedef struct _USERDIR { LPTSTR lpPath; LPSTARTUPLINK lpList; } USERDIR, *PUSERDIR, *LPUSERDIR;
//
// Internal global variable(s).
//
TCHAR g_szUserName[UNLEN + CNLEN + 1] = NULLSTR; LPSTARTUPLINK g_lpStartupLinks = NULL;
//
// Inernal function prototype(s).
//
static VOID FreeStartupLink(LPSTARTUPLINK, LPTSTR); static VOID InitStartupUsers(HWND); static BOOL CALLBACK AddString(HKEY, LPTSTR, LPARAM); static PSID GetUserSid(VOID); static LPTSTR GetSidString(PSID); static LRESULT CALLBACK ListBox_Proc(HWND, UINT, WPARAM, LPARAM);
VOID InitStartupMenu(HWND hDlg) { PSID pSid = NULL; SID_NAME_USE SidName; TCHAR szKey[MAX_PATH + 1], szUserName[UNLEN], szCompName[CNLEN], szDomainName[DNLEN], szDisplayName[UNLEN + CNLEN + 1]; DWORD cbUserName = sizeof(szUserName) / sizeof(TCHAR), cbCompName = sizeof(szCompName), cbDomainName = sizeof(szDomainName) / sizeof(TCHAR); INT nIndex = CB_ERR; LPTSTR lpBuffer; LPUSERDIR lpUserDir; LONG lMove; RECT ParentRect, Rect;
// First things first, replace the list box windows procedure
// so we can get the single click message.
//
ListBox_Proc(GetDlgItem(hDlg, IDC_STARTUP), WM_REPLACEPROC, 0, 0L);
if ( IsUserAdmin() ) { // Init the combo box.
//
InitStartupUsers(GetDlgItem(hDlg, IDC_USERS)); } else { // Hide the combo box because user is not an administrator of
// this machine.
//
ShowWindow(GetDlgItem(hDlg, IDC_SELUSER), FALSE); ShowWindow(GetDlgItem(hDlg, IDC_USERS), FALSE);
// Now move the controls up so that they don't look out of place.
//
GetWindowRect(hDlg, &ParentRect); GetWindowRect(GetDlgItem(hDlg, IDC_SELUSER), &Rect); lMove = Rect.top;
GetWindowRect(GetDlgItem(hDlg, IDC_PROGRAMS), &Rect); lMove -= Rect.top; SetWindowPos(GetDlgItem(hDlg, IDC_PROGRAMS), NULL, Rect.left - ParentRect.left, (Rect.top + lMove) - ParentRect.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
GetWindowRect(GetDlgItem(hDlg, IDC_STARTUP), &Rect); SetWindowPos(GetDlgItem(hDlg, IDC_STARTUP), NULL, Rect.left - ParentRect.left, (Rect.top + lMove) - ParentRect.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
// Lastly update the text box so that it make sence without the combo box.
//
if ( lpBuffer = AllocateString(NULL, IDS_STARTUPTEXT) ) { SetDlgItemText(hDlg, IDC_STARTUPTEXT, lpBuffer); FREE(lpBuffer); }
}
if ( ( pSid = GetUserSid() ) && ( lpBuffer = GetSidString(pSid) ) ) { // First we need the profile directory for this user.
//
wsprintf(szKey, _T("%s\\%s"), g_szRegKeyProfiles, lpBuffer); FREE(lpBuffer); if ( lpBuffer = RegGetString(HKLM, szKey, _T("ProfileImagePath")) ) { // We only want them if the directory exists.
//
if ( EXIST(lpBuffer) ) { // Lookup the account info with the sid so we know the user and domain name.
//
if ( LookupAccountSid(NULL, pSid, szUserName, &cbUserName, szDomainName, &cbDomainName, &SidName) ) { // Create the display name (combine the computer/domain name with the
// user name unless the computer/domain name is the same as the computer name).
//
if ( ( GetComputerName(szCompName, &cbCompName) ) && ( lstrcmp(szCompName, szDomainName) == 0 ) ) lstrcpy(szDisplayName, szUserName); else wsprintf(szDisplayName, _T("%s\\%s"), szDomainName, szUserName);
// Copy the display name to the global buffer.
//
lstrcpy(g_szUserName, szDisplayName);
// Select the display name to the combo box.
//
if ( SendDlgItemMessage(hDlg, IDC_USERS, CB_SELECTSTRING, 0, (LPARAM) szDisplayName) == CB_ERR ) { // It wasn't found, so we need to add it (probably because the user isn't and admin).
//
if ( (nIndex = (INT)SendDlgItemMessage(hDlg, IDC_USERS, CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) szDisplayName)) > CB_ERR ) { if ( lpUserDir = (LPUSERDIR) MALLOC(sizeof(USERDIR)) ) { lpUserDir->lpPath = lpBuffer; if ( (nIndex = (INT)SendDlgItemMessage(hDlg, IDC_USERS, CB_SETITEMDATA, nIndex, (LPARAM) lpUserDir)) == CB_ERR ) FREE(lpUserDir); SendDlgItemMessage(hDlg, IDC_USERS, CB_SELECTSTRING, 0, (LPARAM) szDisplayName); } else { SendDlgItemMessage(hDlg, IDC_USERS, CB_DELETESTRING, nIndex, 0L); nIndex = CB_ERR; } } }
// Now populate the startup groups.
//
InitStartupList(hDlg); } } // If we just added this string, don't free the buffer
// that has the path to the profile.
//
if (nIndex < 0) FREE(lpBuffer); } } FREE(pSid); }
VOID ReleaseStartupMenu(HWND hDlg) { INT nCount, nIndex; DWORD_PTR dwBuffer; LPUSERDIR lpUserDir;
//
// We need to free the buffer associated with each CB item.
//
// First get the count.
//
if ( (nCount = (INT)SendDlgItemMessage(hDlg, IDC_USERS, CB_GETCOUNT, 0, 0L)) > CB_ERR ) { // Now go through all the items.
//
for (nIndex = 0; nIndex < nCount; nIndex++) { // Free the buffer stored in the CB item.
//
if ( (dwBuffer = SendDlgItemMessage(hDlg, IDC_USERS, CB_GETITEMDATA, nIndex, 0L)) != CB_ERR ) { lpUserDir = (LPUSERDIR)dwBuffer; FreeStartupLink(lpUserDir->lpList, lpUserDir->lpPath); FREE(lpUserDir->lpPath); FREE(lpUserDir); } } } }
BOOL InitStartupList(HWND hDlg) { INT iIndex, iString = IDS_STARTUP; DWORD_PTR dwBuffer; TCHAR szDir[MAX_PATH]; LPUSERDIR lpUserDir; HANDLE hFindFile; WIN32_FIND_DATA FindData; SHFILEINFO SHFileInfo; LPSTARTUPLINK *lpNextLink = NULL; LPTSTR lpOffice95, lpOffice97;
// First get the currently selected user from the combo box.
//
if ( ( (iIndex = (INT)SendDlgItemMessage(hDlg, IDC_USERS, CB_GETCURSEL, 0, 0L)) != CB_ERR ) && ( (dwBuffer = SendDlgItemMessage(hDlg, IDC_USERS, CB_GETITEMDATA, iIndex, 0L)) != CB_ERR ) ) { // Now remove all the current items from the list box.
//
SendDlgItemMessage(hDlg, IDC_STARTUP, LB_RESETCONTENT, 0, 0L);
// Now get the profile directory stored as the extra data in the combo box.
//
lpUserDir = (LPUSERDIR)dwBuffer;
// Check to see if we already have the files in this directory.
//
if ( lpUserDir->lpList ) { // Add the names arleady found to the list box and set the structure pointer as the list box item data.
//
for (lpNextLink = &(lpUserDir->lpList); *lpNextLink; lpNextLink = &((*lpNextLink)->lpNext)) if ( (iIndex = (INT)SendDlgItemMessage(hDlg, IDC_STARTUP, LB_ADDSTRING, 0, (LPARAM) (*lpNextLink)->szDisplayName)) >= 0 ) SendDlgItemMessage(hDlg, IDC_STARTUP, LB_SETITEMDATA, iIndex, (LPARAM) *lpNextLink); } else { // Get the name of Office stuff which we want it default unchecked.
//
lpOffice95 = AllocateString(NULL, IDS_OFFICE95_STARTUP); lpOffice97 = AllocateString(NULL, IDS_OFFICE97_STARTUP);
// Setup the pointer to the global structure that holds all the startup links.
//
lpNextLink = &lpUserDir->lpList;
// Loop through the two directories (the actual startup items and the disabled ones).
//
while ( iString ) { // Copy the profile path into the dir buffer.
//
lstrcpy(szDir, lpUserDir->lpPath);
// Tack on the startup group to the end.
//
LoadString(NULL, iString, szDir + lstrlen(szDir), (sizeof(szDir) / sizeof(TCHAR)) - lstrlen(szDir) - 1);
// Look for all the files.
//
if ( (hFindFile = FindFirstFile(szDir, &FindData)) != INVALID_HANDLE_VALUE ) { do { // Ignore directories.
//
if ( !(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) { //
// Ok, this is a link that we need to add. We need to build the
// structure for it.
//
// Now allocate the memory we need for the structure that holds
// all the info for the startup link.
//
if ( *lpNextLink = (LPSTARTUPLINK) MALLOC(sizeof(STARTUPLINK)) ) { // Create the full path to the file and add it to the structure.
//
(*lpNextLink)->szFileName[0] = NULLCHR; lstrcpyn((*lpNextLink)->szFileName, szDir, lstrlen(szDir)); lstrcat((*lpNextLink)->szFileName, FindData.cFileName);
// Get the selected small icon for the file.
//
SHGetFileInfo((*lpNextLink)->szFileName, 0, &SHFileInfo, sizeof(SHFILEINFO), SHGFI_ICON | SHGFI_SMALLICON | SHGFI_SELECTED); (*lpNextLink)->hIconSelected = SHFileInfo.hIcon;
// Get the normal small icon and the display name
// to use in the list box.
//
SHGetFileInfo((*lpNextLink)->szFileName, 0, &SHFileInfo, sizeof(SHFILEINFO), SHGFI_ICON | SHGFI_SMALLICON | SHGFI_DISPLAYNAME); (*lpNextLink)->hIcon = SHFileInfo.hIcon; lstrcpy((*lpNextLink)->szDisplayName, SHFileInfo.szDisplayName);
// Set the initial selected state for the item.
//
if ( ( lstrcmpi(lpOffice95, (*lpNextLink)->szDisplayName) == 0 ) || ( lstrcmpi(lpOffice97, (*lpNextLink)->szDisplayName) == 0 ) ) (*lpNextLink)->bSelected = FALSE; else (*lpNextLink)->bSelected = ( iString == IDS_STARTUP );
// Add the name to the list box and set the structure pointer as the list box item data.
//
if ( (iIndex = (INT)SendDlgItemMessage(hDlg, IDC_STARTUP, LB_ADDSTRING, 0, (LPARAM) SHFileInfo.szDisplayName)) >= 0 ) { SendDlgItemMessage(hDlg, IDC_STARTUP, LB_SETITEMDATA, iIndex, (LPARAM) *lpNextLink); lpNextLink = &((*lpNextLink)->lpNext); } else FREE(*lpNextLink); } } } while ( FindNextFile(hFindFile, &FindData) );
FindClose(hFindFile); }
if ( iString == IDS_STARTUP ) iString = IDS_APTUNEUP; else iString = 0; } } }
return TRUE; }
BOOL UserHasStartupItems() { PSID pSid; TCHAR szBuffer[MAX_PATH + 1]; LPTSTR lpBuffer; BOOL bFound = FALSE; INT iString = IDS_STARTUP; HANDLE hFindFile; WIN32_FIND_DATA FindData;
if ( ( pSid = GetUserSid() ) && ( lpBuffer = GetSidString(pSid) ) ) { // First we need the profile directory for this user.
//
wsprintf(szBuffer, _T("%s\\%s"), g_szRegKeyProfiles, lpBuffer); FREE(lpBuffer);
// Get the users profile directory.
//
if ( lpBuffer = RegGetString(HKLM, szBuffer, _T("ProfileImagePath")) ) { // We only want them if the directory exists.
//
if ( EXIST(lpBuffer) ) { // Loop through the two directories (the actual startup items and the disabled ones).
//
while ( iString ) { // Copy the user's profile directory into the buffer.
//
lstrcpy(szBuffer, lpBuffer);
// Tack on the startup group to the end.
//
LoadString(NULL, iString, szBuffer + lstrlen(szBuffer), (sizeof(szBuffer) / sizeof(TCHAR)) - lstrlen(szBuffer) - 1);
// Look for all the files.
//
if ( (hFindFile = FindFirstFile(szBuffer, &FindData)) != INVALID_HANDLE_VALUE ) { do { // Ignore directories.
//
if ( !(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) bFound = TRUE; } while ( FindNextFile(hFindFile, &FindData) );
FindClose(hFindFile); }
if ( iString == IDS_STARTUP ) iString = IDS_APTUNEUP; else iString = 0; } } FREE(lpBuffer); } } return bFound; }
VOID SelectUserRadio(HWND hDlg, BOOL bAllNotCur) { LPTSTR lpBuffer;
if (bAllNotCur) { if ( lpBuffer = AllocateString(NULL, IDS_ALLUSERS) ) { SendDlgItemMessage(hDlg, IDC_USERS, CB_SELECTSTRING, 0, (LPARAM) lpBuffer); FREE(lpBuffer); } } else SendDlgItemMessage(hDlg, IDC_USERS, CB_SELECTSTRING, 0, (LPARAM) g_szUserName); InitStartupList(hDlg); }
static VOID FreeStartupLink(LPSTARTUPLINK lpStartupLink, LPTSTR lpPath) { // Obviously don't want to free this memory if we were passed in NULL.
//
if ( lpStartupLink != NULL) { // Check to see if we need to move the file before
// we free it's structure. We dynamically allocate the MAX_PATH
// buffer so we don't fill up the stack with this recursive function.
//
if ( g_dwFlags & TUNEUP_FINISHED ) { TCHAR szNewPath[MAX_PATH], szOldPath[MAX_PATH]; LPTSTR lpOldName;
// Copy the profile path into the dir buffer.
//
lstrcpy(szNewPath, lpPath);
// Get the rest of the path info.
//
if ( lpStartupLink->bSelected ) LoadString(NULL, IDS_STARTUP, szNewPath + lstrlen(szNewPath), (sizeof(szNewPath) / sizeof(TCHAR)) - lstrlen(szNewPath)); else LoadString(NULL, IDS_APTUNEUP, szNewPath + lstrlen(szNewPath), (sizeof(szNewPath) / sizeof(TCHAR)) - lstrlen(szNewPath));
// Remove the * from the end of the path.
//
*(szNewPath + lstrlen(szNewPath) - 1) = NULLCHR;
// Make sure the path exists.
//
CreatePath(szNewPath);
// Get a pointer to the file name.
//
GetFullPathName(lpStartupLink->szFileName, sizeof(szOldPath) / sizeof(TCHAR), szOldPath, &lpOldName);
// Add the file name to the new path.
//
lstrcat(szNewPath, lpOldName);
// Now we have the full path to what the file name should be.
// If the file that should be there doesn't exist and the old
// file name does, move it.
//
if ( !EXIST(szNewPath) && EXIST(szOldPath) ) MoveFile(szOldPath, szNewPath); }
// Free the next link.
//
FreeStartupLink(lpStartupLink->lpNext, lpPath);
// Now finally free the memory for this link.
//
FREE(lpStartupLink); } }
static VOID InitStartupUsers(HWND hCtrlUsers) { INT iString[] = { IDS_ALLUSERS, IDS_DEFAULTUSER, 0 }, iId, iIndex; LPTSTR lpProfile, lpPath; LPUSERDIR lpUserDir; TCHAR szString[256];
RegEnumKeys(HKLM, g_szRegKeyProfiles, (REGENUMKEYPROC) AddString, (LPARAM) hCtrlUsers, FALSE);
if ( lpProfile = RegGetString(HKLM, g_szRegKeyProfiles, g_szRegValProfileDir) ) { // Loop through the default users.
//
for (iId = 0; iString[iId] != 0; iId++) { // Load the string and allocate memory for it and the full path.
//
if ( ( LoadString(NULL, iString[iId], szString, sizeof(szString) / sizeof(TCHAR)) ) && ( lpPath = (LPTSTR) MALLOC(sizeof(TCHAR) * (lstrlen(lpProfile) + lstrlen(szString) + 2)) ) ) { // Create the full path.
//
wsprintf(lpPath, _T("%s\\%s"), lpProfile, szString);
// Make sure the path exists.
//
if ( EXIST(lpPath) ) { // Add the name to the combo box.
//
if ( (iIndex = (INT)SendMessage(hCtrlUsers, CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) szString)) > CB_ERR ) { // Add the path data to the name.
//
if ( lpUserDir = (LPUSERDIR) MALLOC(sizeof(USERDIR)) ) { lpUserDir->lpPath = lpPath; if ( (iIndex = (INT)SendMessage(hCtrlUsers, CB_SETITEMDATA, iIndex, (LPARAM) lpUserDir)) == CB_ERR ) FREE(lpUserDir); } else { SendDlgItemMessage(hCtrlUsers, IDC_USERS, CB_DELETESTRING, iIndex, 0L); iIndex = CB_ERR; } } } else iIndex = CB_ERR;
// If anything failed, we should free the buffer.
//
if ( iIndex <= CB_ERR ) FREE(lpPath);
} }
// Free the path to the profiles.
//
FREE(lpProfile); } }
static BOOL CALLBACK AddString(HKEY hKey, LPTSTR lpKey, LPARAM lParam) { LPTSTR lpBuffer; LPUSERDIR lpUserDir; PSID pSid; TCHAR szUserName[UNLEN], szCompName[CNLEN], szDomainName[DNLEN], szDisplayName[UNLEN + CNLEN + 1]; DWORD cbUserName = sizeof(szUserName) / sizeof(TCHAR), cbCompName = sizeof(szCompName), cbDomainName = sizeof(szDomainName) / sizeof(TCHAR); INT nIndex = CB_ERR; SID_NAME_USE SidName;
// First we need the profile directory for this user.
//
if ( lpBuffer = RegGetString(hKey, NULL, g_szRegValProfilePath) ) { // We only want them if the directory exists.
//
if ( EXIST(lpBuffer) ) { // Now get the sid for this user from the registry.
//
if ( pSid = (PSID) RegGetBin(hKey, NULL, _T("Sid")) ) { // Lookup the account info with the sid so we know the user and domain name.
//
if ( LookupAccountSid(NULL, pSid, szUserName, &cbUserName, szDomainName, &cbDomainName, &SidName) ) { // Create the display name (combine the computer/domain name with the
// user name unless the computer/domain name is the same as the computer name.
//
if ( ( GetComputerName(szCompName, &cbCompName) ) && ( lstrcmp(szCompName, szDomainName) == 0 ) ) lstrcpy(szDisplayName, szUserName); else wsprintf(szDisplayName, _T("%s\\%s"), szDomainName, szUserName);
// Add the display name to the combo box.
//
if ( (nIndex = (INT)SendMessage((HWND) lParam, CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) szDisplayName)) > CB_ERR ) { if ( lpUserDir = (LPUSERDIR) MALLOC(sizeof(USERDIR)) ) { lpUserDir->lpPath = lpBuffer; if ( (nIndex = (INT)SendMessage((HWND) lParam, CB_SETITEMDATA, nIndex, (LPARAM) lpUserDir)) == CB_ERR ) FREE(lpUserDir); } else { SendDlgItemMessage((HWND) lParam, IDC_USERS, CB_DELETESTRING, nIndex, 0L); nIndex = CB_ERR; } } } FREE(pSid); } }
// If the add never happend, we should free the buffer.
//
if (nIndex < 0) FREE(lpBuffer); }
// Return TRUE to keep proccessing the registry keys.
//
return TRUE; }
static PSID GetUserSid() { PTOKEN_USER pUser = NULL; DWORD dwSize = 0; HANDLE hToken = INVALID_HANDLE_VALUE; PSID pSid = NULL;
// Get the current process token and
// allocate space for and get the user info.
//
if ( !( ( OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) ) && ( !GetTokenInformation(hToken, TokenUser, pUser, dwSize, &dwSize) ) && ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) && ( pUser = (PTOKEN_USER) MALLOC(dwSize) ) && ( GetTokenInformation(hToken, TokenUser, pUser, dwSize, &dwSize) ) && ( pSid = (PSID) MALLOC(dwSize = GetLengthSid(pUser->User.Sid)) ) && ( CopySid(dwSize, pSid, pUser->User.Sid) ) ) )
// If all those items didn't succeed, we need to free the sid.
// This macro automatically checks for NULL before freeing and
// sets to NULL after freeing.
//
FREE(pSid);
// Free up and close up the resources used.
//
FREE(pUser); if ( hToken != INVALID_HANDLE_VALUE ) CloseHandle(hToken);
return pSid; }
static LPTSTR GetSidString(PSID pSid) { LPTSTR lpszSid = NULL; PSID_IDENTIFIER_AUTHORITY pSidIA; DWORD dwSubAuthorities, dwCounter, dwSidSize;
// Check to make sure the Sid is vallid.
//
if ( pSid && IsValidSid(pSid) ) { // Obtain SidIdentifierAuthority
//
pSidIA = GetSidIdentifierAuthority(pSid);
// Obtain SidSubAuthority count
//
dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
// Compute buffer length:
// S-SID_REVISION- + identifierauthority- + subauthorities- + NULL
//
dwSidSize = (15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
// Automatically allocate the space needed for the Sid.
//
if ( lpszSid = (LPTSTR) MALLOC(dwSidSize) ) { // Prepare S-SID_REVISION-
//
dwSidSize = wsprintf(lpszSid, TEXT("S-%lu-"), SID_REVISION);
// Prepare SidIdentifierAuthority.
//
if ( ( pSidIA->Value[0] != 0 ) || ( pSidIA->Value[1] != 0 ) ) { dwSidSize += wsprintf( lpszSid + lstrlen(lpszSid), _T("0x%02hx%02hx%02hx%02hx%02hx%02hx"), (USHORT) pSidIA->Value[0], (USHORT) pSidIA->Value[1], (USHORT) pSidIA->Value[2], (USHORT) pSidIA->Value[3], (USHORT) pSidIA->Value[4], (USHORT) pSidIA->Value[5] ); } else { dwSidSize += wsprintf(lpszSid + lstrlen(lpszSid), _T("%lu"), (ULONG) (pSidIA->Value[5] ) + (ULONG) (pSidIA->Value[4] << 8) + (ULONG) (pSidIA->Value[3] << 16) + (ULONG) (pSidIA->Value[2] << 24) ); }
// Loop through SidSubAuthorities.
//
for (dwCounter = 0; dwCounter < dwSubAuthorities; dwCounter++) dwSidSize += wsprintf(lpszSid + dwSidSize, _T("-%lu"), *GetSidSubAuthority(pSid, dwCounter)); } } return lpszSid; }
BOOL StartupDrawItem(HWND hWnd, const DRAWITEMSTRUCT * lpDrawItem) {
TCHAR szBuffer[MAX_PATH]; BOOL bRestore = FALSE; COLORREF crText, crBk; DWORD dwColor; RECT rect; HBRUSH hbrBack; LPSTARTUPLINK lpStartupLink;
static HICON hIconCheck = NULL, hIconUnCheck = NULL;
switch ( lpDrawItem->itemAction ) { case ODA_SELECT: case ODA_DRAWENTIRE:
if (lpDrawItem->itemState & ODS_SELECTED) { // Set new text/background colors and store the old ones away.
//
crText = SetTextColor(lpDrawItem->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); crBk = SetBkColor(lpDrawItem->hDC, GetSysColor(COLOR_HIGHLIGHT));
// Restore the text and background colors when we are finished.
//
bRestore = TRUE;
// Get the hightlight color to fill in the listbox item.
//
dwColor = GetSysColor(COLOR_HIGHLIGHT);
} else { // Get the window color so we can clear the listbox item.
//
dwColor = GetSysColor(COLOR_WINDOW); }
// Fill entire item rectangle with the appropriate color
//
hbrBack = CreateSolidBrush(dwColor); FillRect(lpDrawItem->hDC, &(lpDrawItem->rcItem), hbrBack); DeleteObject(hbrBack);
// Display the icon associated with the item.
//
if ( lpStartupLink = (LPSTARTUPLINK) SendMessage(lpDrawItem->hwndItem, LB_GETITEMDATA, lpDrawItem->itemID, (LPARAM) 0) ) { // Load the checked and unchecked icons if we don't
// have them already.
//
if ( hIconCheck == NULL ) hIconCheck = (HICON) LoadImage(g_hInst, MAKEINTRESOURCE(IDI_CHECK), IMAGE_ICON, 16, 16, 0); if ( hIconUnCheck == NULL ) hIconUnCheck = (HICON) LoadImage(g_hInst, MAKEINTRESOURCE(IDI_UNCHECK), IMAGE_ICON, 16, 16, 0);
// Draw the checked or unchecked icon.
//
DrawIconEx( lpDrawItem->hDC, lpDrawItem->rcItem.left, lpDrawItem->rcItem.top, lpStartupLink->bSelected ? hIconCheck : hIconUnCheck, lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top, lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top, 0, 0, DI_NORMAL);
// Draw the items icon.
//
DrawIconEx( lpDrawItem->hDC, lpDrawItem->rcItem.left + lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top + 2, lpDrawItem->rcItem.top, (lpDrawItem->itemState & ODS_SELECTED) ? lpStartupLink->hIconSelected : lpStartupLink->hIcon, lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top, lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top, 0, 0, DI_NORMAL); }
// Display the text associated with the item.
//
SendMessage(lpDrawItem->hwndItem, LB_GETTEXT, lpDrawItem->itemID, (LPARAM) szBuffer);
TextOut( lpDrawItem->hDC, lpDrawItem->rcItem.left + ((lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top + 2) * 2), lpDrawItem->rcItem.top + 1, szBuffer, lstrlen(szBuffer));
if (bRestore) { // Restore original text and background colors.
//
SetTextColor(lpDrawItem->hDC, crText); SetBkColor(lpDrawItem->hDC, crBk); } break;
case ODA_FOCUS:
// Get rectangle coordinates for listbox item.
//
SendMessage(lpDrawItem->hwndItem, LB_GETITEMRECT, lpDrawItem->itemID, (LPARAM) &rect); DrawFocusRect(lpDrawItem->hDC, &rect); break;
}
return TRUE; }
VOID StartupSelectItem(HWND hWndCtrl) { INT nIndex; LPSTARTUPLINK lpStartupLink;
if ( ( (nIndex = (INT)SendMessage(hWndCtrl, LB_GETCURSEL, 0, 0L)) >= 0 ) && ( (lpStartupLink = (LPSTARTUPLINK) SendMessage(hWndCtrl, LB_GETITEMDATA, nIndex, 0L)) != NULL ) ) { lpStartupLink->bSelected = !lpStartupLink->bSelected; SendMessage(hWndCtrl, LB_SETCURSEL, (WPARAM) nIndex, 0L); } }
static LRESULT CALLBACK ListBox_Proc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { static WNDPROC ListBoxProc = NULL; LONG rc = 0;
if ( iMsg == WM_REPLACEPROC ) { // Replace the default Windows procedure for the list box. AKA: The Glorious Hack!
//
if ( ( ListBoxProc == NULL ) && ( (ListBoxProc = (WNDPROC) GetWindowLongPtr(hWnd, GWLP_WNDPROC)) != NULL ) ) SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR) ListBox_Proc); return rc; }
// Just a safty catch to make sure we have the default windows procedure.
//
if ( ( ListBoxProc == NULL ) && ( (ListBoxProc = (WNDPROC) GetWindowLongPtr(hWnd, GWLP_WNDPROC)) == NULL ) ) return rc;
// Let the standard window proc handle the message.
//
rc = (LONG)CallWindowProc((WNDPROC) ListBoxProc, hWnd, iMsg, wParam, lParam);
// Do the single click thing if we need to.
//
if ( ( iMsg == WM_LBUTTONDOWN ) && ( (LOWORD(lParam) < 16) && (HIWORD(lParam) < (SendMessage(hWnd, LB_GETCOUNT, 0, 0L) * 16)) ) ) StartupSelectItem(hWnd);
return rc; }
|