/*++ Copyright (c) 1989-2001 Microsoft Corporation Module Name: CAppHelpWizard.cpp Abstract: Code for the AppHelp Wizard Author: kinshu created July 2, 2001 Notes: The name of the AppHelp message in the library section is made same as the HTMLHelp id for that apphelp message as in the entry Apphelp messages are not shared and each apphelped entry has an exclusive apphelp message in the library E.g of XML for soft blocked AppHelped entry: Hello World!!!! Part of the .sdb created for the above XML: 0x00000134 | 0x7007 | EXE | LIST | Size 0x0000006C 0x0000013A | 0x6001 | NAME | STRINGREF | w.exe 0x00000140 | 0x6006 | APP_NAME | STRINGREF | New Application 0x00000146 | 0x6005 | VENDOR | STRINGREF | Vendor Name 0x0000014C | 0x9004 | EXE_ID(GUID) | BINARY | Size 0x00000010 | {31490b6d-6202-4bbf-9b92-2edf209b3ccc} 0x00000162 | 0x700D | APPHELP | LIST | Size 0x00000012 0x00000168 | 0x4017 | FLAGS | DWORD | 0x00000001 0x0000016E | 0x4010 | PROBLEM_SEVERITY | DWORD | 0x00000001 0x00000174 | 0x4015 | HTMLHELPID | DWORD | 0x00000001 -end- APPHELP 0x0000017A | 0x7008 | MATCHING_FILE | LIST | Size 0x00000026 0x00000180 | 0x6001 | NAME | STRINGREF | * 0x00000186 | 0x6011 | PRODUCT_VERSION | STRINGREF | 5.1.2467.0 0x0000018C | 0x5002 | BIN_FILE_VERSION | QWORD | 0x0005000109A30000 0x00000196 | 0x5003 | BIN_PRODUCT_VERSION | QWORD | 0x0005000109A30000 0x000001A0 | 0x6013 | FILE_VERSION | STRINGREF | 5.1.2467.0 (lab06_N.010419-2241) -end- MATCHING_FILE -end- EXE 0x000001A6 | 0x700D | APPHELP | LIST | Size 0x0000001E 0x000001AC | 0x4015 | HTMLHELPID | DWORD | 0x00000001 0x000001B2 | 0x700E | LINK | LIST | Size 0x00000006 0x000001B8 | 0x6019 | LINK_URL | STRINGREF | www.microsoft.com -end- LINK 0x000001BE | 0x601B | APPHELP_TITLE | STRINGREF | New Application 0x000001C4 | 0x6018 | PROBLEM_DETAILS | STRINGREF | Hello World!!!! -end- APPHELP Revision History: --*/ #include "precomp.h" /////////////////////// Defines /////////////////////////////////////////////// // The first page of the wizard. Gets the app info, app name, vendor name, exe path #define PAGE_GETAPP_INFO 0 // The second page of the wizard #define PAGE_GET_MATCH_FILES 1 // The third page of the wizard. Gets the type of apphelp-soft or hard bloc #define PAGE_GETMSG_TYPE 2 // The last page of the wizard. Gets the message and the URL #define PAGE_GETMSG_INFORMATION 3 // Total number of pages in the wizard #define NUM_PAGES 4 // The maximum length of a apphelp URL in chars #define MAX_URL_LENGTH 1023 // The maximum length of a apphelp message in chars #define MAX_MESSAGE_LENGTH 1023 /////////////////////////////////////////////////////////////////////////////// //////////////////////// Externs ////////////////////////////////////////////// extern CShimWizard* g_pCurrentWizard; extern HINSTANCE g_hInstance; extern DATABASE GlobalDataBase; /////////////////////////////////////////////////////////////////////////////// //////////////////////// Function declarations //////////////////////////////// BOOL DeleteAppHelp( DWORD nHelpID ); /////////////////////////////////////////////////////////////////////////////// BOOL CAppHelpWizard::BeginWizard( IN HWND hParent, IN PDBENTRY pEntry, IN PDATABASE pDatabase ) /*++ CAppHelpWizard::BeginWizard Desc: Starts up the wizard. Initializes the various prop-sheet parameters and calls the wizard Params: IN HWND hParent : Parent for the wizard window IN PDBENTRY pEntry : Entry for which AppHelp has to be created or modified IN PDATABASE pDatabase : Database in which pEntry resides Return: TRUE: The user pressed Finish FALSE: The user pressed Cancel --*/ { m_pDatabase = pDatabase; PROPSHEETPAGE Pages[NUM_PAGES]; if (pEntry == NULL) { // // Create a new fix. // ZeroMemory(&m_Entry, sizeof(m_Entry)); GUID Guid; CoCreateGuid(&Guid); StringCchPrintf(m_Entry.szGUID, ARRAYSIZE(m_Entry.szGUID), TEXT("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"), Guid.Data1, Guid.Data2, Guid.Data3, Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3], Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]); m_bEditing = FALSE; } else { // // Edit the passed fix. // m_bEditing = TRUE; // // If we are editing then set m_Entry as *pEntry. The operator is overloaded // All throughout the wizard we only work on m_pEntry // m_Entry = *pEntry; } // // Setup wizard variables // g_pCurrentWizard = this; g_pCurrentWizard->m_uType = TYPE_APPHELPWIZARD; // // begin the wizard // PROPSHEETHEADER Header; Header.dwSize = sizeof(PROPSHEETHEADER); Header.dwFlags = PSH_WIZARD97 | PSH_HEADER | PSH_WATERMARK | PSH_PROPSHEETPAGE; Header.hwndParent = hParent; Header.hInstance = g_hInstance; Header.pszCaption = MAKEINTRESOURCE(IDS_CUSTOMAPPHELP); Header.nStartPage = 0; Header.ppsp = Pages; Header.nPages = NUM_PAGES; Header.pszbmHeader = MAKEINTRESOURCE(IDB_WIZBMP); if (m_bEditing) { // // If we are editing then, put Finish button on all pages // Header.dwFlags |= PSH_WIZARDHASFINISH; } Pages[PAGE_GETAPP_INFO].dwSize = sizeof(PROPSHEETPAGE); Pages[PAGE_GETAPP_INFO].dwFlags = PSP_DEFAULT| PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; Pages[PAGE_GETAPP_INFO].hInstance = g_hInstance; Pages[PAGE_GETAPP_INFO].pszTemplate = MAKEINTRESOURCE(IDD_HELPWIZ_APPINFO); Pages[PAGE_GETAPP_INFO].pfnDlgProc = GetAppInfo; Pages[PAGE_GETAPP_INFO].pszHeaderTitle = MAKEINTRESOURCE(IDS_GIVEAPPINFO); Pages[PAGE_GETAPP_INFO].pszHeaderSubTitle = MAKEINTRESOURCE(IDS_GIVEAPPINFOSUBHEADING); Pages[PAGE_GET_MATCH_FILES].dwSize = sizeof(PROPSHEETPAGE); Pages[PAGE_GET_MATCH_FILES].dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; Pages[PAGE_GET_MATCH_FILES].hInstance = g_hInstance; Pages[PAGE_GET_MATCH_FILES].pszTemplate = MAKEINTRESOURCE(IDD_FIXWIZ_MATCHINGINFO); Pages[PAGE_GET_MATCH_FILES].pfnDlgProc = SelectFiles; Pages[PAGE_GET_MATCH_FILES].pszHeaderTitle = MAKEINTRESOURCE(IDS_MATCHINFO); Pages[PAGE_GET_MATCH_FILES].pszHeaderSubTitle = MAKEINTRESOURCE(IDS_MATCHINFO_SUBHEADING); Pages[PAGE_GETMSG_TYPE].dwSize = sizeof(PROPSHEETPAGE); Pages[PAGE_GETMSG_TYPE].dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; Pages[PAGE_GETMSG_TYPE].hInstance = g_hInstance; Pages[PAGE_GETMSG_TYPE].pszTemplate = MAKEINTRESOURCE(IDD_HELPWIZ_TYPE); Pages[PAGE_GETMSG_TYPE].pfnDlgProc = GetMessageType; Pages[PAGE_GETMSG_TYPE].pszHeaderTitle = MAKEINTRESOURCE(IDS_MESSAGETYPE); Pages[PAGE_GETMSG_TYPE].pszHeaderSubTitle = MAKEINTRESOURCE(IDS_MESSAGETYPE_SUBHEADING); Pages[PAGE_GETMSG_INFORMATION].dwSize = sizeof(PROPSHEETPAGE); Pages[PAGE_GETMSG_INFORMATION].dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; Pages[PAGE_GETMSG_INFORMATION].hInstance = g_hInstance; Pages[PAGE_GETMSG_INFORMATION].pszTemplate = MAKEINTRESOURCE(IDD_HELPWIZ_MESSAGE); Pages[PAGE_GETMSG_INFORMATION].pfnDlgProc = GetMessageInformation; Pages[PAGE_GETMSG_INFORMATION].pszHeaderTitle = MAKEINTRESOURCE(IDS_MESSAGEINFO); Pages[PAGE_GETMSG_INFORMATION].pszHeaderSubTitle = MAKEINTRESOURCE(IDS_MESSAGEINFO_SUBHEADING); BOOL bReturn = FALSE; if (0 < PropertySheet(&Header)) { // // Finish Pressed // bReturn = TRUE; } else { // // Cancel pressed, we might have to delete the new apphelp in the Database. // bReturn = FALSE; if (nPresentHelpId != -1) { // // There is some apphelp that has been entered in the database // if(!g_pCurrentWizard->m_pDatabase) { assert(FALSE); goto End; } g_pCurrentWizard->m_Entry.appHelp.bPresent = FALSE; g_pCurrentWizard->m_Entry.appHelp.bBlock = FALSE; DeleteAppHelp(g_pCurrentWizard->m_pDatabase, g_pCurrentWizard->m_pDatabase->m_nMAXHELPID); nPresentHelpId = -1; // // Decrement the maximum help id, so that the next apphelp for this database // can use that id // --(g_pCurrentWizard->m_pDatabase->m_nMAXHELPID); } } End: ENABLEWINDOW(g_hDlg, TRUE); return bReturn; } /*++--------------------------------------------------------------------------- All the wizard page routines --------------------------------------------------------------------------- --*/ INT_PTR CALLBACK GetAppInfo( IN HWND hDlg, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam ) /*++ GetAppInfo Desc: Handler for the first page of the wizard. Params: Standard dialog handler parameters IN HWND hDlg IN UINT uMsg IN WPARAM wParam IN LPARAM lParam Return: Standard dialog handler return --*/ { switch (uMsg) { case WM_INITDIALOG: { HWND hParent = GetParent(hDlg); CenterWindow(GetParent(hParent), hParent); if (g_pCurrentWizard->m_bEditing && g_pCurrentWizard->m_Entry.appHelp.bPresent) { // // We are editing an existing apphelp // SetWindowText(hParent, CSTRING(IDS_CUSTOMAPPHELP_EDIT)); } else if (g_pCurrentWizard->m_bEditing && !g_pCurrentWizard->m_Entry.appHelp.bPresent) { // // We are adding a new apphelp to an existing entry, which contains some fix // SetWindowText(hParent, CSTRING(IDS_CUSTOMAPPHELP_ADD)); } else { // // Creating a new apphelp entry // SetWindowText(hParent, CSTRING(IDS_CUSTOMAPPHELP)); } // // Limit the length of the text boxes // SendMessage(GetDlgItem(hDlg, IDC_APPNAME), EM_LIMITTEXT, (WPARAM)LIMIT_APP_NAME, (LPARAM)0); SendMessage(GetDlgItem(hDlg, IDC_VENDOR), EM_LIMITTEXT, (WPARAM)MAX_VENDOR_LENGTH, (LPARAM)0); SendMessage(GetDlgItem(hDlg, IDC_EXEPATH), EM_LIMITTEXT, (WPARAM)MAX_PATH - 1, (LPARAM)0); if (g_pCurrentWizard->m_bEditing) { // // If we are editing a fix, make the App. and exe path text fields read only // SendMessage(GetDlgItem(hDlg, IDC_APPNAME), EM_SETREADONLY, TRUE, 0); SendMessage(GetDlgItem(hDlg, IDC_EXEPATH), EM_SETREADONLY, TRUE, 0); ENABLEWINDOW(GetDlgItem(hDlg, IDC_BROWSE), FALSE); } // // Set the text for the app name field // if (g_pCurrentWizard->m_Entry.strAppName.Length() > 0) { SetDlgItemText(hDlg, IDC_APPNAME, g_pCurrentWizard->m_Entry.strAppName); } else { SetDlgItemText(hDlg, IDC_APPNAME, GetString(IDS_DEFAULT_APP_NAME)); SendMessage(GetDlgItem(hDlg, IDC_APPNAME), EM_SETSEL, 0,-1); } // // Set the text for the vendor name field // if (g_pCurrentWizard->m_Entry.strVendor.Length() > 0) { SetDlgItemText(hDlg, IDC_VENDOR, g_pCurrentWizard->m_Entry.strVendor); } else { SetDlgItemText(hDlg, IDC_VENDOR, GetString(IDS_DEFAULT_VENDOR_NAME)); } // // Set the text for the entry name field // if (g_pCurrentWizard->m_Entry.strExeName.Length() > 0) { SetDlgItemText(hDlg, IDC_EXEPATH, g_pCurrentWizard->m_Entry.strExeName); } SHAutoComplete(GetDlgItem(hDlg, IDC_EXEPATH), AUTOCOMPLETE); // // Force proper Next button state. // SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_APPNAME, EN_CHANGE), 0); break; } case WM_NOTIFY: { NMHDR* pHdr = (NMHDR*)lParam; if (pHdr == NULL) { break; } switch (pHdr->code) { case PSN_SETACTIVE: SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_EXEPATH, EN_CHANGE), 0); break; case PSN_WIZFINISH: case PSN_WIZNEXT: { TCHAR szTemp[MAX_PATH]; TCHAR szEXEPath[MAX_PATH]; TCHAR szPathTemp[MAX_PATH]; *szTemp = *szEXEPath = *szPathTemp = 0; GetDlgItemText(hDlg, IDC_APPNAME, szTemp, ARRAYSIZE(szTemp)); CSTRING::Trim(szTemp); if (!IsValidAppName(szTemp)) { // // The app name contains invalid chars // DisplayInvalidAppNameMessage(hDlg); SetFocus(GetDlgItem(hDlg, IDC_APPNAME)); SetWindowLongPtr(hDlg, DWLP_MSGRESULT,-1); return -1; } g_pCurrentWizard->m_Entry.strAppName = szTemp; GetDlgItemText(hDlg, IDC_EXEPATH, szEXEPath, ARRAYSIZE(szEXEPath)); CSTRING::Trim(szEXEPath); *szPathTemp = 0; // // Check if the file exists. We check for this only when we are creating // a new fix and not when we are editing an existing fix // if (!g_pCurrentWizard->m_bEditing) { HANDLE hFile = CreateFile(szEXEPath, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { // // File does not exist // MessageBox(hDlg, CSTRING(IDS_INVALIDEXE), g_szAppName, MB_OK | MB_ICONWARNING); SetWindowLongPtr(hDlg, DWLP_MSGRESULT,-1); return -1; } CloseHandle(hFile); // // Set the full path // g_pCurrentWizard->m_Entry.strFullpath = szEXEPath; g_pCurrentWizard->m_Entry.strFullpath.ConvertToLongFileName(); // // Set the default mask for the matching attributes to be used // g_pCurrentWizard->dwMaskOfMainEntry = DEFAULT_MASK; // // Set the entry name that will be written in the xml // SafeCpyN(szPathTemp, (PCTSTR)g_pCurrentWizard->m_Entry.strFullpath, ARRAYSIZE(szPathTemp)); PathStripPath(szPathTemp); g_pCurrentWizard->m_Entry.strExeName = szPathTemp; } else if (g_pCurrentWizard->m_Entry.strFullpath.Length() == 0) { // // Since we do not have the complete path, // this SDB was loaded from the disk // g_pCurrentWizard->m_Entry.strFullpath = szEXEPath; } GetDlgItemText(hDlg, IDC_VENDOR, szTemp, ARRAYSIZE(szTemp)); // // Set the vendor information // if (CSTRING::Trim(szTemp)) { g_pCurrentWizard->m_Entry.strVendor = szTemp; } else { g_pCurrentWizard->m_Entry.strVendor = GetString(IDS_DEFAULT_VENDOR_NAME); } break; } } break; } case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_EXEPATH: case IDC_APPNAME: // // Check if all the fields are filled up properly. // We enable disable the Next/Finish button here. // // The vendor name field is not mandatory // // if (EN_CHANGE == HIWORD(wParam)) { TCHAR szTemp[MAX_PATH]; DWORD dwFlags = 0; BOOL bEnable = FALSE; *szTemp = 0; GetDlgItemText(hDlg, IDC_APPNAME, szTemp, ARRAYSIZE(szTemp)); bEnable = ValidInput(szTemp); GetDlgItemText(hDlg, IDC_EXEPATH, szTemp, ARRAYSIZE(szTemp)); bEnable &= ValidInput(szTemp); if (bEnable) { dwFlags |= PSWIZB_NEXT; if (g_pCurrentWizard->m_bEditing) { dwFlags |= PSWIZB_FINISH; } } else { if (g_pCurrentWizard->m_bEditing) { dwFlags |= PSWIZB_DISABLEDFINISH; } } SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, dwFlags); } break; case IDC_BROWSE: { CSTRING szFilename; TCHAR szBuffer[64] = TEXT(""); HWND hwndFocus = GetFocus(); GetString(IDS_EXEFILTER, szBuffer, ARRAYSIZE(szBuffer)); if (GetFileName(hDlg, CSTRING(IDS_FINDEXECUTABLE), szBuffer, TEXT(""), CSTRING(IDS_EXE_EXT), OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST, TRUE, szFilename)) { SetDlgItemText(hDlg, IDC_EXEPATH, szFilename); // // Force proper Next button state. // SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_EXEPATH, EN_CHANGE), 0); } SetFocus(hwndFocus); break; } } } return FALSE; } INT_PTR CALLBACK GetMessageType( IN HWND hDlg, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam ) /*++ GetMessageType Desc: Handler for the third wizard page. This routine collects the type of the apphelp message. One of soft block or hard block. These are set in @pEntry.apphelp Params: Standard dialog handler parameters IN HWND hDlg IN UINT uMsg IN WPARAM wParam IN LPARAM lParam Return: Standard dialog handler return --*/ { switch (uMsg) { case WM_INITDIALOG: // // Set the type of the app help radio button // if (g_pCurrentWizard->m_Entry.appHelp.bBlock == FALSE || g_pCurrentWizard->m_Entry.appHelp.bPresent == FALSE) { SendMessage(GetDlgItem(hDlg, IDC_NOBLOCK), BM_SETCHECK, 1, 0); } else { SendMessage(GetDlgItem(hDlg, IDC_BLOCK), BM_SETCHECK, 1, 0); } return TRUE; case WM_NOTIFY: { NMHDR* pHdr = (NMHDR*)lParam; if (pHdr == NULL) { break; } switch (pHdr->code) { case PSN_WIZFINISH: case PSN_WIZNEXT: { int iReturn = SendMessage(GetDlgItem(hDlg, IDC_NOBLOCK), BM_GETCHECK, 1, 0); if (iReturn == BST_CHECKED) { // // Soft block // g_pCurrentWizard->m_Entry.appHelp.bBlock = FALSE; } else { // // Hard block // g_pCurrentWizard->m_Entry.appHelp.bBlock = TRUE; } // // Set the severity depending upon type of block // if (g_pCurrentWizard->m_Entry.appHelp.bBlock) { g_pCurrentWizard->m_Entry.appHelp.severity = APPTYPE_INC_HARDBLOCK; } else { g_pCurrentWizard->m_Entry.appHelp.severity = APPTYPE_INC_NOBLOCK; } break; } case PSN_SETACTIVE: { DWORD dwFlags = PSWIZB_NEXT | PSWIZB_BACK; // // Set finish buttton status appropriately if we are editing // if (g_pCurrentWizard->m_bEditing) { if (g_pCurrentWizard->m_Entry.appHelp.bPresent) { dwFlags |= PSWIZB_FINISH; } else { dwFlags |= PSWIZB_DISABLEDFINISH; } } // // Set the buttons // SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, dwFlags); return TRUE; } } break; } } return FALSE; } INT_PTR CALLBACK GetMessageInformation( IN HWND hDlg, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam ) /*++ GetMessageInformation Desc: Handler for the last wizard page. This routine collects the apphelp message and the url for the apphelp. Creates a new apphelp message and puts the apphelp message inside the database. When we are editing a apphelp, the previous apphelp needs to be removed Params: Standard dialog handler parameters IN HWND hDlg IN UINT uMsg IN WPARAM wParam IN LPARAM lParam Return: Standard dialog handler return --*/ { switch (uMsg) { case WM_INITDIALOG: { // // Set the maximum length of the text boxes // SendMessage(GetDlgItem(hDlg, IDC_URL), EM_LIMITTEXT, (WPARAM)MAX_URL_LENGTH, (LPARAM)0); SendMessage(GetDlgItem(hDlg, IDC_MSG_SUMMARY), EM_LIMITTEXT, (WPARAM)MAX_MESSAGE_LENGTH, (LPARAM)0); if (g_pCurrentWizard->m_bEditing && g_pCurrentWizard->m_Entry.appHelp.bPresent) { PAPPHELP pAppHelp= g_pCurrentWizard->m_Entry.appHelp.pAppHelpinLib; if (pAppHelp == NULL) { // // This is an error. We should have had a proper value.. // assert(FALSE); Dbg(dlError, "[GetMessageInformation] WM_INITDIALOG: pApphelp is NULL"); break; } if (pAppHelp->strURL.Length()) { SetDlgItemText(hDlg, IDC_URL, pAppHelp->strURL); } SetDlgItemText(hDlg, IDC_MSG_SUMMARY, pAppHelp->strMessage); } // // Force proper Next/Finish button state. // SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_MSG_SUMMARY, EN_CHANGE), 0); break; } case WM_NOTIFY: { NMHDR * pHdr = (NMHDR*)lParam; switch (pHdr->code) { case PSN_SETACTIVE: // // Force proper Next/Finish button state // SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_MSG_SUMMARY, EN_CHANGE), 0); break; case PSN_WIZFINISH: if (!OnAppHelpFinish(hDlg)) { // // We failed most probably because the message input was not valid // MessageBox(hDlg, GetString(IDS_INVALID_APPHELP_MESSAGE), g_szAppName, MB_ICONWARNING); SetWindowLongPtr(hDlg, DWLP_MSGRESULT,-1); return -1; } return TRUE; } } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_MSG_SUMMARY: if (EN_CHANGE == HIWORD(wParam)) { BOOL bEnable = (GetWindowTextLength(GetDlgItem(hDlg, IDC_MSG_SUMMARY)) > 0) ? TRUE:FALSE; DWORD dwFlags = PSWIZB_BACK; if (bEnable) { dwFlags |= PSWIZB_FINISH; } else { if (g_pCurrentWizard->m_bEditing) { dwFlags |= PSWIZB_DISABLEDFINISH; } } ENABLEWINDOW(GetDlgItem(hDlg, IDC_TESTRUN), bEnable); SendMessage(GetParent(hDlg), PSM_SETWIZBUTTONS, 0, dwFlags); } break; case IDC_TESTRUN: { if (g_bAdmin == FALSE) { // // Test run will need to call sdbinst.exe which will not run if we are // not an admin // MessageBox(hDlg, GetString(IDS_ERRORNOTADMIN), g_szAppName, MB_ICONINFORMATION); break; } // // Save the apphelp of the entry so that we can revert back after test run. // After test run, the database and the entry should be in the same state as // it was before test run. Any apphelp message added to the database should be // removed and any apphelp properties that were changed for the entry should be // reverted // APPHELP AppHelpPrev = g_pCurrentWizard->m_Entry.appHelp; // // Add apphelp info to the library and set the fields of the entry // if (!OnAppHelpTestRun(hDlg)) { // // We failed most probably because the message input was not valid // MessageBox(hDlg, GetString(IDS_INVALID_APPHELP_MESSAGE), g_szAppName, MB_ICONWARNING); break; } TestRun(&g_pCurrentWizard->m_Entry, &g_pCurrentWizard->m_Entry.strFullpath, NULL, hDlg); // // This is a hack!!!. TestRun launches a process using CreateProcess // and then the modal wizard starts behaving like a modeless wizard // ENABLEWINDOW(g_hDlg, FALSE); // // We have to delete the apphelp message that has been added to the library. // if (((CAppHelpWizard*)g_pCurrentWizard)->nPresentHelpId != -1) { if (g_pCurrentWizard->m_pDatabase == NULL) { assert(FALSE); break; } DeleteAppHelp(g_pCurrentWizard->m_pDatabase, g_pCurrentWizard->m_pDatabase->m_nMAXHELPID); g_pCurrentWizard->m_Entry.appHelp.bPresent = FALSE; g_pCurrentWizard->m_Entry.appHelp.bBlock = FALSE; --(g_pCurrentWizard->m_pDatabase->m_nMAXHELPID); ((CAppHelpWizard*)g_pCurrentWizard)->nPresentHelpId = -1; } // // Revert the apphelp properties. This is necessary for edit mode as // OnAppHelpTestRun will make changes to g_pCurrentWizard->m_Entry.appHelp. // g_pCurrentWizard->m_Entry.appHelp = AppHelpPrev; SetActiveWindow(hDlg); SetFocus(hDlg); } break; } } return FALSE; } BOOL DeleteAppHelp( IN PDATABASE pDatabase, IN DWORD nHelpID ) /*++ DeleteAppHelp Desc: Deletes the AppHelp message with ID of nHelpID from database pDatabase Params: IN PDATABASE pDatabase : The database in which the apphelp message lives IN DWORD nHelpID : ID of the apphelp message that has to be deleted Return: TRUE: The apphelp message was deleted FALSE: Otherwise --*/ { if (pDatabase == NULL) { assert(FALSE); return FALSE; } PAPPHELP pAppHelp = pDatabase->pAppHelp; PAPPHELP pPrev = NULL; while (pAppHelp) { if (pAppHelp->HTMLHELPID == nHelpID) { if (pPrev == NULL) { pDatabase->pAppHelp = pDatabase->pAppHelp->pNext; } else { pPrev->pNext = pAppHelp->pNext; } delete pAppHelp; return TRUE; } else { pPrev = pAppHelp; pAppHelp = pAppHelp->pNext; } } return FALSE; } BOOL OnAppHelpTestRun( IN HWND hDlg ) /*++ OnAppHelpTestRun Desc: Handles the test run case. Lets OnAppHelpFinish handle it. This routine is invoked when the user presses Test Run Params: IN HWND hDlg: The wizard page containing the Test-Run button --*/ { return OnAppHelpFinish(hDlg, TRUE); } BOOL OnAppHelpFinish( IN HWND hDlg, IN BOOL bTestRun // (FALSE) ) /*++ OnAppHelpFinish Desc: Handles the user's pressing Finish button in the wizard Also is called by the routine that handles the pressing of Test Run button Params: IN HWND hDlg : The wizard page IN BOOL bTestRun (FALSE) : Whether this routine is invoked because of pressing Test-Run or Finish Return: void --*/ { K_SIZE k_szTemp = MAX_MESSAGE_LENGTH + 1; PTSTR pszTemp = new TCHAR[k_szTemp]; BOOL bOk = TRUE; if (pszTemp == NULL) { bOk = FALSE; goto End; } *pszTemp = 0; GetDlgItemText(hDlg, IDC_MSG_SUMMARY, pszTemp, k_szTemp); if (ValidInput(pszTemp) == FALSE) { bOk = FALSE; goto End; } // // If we are in editing mode we have to remove the previous AppHelp // from the Lib. But NOT if this function is being called because of test run !! // if (g_pCurrentWizard->m_bEditing && !bTestRun) { if (g_pCurrentWizard->m_Entry.appHelp.bPresent) { DeleteAppHelp(g_pCurrentWizard->m_pDatabase, g_pCurrentWizard->m_Entry.appHelp.HTMLHELPID); } } // // Create a new apphelp message that we will put in the lib of the database. // The entry being apphelped will point to this though its Apphelp.pAppHelpinLib // PAPPHELP pAppHelp = NULL; pAppHelp = new APPHELP; if (pAppHelp == NULL) { MEM_ERR; bOk = FALSE; goto End; } assert(g_pCurrentWizard->m_pDatabase); // // Give it the next apphelp message id // pAppHelp->HTMLHELPID = ++(g_pCurrentWizard->m_pDatabase->m_nMAXHELPID); pAppHelp->strMessage = pszTemp; pAppHelp->strMessage.Trim(); *pszTemp = 0; GetDlgItemText(hDlg, IDC_URL, pszTemp, k_szTemp); pAppHelp->strURL = pszTemp; pAppHelp->strURL.Trim(); // // Add the APPHELP message in the Library. // pAppHelp->pNext = g_pCurrentWizard->m_pDatabase->pAppHelp; g_pCurrentWizard->m_pDatabase->pAppHelp = pAppHelp; // // Indicate that we have added a new apphelp message in the database. If during an // Apphelp wizard invocation, no apphelp message was added in the database // then (CAppHelpWizard*)g_pCurrentWizard)->nPresentHelpId should be equal // to -1 // ((CAppHelpWizard*)g_pCurrentWizard)->nPresentHelpId = pAppHelp->HTMLHELPID; // // Add the AppHelp fields for the entry // g_pCurrentWizard->m_Entry.appHelp.bPresent = TRUE; g_pCurrentWizard->m_Entry.appHelp.pAppHelpinLib = pAppHelp; g_pCurrentWizard->m_Entry.appHelp.HTMLHELPID = ((CAppHelpWizard*)g_pCurrentWizard)->nPresentHelpId; End: if (pszTemp) { delete[] pszTemp; pszTemp = NULL; } return bOk; }