/* * propsht.cpp - IPropSheetExt implementation for App Shortcut class. */ // * NOTE!!: this code is incomplete. Also error checking (any leak?), // * restructuring (for better coding/efficiency) to be done. // * this file uses CharNext etc as it needs User32 anyway * /* Headers **********/ #include "project.hpp" #include #include "resource.h" extern "C" WINSHELLAPI int WINAPI PickIconDlg(HWND hwnd, LPWSTR pwzIconPath, UINT cbIconPath, int *piIconIndex); extern HINSTANCE g_DllInstance; /* Types ********/ // Application Shortcut property sheet data typedef enum _appshcutpropsheetpgs { APPSHCUT_PS_APPSHCUT_PAGE = 0x0000, APPSHCUT_PS_APPREF_PAGE = 0x0001, ALL_APPSHCUT_PS_PAGES } APPSHCUTPSPAGES; typedef struct _asps { CAppShortcut* pappshcut; WCHAR rgchIconFile[MAX_PATH]; int niIcon; APPSHCUTPSPAGES eCurPage; } ASPS; DECLARE_STANDARD_TYPES(ASPS); typedef ASPS* PASPS; /* Module Constants *******************/ // Tray notification window class //copied from shell32! #define WNDCLASS_TRAYNOTIFY L"Shell_TrayWnd" //internal_win40 const WCHAR s_cwzTrayNotificationClass[] = WNDCLASS_TRAYNOTIFY; // HACKHACK: WMTRAY_SCREGISTERHOTKEY and WMTRAY_SCUNREGISTERHOTKEY are stolen // from shelldll\link.c. typedef const UINT CUINT; CUINT WMTRAY_SCREGISTERHOTKEY = (WM_USER + 233); CUINT WMTRAY_SCUNREGISTERHOTKEY = (WM_USER + 234); // show commands - N.b., the order of these constants must match the order of // the corresponding IDS_ string table constants. const UINT s_ucMaxShowCmdLen = MAX_PATH; const UINT s_ucMaxTypeLen = TYPESTRINGLENGTH; const int s_rgnShowCmds[] = { SW_SHOWNORMAL, SW_SHOWMINNOACTIVE, SW_SHOWMAXIMIZED }; // this ordering has to match the strings in the resource file, // the strings has to be in sync with the parsing code in persist.cpp const int s_rgnType[] = { APPTYPE_NETASSEMBLY, APPTYPE_WIN32EXE }; /* ** ExtractFileName() ** ** Extracts the file name from a path name. ** ** Arguments: pcwzPathName - path string from which to extract file name ** ** Returns: Pointer to file name in path string. ** ** Side Effects: none */ #define BACKSLASH L'/' #define SLASH L'\\' #define COLON L':' #define IS_SLASH(ch) ((ch) == SLASH || (ch) == BACKSLASH) PCWSTR ExtractFileName(PCWSTR pcwzPathName) { PCWSTR pcwzLastComponent; PCWSTR pcwz; for (pcwzLastComponent = pcwz = pcwzPathName; *pcwz; pcwz = CharNext(pcwz)) { if (IS_SLASH(*pcwz) || *pcwz == COLON) pcwzLastComponent = CharNext(pcwz); } ASSERT(IsValidPath(pcwzLastComponent)); return(pcwzLastComponent); } /***************************** Private Functions *****************************/ UINT CALLBACK ASPSCallback(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp) { // this is called after ASPS_DlgProc WM_DESTROY (ie. ASPS_Destroy) // this func should do the frees/releases UINT uResult = TRUE; PASPS pasps = (PASPS)(ppsp->lParam); // uMsg may be any value. ASSERT(! hwnd || IS_VALID_HANDLE(hwnd, WND)); switch (uMsg) { case PSPCB_CREATE: // from MSDN: A dialog box for a page is being created. // Return nonzero to allow it to be created, or zero to prevent it. break; case PSPCB_RELEASE: // ???? need checking if NULL pasps->pappshcut->Release(); // free the ASPS structure, this is created in AddASPS // delete only after the ref is removed delete pasps; ppsp->lParam = NULL; break; default: // ignore other msg - unhandled break; } return(uResult); } void SetASPSIcon(HWND hdlg, HICON hicon) { HICON hiconOld; ASSERT(IS_VALID_HANDLE(hdlg, WND)); ASSERT(IS_VALID_HANDLE(hicon, ICON)); hiconOld = (HICON)SendDlgItemMessage(hdlg, IDD_ICON, STM_SETICON, (WPARAM)hicon, 0); if (hiconOld) DestroyIcon(hiconOld); return; } void SetASPSFileNameAndIcon(HWND hdlg) { HRESULT hr; CAppShortcut* pappshcut; WCHAR rgchFile[MAX_PATH]; ASSERT(IS_VALID_HANDLE(hdlg, WND)); pappshcut = ((PASPS)(((PROPSHEETPAGE*)GetWindowLongPtr(hdlg, DWLP_USER))->lParam))->pappshcut; hr = pappshcut->GetCurFile(rgchFile, sizeof(rgchFile) / sizeof(WCHAR)); if (hr == S_OK) { SHFILEINFO shfi; DWORD_PTR dwResult; dwResult = SHGetFileInfo(rgchFile, 0, &shfi, sizeof(shfi), (SHGFI_DISPLAYNAME | SHGFI_ICON)); if (dwResult) { LPWSTR pwzFileName; pwzFileName = (LPWSTR)ExtractFileName(shfi.szDisplayName); EVAL(SetDlgItemText(hdlg, IDD_NAME, pwzFileName)); SetASPSIcon(hdlg, shfi.hIcon); } else { hr = E_FAIL; } } if (hr != S_OK) EVAL(SetDlgItemText(hdlg, IDD_NAME, g_cwzEmptyString)); return; } void SetASPSWorkingDirectory(HWND hdlg) { CAppShortcut* pappshcut; HRESULT hr; WCHAR rgchWorkingDirectory[MAX_PATH]; ASSERT(IS_VALID_HANDLE(hdlg, WND)); pappshcut = ((PASPS)(((PROPSHEETPAGE*)GetWindowLongPtr(hdlg, DWLP_USER))->lParam))->pappshcut; hr = pappshcut->GetWorkingDirectory(rgchWorkingDirectory, sizeof(rgchWorkingDirectory) / sizeof(WCHAR)); if (hr == S_OK) { EVAL(SetDlgItemText(hdlg, IDD_START_IN, rgchWorkingDirectory)); } else { EVAL(SetDlgItemText(hdlg, IDD_START_IN, g_cwzEmptyString)); } return; } void InitASPSHotkey(HWND hdlg) { CAppShortcut* pappshcut; WORD wHotkey; HRESULT hr; ASSERT(IS_VALID_HANDLE(hdlg, WND)); // Set hotkey combinations. SendDlgItemMessage(hdlg, IDD_HOTKEY, HKM_SETRULES, (HKCOMB_NONE | HKCOMB_A | HKCOMB_C | HKCOMB_S), (HOTKEYF_CONTROL | HOTKEYF_ALT)); // Set current hotkey. pappshcut = ((PASPS)(((PROPSHEETPAGE*)GetWindowLongPtr(hdlg, DWLP_USER))->lParam))->pappshcut; hr = pappshcut->GetHotkey(&wHotkey); SendDlgItemMessage(hdlg, IDD_HOTKEY, HKM_SETHOTKEY, wHotkey, 0); return; } void InitASPSShowCmds(HWND hdlg) { int niShowCmd; ASSERT(IS_VALID_HANDLE(hdlg, WND)); for (niShowCmd = IDS_SHOW_NORMAL; niShowCmd <= IDS_SHOW_MAXIMIZED; niShowCmd++) { WCHAR rgchShowCmd[s_ucMaxShowCmdLen]; if (LoadString(g_DllInstance, niShowCmd, rgchShowCmd, //MLLoadStringA s_ucMaxShowCmdLen))//sizeof(rgchShowCmd))) { SendDlgItemMessage(hdlg, IDD_SHOW_CMD, CB_ADDSTRING, 0, (LPARAM)rgchShowCmd); } } return; } void SetASPSShowCmd(HWND hdlg) { CAppShortcut* pappshcut; int nShowCmd; int i; ASSERT(IS_VALID_HANDLE(hdlg, WND)); pappshcut = ((PASPS)(((PROPSHEETPAGE*)GetWindowLongPtr(hdlg, DWLP_USER))->lParam))->pappshcut; pappshcut->GetShowCmd(&nShowCmd); for (i = 0; i < ARRAY_ELEMENTS(s_rgnShowCmds); i++) { if (s_rgnShowCmds[i] == nShowCmd) break; } if (i >= ARRAY_ELEMENTS(s_rgnShowCmds)) { ASSERT(i == ARRAY_ELEMENTS(s_rgnShowCmds)); i = 0; // default is 0 == 'normal' } SendDlgItemMessage(hdlg, IDD_SHOW_CMD, CB_SETCURSEL, i, 0); return; } void SetASPSDisplayName(HWND hdlg) { CAppShortcut* pappshcut; HRESULT hr; WCHAR rgchString[DISPLAYNAMESTRINGLENGTH]; ASSERT(IS_VALID_HANDLE(hdlg, WND)); pappshcut = ((PASPS)(((PROPSHEETPAGE*)GetWindowLongPtr(hdlg, DWLP_USER))->lParam))->pappshcut; hr = pappshcut->GetDisplayName(rgchString, sizeof(rgchString) / sizeof(WCHAR)); if (hr == S_OK) { EVAL(SetDlgItemText(hdlg, IDD_DISPLAY_NAME, rgchString)); } else { EVAL(SetDlgItemText(hdlg, IDD_DISPLAY_NAME, g_cwzEmptyString)); } return; } void SetASPSName(HWND hdlg) { CAppShortcut* pappshcut; HRESULT hr; WCHAR rgchString[NAMESTRINGLENGTH]; ASSERT(IS_VALID_HANDLE(hdlg, WND)); pappshcut = ((PASPS)(((PROPSHEETPAGE*)GetWindowLongPtr(hdlg, DWLP_USER))->lParam))->pappshcut; hr = pappshcut->GetName(rgchString, sizeof(rgchString) / sizeof(WCHAR)); if (hr == S_OK) { EVAL(SetDlgItemText(hdlg, IDD_NAME, rgchString)); } else { EVAL(SetDlgItemText(hdlg, IDD_NAME, g_cwzEmptyString)); } return; } void SetASPSVersion(HWND hdlg) { CAppShortcut* pappshcut; HRESULT hr; WCHAR rgchString[VERSIONSTRINGLENGTH]; ASSERT(IS_VALID_HANDLE(hdlg, WND)); pappshcut = ((PASPS)(((PROPSHEETPAGE*)GetWindowLongPtr(hdlg, DWLP_USER))->lParam))->pappshcut; hr = pappshcut->GetVersion(rgchString, sizeof(rgchString) / sizeof(WCHAR)); if (hr == S_OK) { EVAL(SetDlgItemText(hdlg, IDD_VERSION, rgchString)); } else { EVAL(SetDlgItemText(hdlg, IDD_VERSION, g_cwzEmptyString)); } return; } void SetASPSCulture(HWND hdlg) { CAppShortcut* pappshcut; HRESULT hr; WCHAR rgchString[CULTURESTRINGLENGTH]; ASSERT(IS_VALID_HANDLE(hdlg, WND)); pappshcut = ((PASPS)(((PROPSHEETPAGE*)GetWindowLongPtr(hdlg, DWLP_USER))->lParam))->pappshcut; hr = pappshcut->GetCulture(rgchString, sizeof(rgchString) / sizeof(WCHAR)); if (hr == S_OK) { EVAL(SetDlgItemText(hdlg, IDD_CULTURE, rgchString)); } else { EVAL(SetDlgItemText(hdlg, IDD_CULTURE, g_cwzEmptyString)); } return; } void SetASPSPKT(HWND hdlg) { CAppShortcut* pappshcut; HRESULT hr; WCHAR rgchString[PKTSTRINGLENGTH]; ASSERT(IS_VALID_HANDLE(hdlg, WND)); pappshcut = ((PASPS)(((PROPSHEETPAGE*)GetWindowLongPtr(hdlg, DWLP_USER))->lParam))->pappshcut; hr = pappshcut->GetPKT(rgchString, sizeof(rgchString) / sizeof(WCHAR)); if (hr == S_OK) { EVAL(SetDlgItemText(hdlg, IDD_PKT, rgchString)); } else { EVAL(SetDlgItemText(hdlg, IDD_PKT, g_cwzEmptyString)); } return; } void SetASPSCodebase(HWND hdlg) { CAppShortcut* pappshcut; HRESULT hr; WCHAR rgchString[MAX_URL_LENGTH]; ASSERT(IS_VALID_HANDLE(hdlg, WND)); pappshcut = ((PASPS)(((PROPSHEETPAGE*)GetWindowLongPtr(hdlg, DWLP_USER))->lParam))->pappshcut; hr = pappshcut->GetCodebase(rgchString, sizeof(rgchString) / sizeof(WCHAR)); if (hr == S_OK) { EVAL(SetDlgItemText(hdlg, IDD_CODEBASE, rgchString)); } else { EVAL(SetDlgItemText(hdlg, IDD_CODEBASE, g_cwzEmptyString)); } return; } void SetASPSEntrypoint(HWND hdlg) { CAppShortcut* pappshcut; HRESULT hr; WCHAR rgchString[MAX_PATH]; ASSERT(IS_VALID_HANDLE(hdlg, WND)); pappshcut = ((PASPS)(((PROPSHEETPAGE*)GetWindowLongPtr(hdlg, DWLP_USER))->lParam))->pappshcut; hr = pappshcut->GetPath(rgchString, sizeof(rgchString) / sizeof(WCHAR), NULL, 0); if (hr == S_OK) { EVAL(SetDlgItemText(hdlg, IDD_ENTRYPOINT, rgchString)); } else { EVAL(SetDlgItemText(hdlg, IDD_ENTRYPOINT, g_cwzEmptyString)); } return; } void InitASPSType(HWND hdlg) { int i; ASSERT(IS_VALID_HANDLE(hdlg, WND)); for (i = IDS_APPTYPE_NETASSEMBLY; i <= IDS_APPTYPE_WIN32EXE; i++) { WCHAR rgchString[s_ucMaxTypeLen]; if (LoadString(g_DllInstance, i, rgchString, s_ucMaxTypeLen))//sizeof(rgchShowCmd))) //MLLoadStringA { SendDlgItemMessage(hdlg, IDD_TYPE, CB_ADDSTRING, 0, (LPARAM)rgchString); } } return; } void SetASPSType(HWND hdlg) { CAppShortcut* pappshcut; int nType; int i; ASSERT(IS_VALID_HANDLE(hdlg, WND)); pappshcut = ((PASPS)(((PROPSHEETPAGE*)GetWindowLongPtr(hdlg, DWLP_USER))->lParam))->pappshcut; pappshcut->GetAppType(&nType); for (i = 0; i < ARRAY_ELEMENTS(s_rgnType); i++) { if (s_rgnType[i] == nType) break; } if (i >= ARRAY_ELEMENTS(s_rgnType)) { ASSERT(i == ARRAY_ELEMENTS(s_rgnType)); // not found! this clears the edit control - there's no default for this // note: InjectASPSData has to handle this special case... as CB_ERR... i = -1; } SendDlgItemMessage(hdlg, IDD_TYPE, CB_SETCURSEL, i, 0); return; } BOOL ASPS_InitDialog(HWND hdlg, WPARAM wparam, LPARAM lparam) { // wparam may be any value. ASSERT(IS_VALID_HANDLE(hdlg, WND)); // this set PROPSHEETPAGE struct to DWLP_USER SetWindowLongPtr(hdlg, DWLP_USER, lparam); // Initialize control contents. if (((PASPS)(((PROPSHEETPAGE*)lparam)->lParam))->eCurPage == APPSHCUT_PS_APPSHCUT_PAGE) { SetASPSFileNameAndIcon(hdlg); // note: need limits on all editbox! SetASPSDisplayName(hdlg); SendDlgItemMessage(hdlg, IDD_CODEBASE, EM_LIMITTEXT, MAX_URL_LENGTH - 1, 0); SetASPSCodebase(hdlg); InitASPSType(hdlg); SetASPSType(hdlg); SendDlgItemMessage(hdlg, IDD_ENTRYPOINT, EM_LIMITTEXT, MAX_PATH - 1, 0); SetASPSEntrypoint(hdlg); SendDlgItemMessage(hdlg, IDD_START_IN, EM_LIMITTEXT, MAX_PATH - 1, 0); SetASPSWorkingDirectory(hdlg); InitASPSHotkey(hdlg); InitASPSShowCmds(hdlg); SetASPSShowCmd(hdlg); } else if (((PASPS)(((PROPSHEETPAGE*)lparam)->lParam))->eCurPage == APPSHCUT_PS_APPREF_PAGE) { // note: need limits on all editbox! SetASPSDisplayName(hdlg); SetASPSName(hdlg); SetASPSVersion(hdlg); SetASPSCulture(hdlg); SetASPSPKT(hdlg); } // else do nothing? return(TRUE); } BOOL ASPS_Destroy(HWND hdlg, WPARAM wparam, LPARAM lparam) { // ASPSCallback is called after this func. The remaining frees/releases are there // wparam may be any value. // lparam may be any value. ASSERT(IS_VALID_HANDLE(hdlg, WND)); SetWindowLongPtr(hdlg, DWLP_USER, NULL); return(TRUE); } void ASPSChanged(HWND hdlg) { ASSERT(IS_VALID_HANDLE(hdlg, WND)); PropSheet_Changed(GetParent(hdlg), hdlg); return; } HRESULT ChooseIcon(HWND hdlg) { HRESULT hr; PASPS pasps; CAppShortcut* pappshcut; WCHAR rgchTempIconFile[MAX_PATH]; int niIcon; UINT uFlags; ASSERT(IS_VALID_HANDLE(hdlg, WND)); pasps = (PASPS)(((PROPSHEETPAGE*)GetWindowLongPtr(hdlg, DWLP_USER))->lParam); pappshcut = pasps->pappshcut; if (pappshcut->GetIconLocation(0, rgchTempIconFile, sizeof(rgchTempIconFile)/sizeof(WCHAR), &niIcon, &uFlags) != S_OK) { rgchTempIconFile[0] = '\0'; niIcon = 0; } ASSERT(wcslen(rgchTempIconFile) < (sizeof(rgchTempIconFile)/sizeof(WCHAR))); // a private shell32.dll export (by ordinal)... if (PickIconDlg(hdlg, rgchTempIconFile, sizeof(rgchTempIconFile), &niIcon)) //??? sizeof { ASSERT(wcslen(rgchTempIconFile) < (sizeof(pasps->rgchIconFile)/sizeof(WCHAR))); wcscpy(pasps->rgchIconFile, rgchTempIconFile); pasps->niIcon = niIcon; hr = S_OK; } else { hr = E_FAIL; } return(hr); } void UpdateASPSIcon(HWND hdlg) { PASPS pasps; HICON hicon; ASSERT(IS_VALID_HANDLE(hdlg, WND)); pasps = (PASPS)(((PROPSHEETPAGE*)GetWindowLongPtr(hdlg, DWLP_USER))->lParam); ASSERT(pasps->rgchIconFile[0]); hicon = ExtractIcon(g_DllInstance, pasps->rgchIconFile, pasps->niIcon); if (hicon) SetASPSIcon(hdlg, hicon); return; } BOOL ASPS_Command(HWND hdlg, WPARAM wparam, LPARAM lparam) { BOOL bMsgHandled = FALSE; WORD wCmd; // wparam may be any value. // lparam may be any value. ASSERT(IS_VALID_HANDLE(hdlg, WND)); wCmd = HIWORD(wparam); switch (LOWORD(wparam)) { case IDD_CODEBASE: case IDD_HOTKEY: case IDD_ENTRYPOINT: case IDD_START_IN: case IDD_DISPLAY_NAME: case IDD_NAME: case IDD_VERSION: case IDD_CULTURE: case IDD_PKT: if (wCmd == EN_CHANGE) { ASPSChanged(hdlg); bMsgHandled = TRUE; } break; case IDD_SHOW_CMD: case IDD_TYPE: if (wCmd == LBN_SELCHANGE) { ASPSChanged(hdlg); bMsgHandled = TRUE; } break; case IDD_CHANGE_ICON: // Ignore return value. if (ChooseIcon(hdlg) == S_OK) { UpdateASPSIcon(hdlg); ASPSChanged(hdlg); } bMsgHandled = TRUE; break; default: break; } return(bMsgHandled); } HRESULT InjectASPSData(HWND hdlg) { // BUGBUG: TODO: this function should validate the user's changes... HRESULT hr = S_OK; PASPS pasps; CAppShortcut* pappshcut; LPWSTR pwzURL; ASSERT(IS_VALID_HANDLE(hdlg, WND)); pasps = (PASPS)(((PROPSHEETPAGE*)GetWindowLongPtr(hdlg, DWLP_USER))->lParam); pappshcut = pasps->pappshcut; return(hr); } HRESULT ASPSSave(HWND hdlg) { HRESULT hr; CAppShortcut* pappshcut; ASSERT(IS_VALID_HANDLE(hdlg, WND)); pappshcut = ((PASPS)(((PROPSHEETPAGE*)GetWindowLongPtr(hdlg, DWLP_USER))->lParam))->pappshcut; if (pappshcut->IsDirty() == S_OK) { // BUGBUG: TODO: IPersistFile::Save is not implemented hr = pappshcut->Save((LPCOLESTR)NULL, FALSE); } else { hr = S_OK; } return(hr); } BOOL ASPS_Notify(HWND hdlg, WPARAM wparam, LPARAM lparam) { BOOL bMsgHandled = FALSE; // wparam may be any value. // lparam may be any value. ASSERT(IS_VALID_HANDLE(hdlg, WND)); switch (((NMHDR*)lparam)->code) { case PSN_APPLY: SetWindowLongPtr(hdlg, DWLP_MSGRESULT, ASPSSave(hdlg) == S_OK ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE); bMsgHandled = TRUE; break; case PSN_KILLACTIVE: SetWindowLongPtr(hdlg, DWLP_MSGRESULT, FAILED(InjectASPSData(hdlg))); bMsgHandled = TRUE; break; default: break; } return(bMsgHandled); } INT_PTR CALLBACK ASPS_DlgProc(HWND hdlg, UINT uMsg, WPARAM wparam, LPARAM lparam) { INT_PTR bMsgHandled = FALSE; // uMsg may be any value. // wparam may be any value. // lparam may be any value. ASSERT(IS_VALID_HANDLE(hdlg, WND)); switch (uMsg) { case WM_INITDIALOG: bMsgHandled = ASPS_InitDialog(hdlg, wparam, lparam); break; case WM_DESTROY: bMsgHandled = ASPS_Destroy(hdlg, wparam, lparam); break; case WM_COMMAND: bMsgHandled = ASPS_Command(hdlg, wparam, lparam); break; case WM_NOTIFY: bMsgHandled = ASPS_Notify(hdlg, wparam, lparam); break; default: break; } return(bMsgHandled); } HRESULT AddASPS(CAppShortcut* pappshcut, LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lparam) { HRESULT hr = S_OK; PASPS pasps; PROPSHEETPAGE psp; HPROPSHEETPAGE hpsp; PASPS pasps2; PROPSHEETPAGE psp2; HPROPSHEETPAGE hpsp2; // lparam may be any value. // this is deleted in ASPSCallback pasps = new ASPS; ZeroMemory(pasps, sizeof(*pasps)); psp.dwSize = sizeof(psp); psp.dwFlags = (PSP_DEFAULT | PSP_USECALLBACK); psp.hInstance = g_DllInstance; //MLGetHinst(); psp.pszTemplate = MAKEINTRESOURCE(DLG_APP_SHORTCUT_PROP_SHEET); psp.pfnDlgProc = &ASPS_DlgProc; psp.pfnCallback = &ASPSCallback; psp.lParam = (LPARAM)pasps; psp.hIcon = 0; // not used psp.pszTitle = NULL; // not used psp.pcRefParent = 0; // not used pasps->pappshcut = pappshcut; pasps->eCurPage = APPSHCUT_PS_APPSHCUT_PAGE; // page 1 // will psp be copied in this func? else this won't work...!!???????? hpsp = CreatePropertySheetPage(&psp); if (hpsp) { if ((*pfnAddPage)(hpsp, lparam)) { pappshcut->AddRef(); } else { DestroyPropertySheetPage(hpsp); hr = E_FAIL; goto exit; } } else { hr = E_OUTOFMEMORY; goto exit; } // this is deleted in ASPSCallback pasps2 = new ASPS; ZeroMemory(pasps2, sizeof(*pasps2)); psp2.dwSize = sizeof(psp2); psp2.dwFlags = (PSP_DEFAULT | PSP_USECALLBACK); psp2.hInstance = g_DllInstance; //MLGetHinst(); psp2.pszTemplate = MAKEINTRESOURCE(DLG_APP_SHORTCUT_PROP_SHEET_APPNAME); psp2.pfnDlgProc = &ASPS_DlgProc; psp2.pfnCallback = &ASPSCallback; psp2.lParam = (LPARAM)pasps2; psp2.hIcon = 0; // not used psp2.pszTitle = NULL; // not used psp2.pcRefParent = 0; // not used pasps2->pappshcut = pappshcut; pasps2->eCurPage = APPSHCUT_PS_APPREF_PAGE; // page 2 // will psp be copied in this func? else this won't work...!!???????? hpsp2 = CreatePropertySheetPage(&psp2); if (hpsp2) { if ((*pfnAddPage)(hpsp2, lparam)) { pappshcut->AddRef(); } else { DestroyPropertySheetPage(hpsp2); hr = E_FAIL; goto exit; } } else { hr = E_OUTOFMEMORY; goto exit; } exit: return(hr); } /****************************** Public Functions *****************************/ BOOL RegisterGlobalHotkey(WORD wOldHotkey, WORD wNewHotkey, LPCWSTR pcwzPath) { // BUGBUG?: does this work?? BOOL bResult = FALSE; HWND hwndTray; ASSERT(! wOldHotkey || IsValidHotkey(wOldHotkey)); ASSERT(! wNewHotkey || IsValidHotkey(wNewHotkey)); ASSERT(IsValidPath(pcwzPath)); hwndTray = FindWindow(s_cwzTrayNotificationClass, 0); if (hwndTray) { if (wOldHotkey) { SendMessage(hwndTray, WMTRAY_SCUNREGISTERHOTKEY, wOldHotkey, 0); } if (wNewHotkey) { ATOM atom = GlobalAddAtom(pcwzPath); ASSERT(atom); if (atom) { SendMessage(hwndTray, WMTRAY_SCREGISTERHOTKEY, wNewHotkey, (LPARAM)atom); GlobalDeleteAtom(atom); } } bResult = TRUE; } /*else { bResult = FALSE; }*/ return(bResult); } /********************************** Methods **********************************/ HRESULT STDMETHODCALLTYPE CAppShortcut::Initialize(LPCITEMIDLIST pcidlFolder, IDataObject* pido, HKEY hkeyProgID) { HRESULT hr; STGMEDIUM stgmed; FORMATETC fmtetc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; ASSERT(NULL != pido); ASSERT(IS_VALID_HANDLE(hkeyProgID, KEY)); hr = pido->GetData(&fmtetc, &stgmed); if (hr == S_OK) { WCHAR wzPath[MAX_PATH]; if (DragQueryFile((HDROP)stgmed.hGlobal, 0, wzPath, sizeof(wzPath)/sizeof(*wzPath))) { //mode is ignored for now hr = Load(wzPath, 0); } // else path len > MAX_PATH or other error ReleaseStgMedium(&stgmed); } return(hr); } HRESULT STDMETHODCALLTYPE CAppShortcut::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lparam) { HRESULT hr; // lparam may be any value. hr = AddASPS(this, pfnAddPage, lparam); // BUGBUG: why this does not work? // From MSDN: //With version 4.71 and later, you can request that a particular property //sheet page be displayed first, instead of the default page. To do so, //return the one-based index of the desired page. For example, if you //want the second of three pages displayed, the return value should be 2. //Note that this return value is a request. The property sheet may still //display the default page. --> see doc for AddPages() if (SUCCEEDED(hr)) hr = HRESULT(4); // or 3?? return(hr); } HRESULT STDMETHODCALLTYPE CAppShortcut::ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplaceWith, LPARAM lparam) { HRESULT hr; // lparam may be any value. // uPageID may be any value. hr = E_NOTIMPL; return(hr); } HRESULT STDMETHODCALLTYPE CAppShortcut::SetDisplayName(LPCWSTR pcwzDisplayName) { // BUGBUG: not much checking is done! BOOL bChanged = FALSE; LPWSTR pwzOriString = NULL; LPWSTR pwzNewString = (LPWSTR) pcwzDisplayName; ASSERT(! pwzNewString); if (!m_pappRefInfo) return (E_FAIL); pwzOriString = m_pappRefInfo->_wzDisplayName; // ... this checks if all space in string... if (! AnyNonWhiteSpace(pwzNewString)) pwzNewString = NULL; bChanged = ! ((! pwzNewString && ! pwzOriString) || (pwzNewString && pwzOriString && ! wcscmp(pwzNewString, pwzOriString))); if (bChanged) { if (pwzNewString) { wcsncpy(pwzOriString, pwzNewString, DISPLAYNAMESTRINGLENGTH-1); pwzOriString[DISPLAYNAMESTRINGLENGTH-1] = L'\0'; } else pwzOriString[0] = L'\0'; Dirty(TRUE); } return(S_OK); } HRESULT STDMETHODCALLTYPE CAppShortcut::GetDisplayName(LPWSTR pwzDisplayName, int ncbLen) { HRESULT hr; if (!m_pappRefInfo) return (E_FAIL); if (m_pappRefInfo->_wzDisplayName) { if ((int) wcslen(m_pappRefInfo->_wzDisplayName) < ncbLen) { wcsncpy(pwzDisplayName, m_pappRefInfo->_wzDisplayName, ncbLen-1); pwzDisplayName[ncbLen-1] = L'\0'; hr = S_OK; } else hr = E_FAIL; } else { if (ncbLen > 0) pwzDisplayName = L'\0'; hr = S_FALSE; } return(hr); } HRESULT STDMETHODCALLTYPE CAppShortcut::SetName(LPCWSTR pcwzName) { // BUGBUG: not much checking is done! BOOL bChanged = FALSE; LPWSTR pwzOriString = NULL; LPWSTR pwzNewString = (LPWSTR) pcwzName; ASSERT(! pwzNewString); if (!m_pappRefInfo) return (E_FAIL); pwzOriString = m_pappRefInfo->_wzName; // ... this checks if all space in string... if (! AnyNonWhiteSpace(pwzNewString)) pwzNewString = NULL; bChanged = ! ((! pwzNewString && ! pwzOriString) || (pwzNewString && pwzOriString && ! wcscmp(pwzNewString, pwzOriString))); if (bChanged) { if (pwzNewString) { wcsncpy(pwzOriString, pwzNewString, NAMESTRINGLENGTH-1); pwzOriString[NAMESTRINGLENGTH-1] = L'\0'; } else pwzOriString[0] = L'\0'; Dirty(TRUE); } return(S_OK); } HRESULT STDMETHODCALLTYPE CAppShortcut::GetName(LPWSTR pwzName, int ncbLen) { HRESULT hr; if (!m_pappRefInfo) return (E_FAIL); if (m_pappRefInfo->_wzName) { if ((int) wcslen(m_pappRefInfo->_wzName) < ncbLen) { wcsncpy(pwzName, m_pappRefInfo->_wzName, ncbLen-1); pwzName[ncbLen-1] = L'\0'; hr = S_OK; } else hr = E_FAIL; } else { if (ncbLen > 0) pwzName = L'\0'; hr = S_FALSE; } return(hr); } HRESULT STDMETHODCALLTYPE CAppShortcut::SetVersion(LPCWSTR pcwzVersion) { // BUGBUG: not much checking is done! BOOL bChanged = FALSE; LPWSTR pwzOriString = NULL; LPWSTR pwzNewString = (LPWSTR) pcwzVersion; ASSERT(! pwzNewString); if (!m_pappRefInfo) return (E_FAIL); pwzOriString = m_pappRefInfo->_wzVersion; // ... this checks if all space in string... if (! AnyNonWhiteSpace(pwzNewString)) pwzNewString = NULL; bChanged = ! ((! pwzNewString && ! pwzOriString) || (pwzNewString && pwzOriString && ! wcscmp(pwzNewString, pwzOriString))); if (bChanged) { if (pwzNewString) { wcsncpy(pwzOriString, pwzNewString, VERSIONSTRINGLENGTH-1); pwzOriString[VERSIONSTRINGLENGTH-1] = L'\0'; } else pwzOriString[0] = L'\0'; Dirty(TRUE); } return(S_OK); } HRESULT STDMETHODCALLTYPE CAppShortcut::GetVersion(LPWSTR pwzVersion, int ncbLen) { HRESULT hr; if (!m_pappRefInfo) return (E_FAIL); if (m_pappRefInfo->_wzVersion) { if ((int) wcslen(m_pappRefInfo->_wzVersion) < ncbLen) { wcsncpy(pwzVersion, m_pappRefInfo->_wzVersion, ncbLen-1); pwzVersion[ncbLen-1] = L'\0'; hr = S_OK; } else hr = E_FAIL; } else { if (ncbLen > 0) pwzVersion = L'\0'; hr = S_FALSE; } return(hr); } HRESULT STDMETHODCALLTYPE CAppShortcut::SetCulture(LPCWSTR pcwzCulture) { // BUGBUG: not much checking is done! BOOL bChanged = FALSE; LPWSTR pwzOriString = NULL; LPWSTR pwzNewString = (LPWSTR) pcwzCulture; ASSERT(! pwzNewString); if (!m_pappRefInfo) return (E_FAIL); pwzOriString = m_pappRefInfo->_wzCulture; // ... this checks if all space in string... if (! AnyNonWhiteSpace(pwzNewString)) pwzNewString = NULL; bChanged = ! ((! pwzNewString && ! pwzOriString) || (pwzNewString && pwzOriString && ! wcscmp(pwzNewString, pwzOriString))); if (bChanged) { if (pwzNewString) { wcsncpy(pwzOriString, pwzNewString, CULTURESTRINGLENGTH-1); pwzOriString[CULTURESTRINGLENGTH-1] = L'\0'; } else pwzOriString[0] = L'\0'; Dirty(TRUE); } return(S_OK); } HRESULT STDMETHODCALLTYPE CAppShortcut::GetCulture(LPWSTR pwzCulture, int ncbLen) { HRESULT hr; if (!m_pappRefInfo) return (E_FAIL); if (m_pappRefInfo->_wzCulture) { if ((int) wcslen(m_pappRefInfo->_wzCulture) < ncbLen) { wcsncpy(pwzCulture, m_pappRefInfo->_wzCulture, ncbLen-1); pwzCulture[ncbLen-1] = L'\0'; hr = S_OK; } else hr = E_FAIL; } else { if (ncbLen > 0) pwzCulture = L'\0'; hr = S_FALSE; } return(hr); } HRESULT STDMETHODCALLTYPE CAppShortcut::SetPKT(LPCWSTR pcwzPKT) { // BUGBUG: not much checking is done! BOOL bChanged = FALSE; LPWSTR pwzOriString = NULL; LPWSTR pwzNewString = (LPWSTR) pcwzPKT; ASSERT(! pwzNewString); if (!m_pappRefInfo) return (E_FAIL); pwzOriString = m_pappRefInfo->_wzPKT; // ... this checks if all space in string... if (! AnyNonWhiteSpace(pwzNewString)) pwzNewString = NULL; bChanged = ! ((! pwzNewString && ! pwzOriString) || (pwzNewString && pwzOriString && ! wcscmp(pwzNewString, pwzOriString))); if (bChanged) { if (pwzNewString) { wcsncpy(pwzOriString, pwzNewString, PKTSTRINGLENGTH-1); pwzOriString[PKTSTRINGLENGTH-1] = L'\0'; } else pwzOriString[0] = L'\0'; Dirty(TRUE); } return(S_OK); } HRESULT STDMETHODCALLTYPE CAppShortcut::GetPKT(LPWSTR pwzPKT, int ncbLen) { HRESULT hr; if (!m_pappRefInfo) return (E_FAIL); if (m_pappRefInfo->_wzPKT) { if ((int) wcslen(m_pappRefInfo->_wzPKT) < ncbLen) { wcsncpy(pwzPKT, m_pappRefInfo->_wzPKT, ncbLen-1); pwzPKT[ncbLen-1] = L'\0'; hr = S_OK; } else hr = E_FAIL; } else { if (ncbLen > 0) pwzPKT = L'\0'; hr = S_FALSE; } return(hr); } HRESULT STDMETHODCALLTYPE CAppShortcut::SetCodebase(LPCWSTR pcwzCodebase) { // BUGBUG: not much checking is done! BOOL bChanged = FALSE; LPWSTR pwzOriString = NULL; LPWSTR pwzNewString = (LPWSTR) pcwzCodebase; ASSERT(! pwzNewString); if (!m_pappRefInfo) return (E_FAIL); pwzOriString = m_pappRefInfo->_wzCodebase; // ... this checks if all space in string... if (! AnyNonWhiteSpace(pwzNewString)) pwzNewString = NULL; bChanged = ! ((! pwzNewString && ! pwzOriString) || (pwzNewString && pwzOriString && ! wcscmp(pwzNewString, pwzOriString))); if (bChanged) { if (pwzNewString) { wcsncpy(pwzOriString, pwzNewString, MAX_URL_LENGTH-1); pwzOriString[MAX_URL_LENGTH-1] = L'\0'; } else pwzOriString[0] = L'\0'; Dirty(TRUE); } return(S_OK); } HRESULT STDMETHODCALLTYPE CAppShortcut::GetCodebase(LPWSTR pwzCodebase, int ncbLen) { HRESULT hr; if (!m_pappRefInfo) return (E_FAIL); if (m_pappRefInfo->_wzCodebase) { if ((int) wcslen(m_pappRefInfo->_wzCodebase) < ncbLen) { wcsncpy(pwzCodebase, m_pappRefInfo->_wzCodebase, ncbLen-1); pwzCodebase[ncbLen-1] = L'\0'; hr = S_OK; } else hr = E_FAIL; } else { if (ncbLen > 0) pwzCodebase = L'\0'; hr = S_FALSE; } return(hr); } HRESULT STDMETHODCALLTYPE CAppShortcut::SetAppType(int nAppType) { if (!m_pappRefInfo) return (E_FAIL); if (nAppType != m_pappRefInfo->_fAppType) { m_pappRefInfo->_fAppType = nAppType; Dirty(TRUE); } return(S_OK); } HRESULT STDMETHODCALLTYPE CAppShortcut::GetAppType(PINT pnAppType) { if (!m_pappRefInfo) return (E_FAIL); *pnAppType = m_pappRefInfo->_fAppType; return(S_OK); }