/* File: AppLock.cpp Project: Author: ScottLe Date: 1/31/00 Comments: AppMan application locking (pinning) Tab in Game Control Panel. Copyright (c) 1999, 2000 Microsoft Corporation */ // This is necessary LVS_EX_INFOTIP #if (_WIN32_IE < 0x400) #undef _WIN32_IE #define _WIN32_IE 0x400 #if 0 typedef struct tagNMITEMACTIVATE{ NMHDR hdr; int iItem; int iSubItem; UINT uNewState; UINT uOldState; UINT uChanged; POINT ptAction; LPARAM lParam; UINT uKeyFlags; } NMITEMACTIVATE, FAR *LPNMITEMACTIVATE; #endif #endif #include #include #include #include // For RegisterDeviceNotification stuff! #include // for DBT_ defines!!! #include // for listview #include // for TCHAR #include // for _alloca #include "hsvrguid.h" #include "cpanel.h" #include "resource.h" #include "joyarray.h" #ifdef MAX_DEVICES // The control panel and the addman both define MAX_DEVICES, we'll use the AppMan supplied version #undef MAX_DEVICES #endif #include #if _DEBUG #define Assert(x) { if(!(x)) { DebugBreak(); }} #else #define Assert(x) #endif static HWND ghDlg; static HWND hAppManCheckBox; extern const DWORD gaHelpIDs[]; extern HINSTANCE ghInstance; // // GLOBALS // static BOOL g_ListPopulated = FALSE; static int g_nm_click = -1; static BOOL g_nm_click_state = FALSE; static BOOL g_DlgInitialized = FALSE; static BOOL g_ChkBoxUpdate = FALSE; static GUID *g_lpsGUID = NULL; extern IApplicationManagerAdmin *g_IAppManAdmin; static struct { BOOL isValid; int iItem; BOOL isClicked; } g_ItemChanged; // constants const short NO_ITEM = -1; static short iItem = NO_ITEM; // index of selected item // Forwards // // local forwards // static BOOL OnInitDialog(HWND hDlg, HWND hWnd, LPARAM lParam); static void OnCommand(HWND hDlg, int id, HWND hWndCtl, UINT code); static BOOL OnNotify(HWND hDlg, WPARAM idFrom, LPARAM lParam); static void OnScroll(HWND hDlg, WPARAM wParam); static void OnListCtrl_Select(HWND hDlg); static void OnListCtrl_DblClick(HWND hDlg); static void OnListCtrl_UpdateFromCheckBoxes( HWND hDlg ); static void OnAdvHelp (LPARAM); //static void OnContextMenu (WPARAM wParam, LPARAM lParam); static void OnListviewContextMenu (HWND hWnd, LPARAM lParam ); // util fcns static int MyInsertItem( HWND hCtrl, LPTSTR lpszBuff, int iItem ); // replaced from cpanel.cpp static void PostDlgItemEnableWindow( HWND hDlg, USHORT nItem, BOOL bEnabled ); static void EnableDiskManageControls( HWND hDlg, BOOL bEnable ); static void EnableScrollBarAndText( HWND hDlg, BOOL bEnable ); //static void EnableAllControls( HWND hDlg, BOOL bEnable ); DWORD GetCurrentDeviceFromList( HWND hDlg, BYTE *nItem = NULL ); static void ConfigureListControl( HWND hDlg ); static void PopulateListControl( HWND hDlg, BYTE nItem ); void UpdateCurrentDeviceFromScrollBar( HWND hDlg, DWORD newPos ); //void UpdateListAndScrollBar( HWND hDlg, BOOL bJustScrollBar = FALSE ); // From AppMan.cpp extern HRESULT AppManShutdown(); extern HRESULT AppManInit(); extern BOOL AppManInitialized(); // // from cpanel.cpp // extern void SetItemText( HWND hCtrl, BYTE nItem, BYTE nSubItem, LPTSTR lpStr); extern void InsertColumn(HWND hCtrl, BYTE nColumn, USHORT nStrID, USHORT nWidth); extern BOOL SetItemData( HWND hCtrl, BYTE nItem, DWORD dwFlag ); extern DWORD GetItemData(HWND hCtrl, BYTE nItem ); extern void SetListCtrlItemFocus ( HWND hCtrl, BYTE nItem ); /////////////////////////////////////////////////////////////////////////////// // FUNCTION: AppManLockProc(HWND hDlg, ULONG uMsg, WPARAM wParam, LPARAM lParam) // // PARAMETERS: hDlg - // uMsg - // wParam - // lParam - // // PURPOSE: Main callback function for "Appman" sheet /////////////////////////////////////////////////////////////////////////////// BOOL WINAPI AppManLockProc(HWND hDlg, ULONG uMsg, WPARAM wParam, LPARAM lParam) { switch( uMsg ) { case WM_ACTIVATEAPP: if( wParam ) { HWND hListCtrl = NULL; hListCtrl = GetDlgItem((HWND) wParam, IDC_APPMAN_DRIVE_LIST); SetListCtrlItemFocus(hListCtrl, (BYTE)iItem); } break; case WM_DEVICECHANGE: switch( (UINT)wParam ) { case DBT_DEVICEARRIVAL: // case DBT_DEVICEREMOVECOMPLETE: break; } break; case WM_LBUTTONDOWN: // Click Drag service for PropSheets! //PostMessage(GetParent(hDlg), WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam); break; case WM_INITDIALOG: if( !HANDLE_WM_INITDIALOG(hDlg, wParam, lParam, OnInitDialog) ) { // Fix #108983 NT, Remove Flash on Error condition. SetWindowPos(::GetParent(hDlg), HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW); DestroyWindow(hDlg); } return(TRUE); case WM_COMMAND: HANDLE_WM_COMMAND(hDlg, wParam, lParam, OnCommand); return(TRUE); case WM_DESTROY: //return(HANDLE_WM_DESTROY(hDlg, wParam, lParam, OnDestroy)); //jchauvin 04/10/2000 Fix Build break in Win64 free( g_lpsGUID ); g_lpsGUID = NULL; return(TRUE); case WM_NOTIFY: return OnNotify(hDlg, wParam, lParam); case WM_HELP: // OnAdvHelp(lParam); return(TRUE); case WM_CONTEXTMENU: // OnContextMenu(wParam, lParam); return(TRUE); default: break; } return(0); } /////////////////////////////////////////////////////////////////////////////// // FUNCTION: OnInitDialog(HWND hDlg, HWND hWnd, LPARAM lParam) // // PARAMETERS: hDlg - // hWnd - // lParam - // // PURPOSE: WM_INITDIALOG message handler /////////////////////////////////////////////////////////////////////////////// BOOL OnInitDialog(HWND hDlg, HWND hWnd, LPARAM lParam) { HRESULT hr = S_OK; hr = AppManInit(); // // init globals // ZeroMemory( &g_ItemChanged, sizeof(g_ItemChanged)); g_DlgInitialized = FALSE; if( FAILED(hr) ) { // // Disable everything // // EnableAllControls(hDlg, FALSE); // // popup saying: hey you need appman installed ? // } else { ghDlg = hDlg; // // Set defaults // // // Configure the List control, and then fill it in // ConfigureListControl( hDlg ); PopulateListControl( hDlg, 0 ); g_DlgInitialized = TRUE; } return(TRUE); } /////////////////////////////////////////////////////////////////////////////// // FUNCTION: OnCommand(HWND hDlg, int id, HWND hWndCtl, UINT code) // // PARAMETERS: hDlg - // id - // hWndCtl - // code - // // PURPOSE: WM_COMMAND message handler /////////////////////////////////////////////////////////////////////////////// void OnCommand(HWND hDlg, int id, HWND hWndCtl, UINT code) { HRESULT hr = S_OK; #if 0 switch( id ) { case IDS_WHATSTHIS: { // point to help file LPTSTR pszHelpFileName = new TCHAR[STR_LEN_32]; ASSERT (pszHelpFileName); if( LoadString(ghInstance, IDS_HELPFILENAME, pszHelpFileName, STR_LEN_32) ) WinHelp((HWND)hDlg, pszHelpFileName, HELP_WM_HELP, (ULONG_PTR)gaHelpIDs); #ifdef _DEBUG else OutputDebugString(TEXT("JOY.CPL: AppMan.cpp: OnCommand: LoadString Failed to find IDS_HELPFILENAME!\n")); #endif // _DEBUG if( pszHelpFileName ) delete[] (pszHelpFileName); } break; /* case IDC_APPMAN_MANAGE_DISK: { BOOL isChecked = (IsDlgButtonChecked(hDlg, id)) ? TRUE : FALSE; EnableDiskManageControls( hDlg, !isChecked ); } break; */ default: break; } #endif } //////////////////////////////////////////////////////////////////////////////// // // FUNCTION: OnNotify(HWND hDlg, WPARAM idFrom, NMHDR* pnmhdr) // // PARAMETERS: hDlg - // idFrom - ID of control sending WM_NOTIFY message // pnmhdr - // // PURPOSE: WM_NOTIFY message handler //////////////////////////////////////////////////////////////////////////////// static DWORD ct=0L; BOOL OnNotify(HWND hDlg, WPARAM idFrom, LPARAM lParam) { NMLISTVIEW *pnmv = NULL; LPNMHDR pnmhdr = (LPNMHDR)lParam; switch (pnmhdr->code) { // 4/13/2000(RichGr): Repopulate the List Control if we reacquire the focus. // This keeps the data in sync with installs and uninstalls. case NM_SETFOCUS: { PopulateListControl(hDlg, 0); break; } case LVN_ITEMCHANGED: pnmv = (LPNMLISTVIEW) lParam; if( idFrom == IDC_APPMAN_PIN_LIST ) { // this is called if a new item has been selected // or if the user clicked on the checkbox, changing state #ifdef _DEBUG { TCHAR tstring[256]; NMITEMACTIVATE *pitemact = (LPNMITEMACTIVATE)lParam; _stprintf(tstring, TEXT("JOY.CPL: AppLock.cpp: OnNotify: LVN_ITEMCHANGED, ct=%ld,idFrom=%lx, item=%lx uChanged=%lx uNewState=%lx uOldState=%lx lParam=%lx\n"), ++ct,idFrom,pitemact->iItem,pitemact->uChanged,pitemact->uNewState,pitemact->uOldState,pitemact->lParam); OutputDebugString(tstring); } #endif // _DEBUG if ( AppManInitialized() && g_DlgInitialized && (pnmv->uNewState & LVIS_SELECTED || pnmv->uNewState == 0x1000 || pnmv->uNewState == 0x2000) && // TODO: Find definitions for x1000 and x2000 (check box state change in a list view control) g_ChkBoxUpdate ) { NMITEMACTIVATE *ll = (LPNMITEMACTIVATE)lParam; HWND hLC = GetDlgItem(hDlg, IDC_APPMAN_PIN_LIST); g_ItemChanged.isValid = TRUE; g_ItemChanged.iItem = ll->iItem; g_ItemChanged.isClicked = FALSE; // // this flag is VERY important for consistent state changes // and eliminating race conditions // g_ChkBoxUpdate = FALSE; OnListCtrl_UpdateFromCheckBoxes( hDlg ); g_ChkBoxUpdate = TRUE; g_ItemChanged.isValid = FALSE; g_ItemChanged.iItem = ll->iItem; OnListCtrl_Select( hDlg ); } return TRUE; break; } // if } // switch return(0); } void OnListCtrl_UpdateFromCheckBoxes( HWND hDlg ) { #if 1 HRESULT hResult; BOOL bIsAppManPinned = FALSE; BOOL bDoToggle = FALSE; BYTE nItem = 0; GUID *pGuid = NULL; IApplicationManager * lpApplicationManager; IApplicationEntry * lpApplicationEntry; DWORD dwIndex; // // go through each item, check the box & set pinning // HWND hLC = GetDlgItem(hDlg, IDC_APPMAN_PIN_LIST); if( !hLC ) return; int iItem = -1; //while( (iItem = ListView_GetNextItem( hLC, iItem, LVNI_ALL )) >= 0 ) if( g_ItemChanged.isValid ) { // // very important: tell the system that this information is no longer // valid. Hence we won't recurse mysteriously or unpredictably. // g_ItemChanged.isValid = FALSE; iItem = g_ItemChanged.iItem; BOOL bIsCheckBoxPinned = !(ListView_GetCheckState( hLC, iItem )); // Check box has the new state NOW // Set the pin state using the GUID to identify the app //JWC 4/10/2000 Added to fix Win64 Build problem dwIndex = (DWORD) GetItemData(hLC, (BYTE)iItem ); pGuid = (GUID *) ((ULONG_PTR)g_lpsGUID + (ULONG_PTR)dwIndex*sizeof(GUID)); // Find out what the pin state is in AppMan // Get an Application Manager interface hResult = CoCreateInstance(CLSID_ApplicationManager, NULL, CLSCTX_INPROC_SERVER, IID_ApplicationManager, (LPVOID *) &lpApplicationManager); if (SUCCEEDED(hResult)) { // Get an application entry object. hResult = lpApplicationManager->CreateApplicationEntry(&lpApplicationEntry); if (SUCCEEDED(hResult)) { // Set the app's GUID hResult = lpApplicationEntry->SetProperty(APP_PROPERTY_GUID, pGuid, sizeof(GUID)); if (SUCCEEDED(hResult)) { // Populate the app info structure hResult = lpApplicationManager->GetApplicationInfo(lpApplicationEntry); if (SUCCEEDED(hResult)) { // Get the current PIN state of the app hResult = lpApplicationEntry->GetProperty(APP_PROPERTY_PIN, &bIsAppManPinned, sizeof(bIsAppManPinned)); if (SUCCEEDED(hResult)) { // bIsAppManPinned is the state appman has for the application. // bIsCheckBoxPinned is the check box state (checked = true = not pinned) // Since AppMan's pinning state for an app is a toggle we could get out of sync // due to redraw or timing issues with the list view control -- so, // we need to make sure that the check box's state is insync with AppMan. // When in doubt, force it to the displayed state of the check box. // Truth table: // // AppManPinned CheckBoxPinned (T=not checked) DoToggle Reason // T T No Same State Already (sync error!) // F F No Same State Already (sync error!) // T F Yes New State Selected // F T Yes New State Selected // if (bIsAppManPinned != bIsCheckBoxPinned) bDoToggle = TRUE; else { // ERR: BUG BUG: The control panel and appman are out of sync, this is an error. bDoToggle = FALSE; #ifdef _DEBUG OutputDebugString(TEXT("JOY.CPL: AppLock.cpp: Pinning Update, AppMan and Check box states are out of sync!\n")); #endif // _DEBUG } if (bDoToggle && pGuid && g_IAppManAdmin) // Toggle the pin state hResult = g_IAppManAdmin->DoApplicationAction(ACTION_APP_PIN, pGuid, 0, (LPVOID) NULL, sizeof(DWORD)); // ERR: Handle error conditions } } } lpApplicationEntry->Release(); } lpApplicationManager->Release(); } } g_ChkBoxUpdate = TRUE; #endif } void OnListCtrl_Select(HWND hDlg) { // // set focus on that item // HWND hLC = GetDlgItem(hDlg, IDC_APPMAN_PIN_LIST); SetListCtrlItemFocus( hLC, (BYTE)g_ItemChanged.iItem ); } int MyInsertItem( HWND hCtrl, LPTSTR lpszBuff, int iItem ) { LPLVITEM plvItem = (LPLVITEM)_alloca(sizeof(LVITEM)); ASSERT (plvItem); ZeroMemory( plvItem, sizeof( LVITEM ) ); plvItem->mask = LVIF_TEXT; plvItem->pszText = lpszBuff; plvItem->cchTextMax = lstrlen(lpszBuff); plvItem->iItem = iItem; return ListView_InsertItem(hCtrl, (const LPLVITEM)plvItem); } #define APPMAN_ADV_PIN_CHECKBOX 0 #define APPMAN_ADV_PIN_TITLENAME 1 #define IDS_APPMANPIN_CHECKBOX 40043 #define IDS_APPMANPIN_TITLENAME 40044 void ConfigureListControl( HWND hDlg ) { #if 1 HWND hLC; hLC = GetDlgItem(hDlg, IDC_APPMAN_PIN_LIST); ::SendMessage( hLC , LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES | LVS_EX_HEADERDRAGDROP // LVS_EX_TWOCLICKACTIVATE // LVN_ITEMACTIVATE (WM_NOTIFY) ); RECT rc; GetClientRect(hLC, &rc); DWORD w = rc.right-rc.left; DWORD w1 = w / 3; // 1/3 of width DWORD w2 = w - w1; // 2/3 of the width InsertColumn(hLC, APPMAN_ADV_PIN_CHECKBOX, IDS_APPMANPIN_CHECKBOX, (USHORT)(w1)); InsertColumn(hLC, APPMAN_ADV_PIN_TITLENAME,IDS_APPMANPIN_TITLENAME, (USHORT)(w2)); #endif } //STDMETHODIMP CApplicationManagerAdmin::DoApplicationAction(const DWORD dwAction, const GUID * lpGuid, LPVOID lpData, const DWORD dwDataLen) //STDMETHODIMP CApplicationManagerAdmin::EnumApplications(const DWORD dwApplicationIndex, IApplicationEntry * lpObject) // populates from appman state void PopulateListControl( HWND hDlg, BYTE nItem ) { #if 1 HRESULT hr = S_OK; BOOL isExcluded = FALSE; UCHAR listIndex = (UCHAR)0; IApplicationManager *lpApplicationManager; IApplicationEntry *lpApplicationEntry; HRESULT hResult; DWORD dwIndex = 0L; TCHAR szString[MAX_PATH]; GUID sGuid; g_ListPopulated = FALSE; g_ChkBoxUpdate = FALSE; Assert( AppManInitialized() ); HWND hLC = GetDlgItem(hDlg, IDC_APPMAN_PIN_LIST); // Turn Redraw off here else it will flicker! ::SendMessage(hLC, WM_SETREDRAW, (WPARAM)FALSE, 0); // Out with the old... ::SendMessage(hLC, LVM_DELETEALLITEMS, 0, 0); //JWC 04/10/2000 Fixing build break in Win64 code g_lpsGUID = (GUID *)malloc(sizeof(GUID)); if (g_lpsGUID == NULL) { //Cannot allocate memory hResult = E_UNEXPECTED; } // Get an Application Manager interface hResult = CoCreateInstance(CLSID_ApplicationManager, NULL, CLSCTX_INPROC_SERVER, IID_ApplicationManager, (LPVOID *) &lpApplicationManager); if (SUCCEEDED(hResult) && g_IAppManAdmin) { // Get an application entry object. This will be populated during the Enumeration loop hResult = lpApplicationManager->CreateApplicationEntry(&lpApplicationEntry); if (SUCCEEDED(hResult)) { // Enumerate all the applications AppMan knows about dwIndex = 0; while (SUCCEEDED(g_IAppManAdmin->EnumApplications(dwIndex, lpApplicationEntry))) { // For each app, get information about it (Pinning state, title, GUID etc) and put in the list DWORD dwState = 0L; // App must be in a good state hResult = lpApplicationEntry->GetProperty(APP_PROPERTY_STATE, &dwState, sizeof(dwState)); dwState &= APP_STATE_MASK; if (!SUCCEEDED(hResult) || dwState == APP_STATE_INSTALLING || dwState == APP_STATE_UNSTABLE) { dwIndex++; continue; // Skip bad apps } else // Good app... { // Create the check box int actualListIndex = MyInsertItem( hLC, _T(""), dwIndex ); // Get the app's GUID hResult = lpApplicationEntry->GetProperty(APP_PROPERTY_GUID, &sGuid, sizeof(sGuid)); if (SUCCEEDED(hResult)) { // Allocate a GUID // ISSUE-2001/03/29-timgill Need error handling //JWC 04/10/2000 Fixing problem with GUID for Win64 g_lpsGUID = (GUID *)realloc((void*)g_lpsGUID,(dwIndex+1)* sizeof(GUID)); *(GUID *)((ULONG_PTR)g_lpsGUID+((ULONG_PTR)(dwIndex)*sizeof(GUID)))= sGuid; SetItemData(hLC, (BYTE)actualListIndex, dwIndex ); } // Get Pin state { DWORD bPinned = FALSE; hResult = lpApplicationEntry->GetProperty(APP_PROPERTY_PIN, &bPinned, sizeof(bPinned)); if (SUCCEEDED(hResult)) ListView_SetCheckState( hLC, actualListIndex, (BOOL)!bPinned ); // Checked=not pinned } // TODO: Company name and/or signature...? // hResult = lpApplicationEntry->GetProperty(APP_PROPERTY_COMPANYNAME | APP_PROPERTY_STR_ANSI, &szString, sizeof(szString)); #ifdef _UNICODE hResult = lpApplicationEntry->GetProperty(APP_PROPERTY_SIGNATURE | APP_PROPERTY_STR_UNICODE, &szString, sizeof(szString)); #else hResult = lpApplicationEntry->GetProperty(APP_PROPERTY_SIGNATURE | APP_PROPERTY_STR_ANSI, &szString, sizeof(szString)); #endif // Set the title name in the "title column" if (SUCCEEDED(hResult)) SetItemText(hLC, (BYTE)actualListIndex, APPMAN_ADV_PIN_TITLENAME, szString); } dwIndex++; } } lpApplicationEntry->Release(); } lpApplicationManager->Release(); // // set focus on that item // SetListCtrlItemFocus( hLC, nItem ); // // Turn the redraw flag back on! // ::SendMessage (hLC, WM_SETREDRAW, (WPARAM)TRUE, 0); g_ListPopulated = TRUE; g_ChkBoxUpdate = TRUE; #endif } void EnableScrollBarAndText( HWND hDlg, BOOL bEnable ) { #if 0 HWND hwnd; // SCROLLBAR //PostDlgItemEnableWindow( hDlg, IDC_APPMAN_SCROLLBAR, enableManageDiskSpace ); hwnd = GetDlgItem(hDlg, IDC_APPMAN_SCROLLBAR); EnableWindow( hwnd, bEnable ); // TEXT hwnd = GetDlgItem(hDlg, IDC_APPMAN_TEXT_PERCENT_DISK_USED); EnableWindow( hwnd, bEnable ); #endif } /////////////////////////////////////////////////////////////////// // AppMan functions /////////////////////////////////////////////////////////////////// #define RELEASE(p) { if((p)) { (p)->Release(); p = NULL; } } #if 0 //////////////////////////////////////////////////////////////////////////////////////// // FUNCTION: OnAdvHelp ( LPARAM lParam ) // // PARAMETERS: lParam - Pointer to HELPINFO struct // // PURPOSE: WM_HELP message handler //////////////////////////////////////////////////////////////////////////////////////// void OnAdvHelp(LPARAM lParam) { ASSERT (lParam); // point to help file LPTSTR pszHelpFileName = new TCHAR[STR_LEN_32]; ASSERT (pszHelpFileName); if( LoadString(ghInstance, IDS_HELPFILENAME, pszHelpFileName, STR_LEN_32) ) { if( ((LPHELPINFO)lParam)->iContextType == HELPINFO_WINDOW ) WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, pszHelpFileName, HELP_WM_HELP, (ULONG_PTR)gaHelpIDs); } #ifdef _DEBUG else OutputDebugString(TEXT("JOY.CPL: AppMan.cpp: OnAdvHelp: LoadString Failed to find IDS_HELPFILENAME!\n")); #endif // _DEBUG if( pszHelpFileName ) delete[] (pszHelpFileName); } //////////////////////////////////////////////////////////////////////////////////////// // FUNCTION: OnContextMenu ( WPARAM wParam ) // // PARAMETERS: wParam - HWND of window under the pointer // // PURPOSE: Handle WM_RBUTTONDOWN over all client windows // (except the list control... that's OnListviewContextMenu() job) //////////////////////////////////////////////////////////////////////////////////////// void OnContextMenu(WPARAM wParam, LPARAM lParam) { // HWND hListCtrl = NULL ASSERT (wParam); #if 0 hListCtrl = GetDlgItem((HWND) wParam, IDC_APPMAN_DRIVE_LIST); // If you are on the ListCtrl... if( (HWND)wParam == hListCtrl ) { SetFocus(hListCtrl); // Don't attempt if nothing selected if( iItem != NO_ITEM ) OnListviewContextMenu(hListCtrl,lParam); } else #endif { // point to help file LPTSTR pszHelpFileName = new TCHAR[STR_LEN_32]; ASSERT (pszHelpFileName); if( LoadString(ghInstance, IDS_HELPFILENAME, pszHelpFileName, STR_LEN_32) ) WinHelp((HWND)wParam, pszHelpFileName, HELP_CONTEXTMENU, (ULONG_PTR)gaHelpIDs); #ifdef _DEBUG else OutputDebugString(TEXT("JOY.CPL: appman.cpp: OnContextMenu: LoadString Failed to find IDS_HELPFILENAME!\n")); #endif // _DEBUG if( pszHelpFileName ) delete[] (pszHelpFileName); } } /////////////////////////////////////////////////////////////////////////////// // FUNCTION: OnListviewContextMenu( void ) // // PURPOSE: Handle Context menu in Listview // // RETURN: TRUE if successfull, FALSE otherwise /////////////////////////////////////////////////////////////////////////////// static void OnListviewContextMenu( HWND hWnd, LPARAM lParam ) { HMENU hPopupMenu = CreatePopupMenu(); HWND hListCtrl = NULL; hListCtrl = GetDlgItem(hWnd, IDC_APPMAN_DRIVE_LIST); ASSERT (hPopupMenu); // unlike life, bRet defaults to bliss BOOL bRet = TRUE; LPTSTR pszText = new TCHAR[STR_LEN_32]; ASSERT (pszText); // Don't display Rename/Change if on (none) entry if( !(GetItemData(hListCtrl, (BYTE)iItem) & ID_NONE) ) { if( TRUE ) // Borrowed code... { // add the "Change..." string ::SendDlgItemMessage(GetParent(hListCtrl), IDC_ADV_CHANGE, WM_GETTEXT, (WPARAM)STR_LEN_32, (LPARAM)(LPCTSTR)pszText); bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_ADV_CHANGE, pszText); #ifdef _DEBUG if( !bRet ) TRACE(TEXT("JOY.CPL: OnListviewCOntextMenu: AppendMenu Failed to insert %s\n"), pszText); #endif //_DEBUG // Add the Rename text VERIFY(LoadString(ghInstance, IDS_RENAME, pszText, STR_LEN_32)); bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_RENAME, pszText); #ifdef _DEBUG if( !bRet ) TRACE(TEXT("JOY.CPL: OnListviewCOntextMenu: AppendMenu Failed to insert %s\n"), pszText); #endif //_DEBUG // Add the SEPERATOR and "What's this?" bRet = AppendMenu(hPopupMenu, MF_SEPARATOR, 0, 0); #ifdef _DEBUG if( !bRet ) TRACE(TEXT("JOY.CPL: OnListviewCOntextMenu: AppendMenu Failed to insert SEPERATOR!\n")); #endif //_DEBUG } } VERIFY(LoadString(ghInstance, IDS_WHATSTHIS, pszText, STR_LEN_32)); bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDS_WHATSTHIS, pszText); #ifdef _DEBUG if( !bRet ) TRACE(TEXT("JOY.CPL: OnListviewCOntextMenu: AppendMenu Failed to insert %s\n"), pszText); #endif //_DEBUG if( pszText ) delete[] (pszText); POINT pt; // lParam is -1 if we got here via Shift+F10 if( lParam > 0 ) { pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); } else { // Centre the popup on the selected item! // This get's a good X pos, but the y is the start of the control! ::SendMessage(hListCtrl, LVM_GETITEMPOSITION, iItem, (LPARAM)&pt); RECT rc; ::GetClientRect(hListCtrl, &rc); pt.x = rc.right>>1; ClientToScreen(hListCtrl, &pt); } bRet = TrackPopupMenu (hPopupMenu, TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON, pt.x, pt.y, 0, ghDlg, NULL); #ifdef _DEBUG if( !bRet ) TRACE (TEXT("JOY.CPL: OnListviewContextMenu: TrackPopupMenu Failed!\n")); #endif //_DEBUG DestroyMenu (hPopupMenu); } #endif