// Copyright (C) Microsoft Corporation 1996-1997, All Rights reserved. // This module contains all the routines necessary for talking to hha.dll. // This dll is installed as part of HtmlHelp Workshop, indicating that a Help // Author is working with the HtmlHelp display. /* TODO: This function calls the following lines TOO many times if (g_hmodHHA == NULL) { if (g_fTriedHHA || !LoadHHA(NULL, _Module.GetModuleInstance())) { this code needs to be consolidated. */ #include "header.h" #include "hhctrl.h" #ifdef _DEBUG #undef THIS_FILE static const char THIS_FILE[] = __FILE__; #endif #include "strtable.h" #include "hha_strtable.h" #include "hhctrl.h" #include "secwin.h" #define DLL_VERSION 0x0018 // from hhafunc.h (help authoring dll project) int (WINAPI *pHHA_msg)(UINT command, WPARAM wParam, LPARAM lParam); PCSTR (STDCALL *pGetDllStringResource)(int idFormatString); int (STDCALL *pDllMsgBox)(int idFormatString, PCSTR pszSubString, UINT nType); static BOOL InitializeHHA(HWND hwnd, HINSTANCE hinst); // persistent local memory class class CDataHHA { public: CDataHHA::CDataHHA() { m_pszMsgBoxTitle = NULL; } CDataHHA::~CDataHHA() { CHECK_AND_FREE( m_pszMsgBoxTitle ); } char* GetMsgBoxTitle(void) { if( !m_pszMsgBoxTitle ) m_pszMsgBoxTitle = lcStrDup(pGetDllStringResource(IDS_AUTHOR_MSG_TITLE)); return m_pszMsgBoxTitle; } private: char* m_pszMsgBoxTitle; }; static CDataHHA s_Data; #if defined(_DEBUG) void WINAPI CopyAssertInfo(PSTR pszDst); void (WINAPI *pAssertErrorReport)(PCSTR pszExpression, UINT line, LPCSTR pszFile); void AssertErrorReport(PCSTR pszExpression, UINT line, LPCSTR pszFile) { if (g_hmodHHA == NULL) { if (g_fTriedHHA || !LoadHHA(NULL, _Module.GetModuleInstance())) { HHAUnavailable: char szMsg[MAX_PATH*2]; wsprintf(szMsg, "%s\n%s (%u)", pszExpression, pszFile, line); #ifdef _DEBUG int answer = ::MessageBox(GetActiveWindow(), pszExpression, "Retry to call DebugBreak()", MB_ABORTRETRYIGNORE); if (answer == IDRETRY) { DebugBreak(); return; } else if (answer == IDIGNORE) { return; } #else MessageBox(GetActiveWindow(), szMsg, "Assertion error", MB_ICONEXCLAMATION); #endif } } if (pAssertErrorReport == NULL) { (FARPROC&) pAssertErrorReport = GetProcAddress(g_hmodHHA, MAKEINTATOM(26)); if (pAssertErrorReport == NULL) goto HHAUnavailable; } pAssertErrorReport(pszExpression, line, pszFile); } /*************************************************************************** FUNCTION: CopyAssertInfo PURPOSE: Allows additional information to be written to the assertion file. PARAMETERS: pszDst -- where to put the additional information. About 900 bytes is available. RETURNS: void COMMENTS: Used when hha.dll is found, and therefore hooked up to assertion errors (HHA will call this). See InitializeHHA. MODIFICATION DATES: 25-Feb-1997 [ralphw] ***************************************************************************/ void WINAPI CopyAssertInfo(PSTR pszDst) { *pszDst = '\0'; return; } #endif // _DEBUG const TCHAR txtRegKeySection[] = "Software\\Microsoft\\HtmlHelp Author"; const TCHAR txtRegKey[] = "location"; extern "C" HMODULE LoadHHA(HWND hwnd, HINSTANCE hinst) { HKEY hkey; TCHAR szPath[MAX_PATH]; if (RegOpenKeyEx(HKEY_CURRENT_USER, txtRegKeySection, 0, KEY_READ, &hkey) == ERROR_SUCCESS) { DWORD type; DWORD cbPath = sizeof(szPath); LONG result = RegQueryValueEx(hkey, txtRegKey, 0, &type, (PBYTE) szPath, &cbPath); RegCloseKey(hkey); if (result == ERROR_SUCCESS) { g_hmodHHA = LoadLibrary(szPath); if (g_hmodHHA != NULL) { if (!InitializeHHA(hwnd, hinst)) { FreeLibrary(g_hmodHHA); g_hmodHHA = NULL; g_fTriedHHA = TRUE; return NULL; } return g_hmodHHA; } } } g_fTriedHHA = TRUE; return NULL; } /*************************************************************************** FUNCTION: InitializeHHA PURPOSE: Initialize the Help Authoring dll PARAMETERS: hwnd -- will be used as the parent of HHA.dll message boxes RETURNS: FALSE if InitializeHHA can't be found, which means a very corrupted HHA.dll COMMENTS: Call this whenever the window handle for messages boxes changes. MODIFICATION DATES: 25-Feb-1997 [ralphw] ***************************************************************************/ typedef void (WINAPI* COPYASSERTINFO)(PSTR pszDst); typedef struct { int cb; HINSTANCE hinstApp; PCSTR pszErrorFile; HWND hwndWindow; COPYASSERTINFO CopyAssertInfo; PCSTR pszMsgBoxTitle; // The following will be filled in by the dll BOOL fDBCSSystem; LCID lcidSystem; BOOL fDualCPU; UINT version; } HHA_INIT; typedef void (WINAPI* INITIALIZEHHA)(HHA_INIT* pinit); void (WINAPI *pInitializeHHA)(HHA_INIT* pinit); static BOOL InitializeHHA(HWND hwnd, HINSTANCE hinst) { ASSERT(g_hmodHHA != NULL); static HWND hwndLast = (HWND) -1; if (hwnd == hwndLast) return TRUE; // no change to window handle, so already initialized if (pInitializeHHA == NULL) { pInitializeHHA = (INITIALIZEHHA) GetProcAddress(g_hmodHHA, MAKEINTATOM(78)); if (pInitializeHHA == NULL) return FALSE; } (FARPROC&) pGetDllStringResource = GetProcAddress(g_hmodHHA, MAKEINTATOM(194)); HHA_INIT hwInit; hwInit.cb = sizeof(HHA_INIT); hwInit.hinstApp = hinst; // BUGBUG: HHA doesn't separate Resource from App. Will get English resource strings in some instances. (HINST_THIS) #if defined(_DEBUG) hwInit.pszErrorFile = "c:\\HtmlHelp.err"; hwInit.CopyAssertInfo = CopyAssertInfo; #else hwInit.pszErrorFile = ""; hwInit.CopyAssertInfo = NULL; #endif hwInit.pszMsgBoxTitle = s_Data.GetMsgBoxTitle(); hwInit.hwndWindow = hwnd; // parent for message boxes hwInit.version = DLL_VERSION; pInitializeHHA(&hwInit); (FARPROC&) pDllMsgBox = GetProcAddress(g_hmodHHA, MAKEINTATOM(115)); (FARPROC&) pHHA_msg = GetProcAddress(g_hmodHHA, MAKEINTATOM(106)); return TRUE; } /*************************************************************************** FUNCTION: doAuthorMessage PURPOSE: Use a format string from HHA.dll, format the message with the supplied string and display it in a message box. PARAMETERS: idStringFormatResource -- must have been defined in HHA.dll pszSubString RETURNS: void COMMENTS: The reason for doing this is to allow for larger, more informative strings for help authors without having to ship those strings in a retail package where users would never see them. MODIFICATION DATES: 25-Feb-1997 [ralphw] ***************************************************************************/ void doAuthorMsg(UINT idStringFormatResource, PCSTR pszSubString) { // Work around known stack overwrite problem in hha.dll // char *pszTempString = lcStrDup(pszSubString); if(pszTempString && strlen(pszTempString) > 768) pszTempString[768] = 0; if (g_hmodHHA == NULL) { if (g_fTriedHHA || !LoadHHA(NULL, _Module.GetModuleInstance())) return; // no HHA.dll, so not a help author } if (pDllMsgBox == NULL) { (FARPROC&) pDllMsgBox = GetProcAddress(g_hmodHHA, MAKEINTATOM(15)); if (pDllMsgBox == NULL) return; } // Note that the resource id is in hha.dll pDllMsgBox(idStringFormatResource, pszTempString, MB_OK); // Track the message in HtmlHelp Workshop if( !pszTempString || !*pszTempString ) HHA_Msg(HHA_SEND_RESID_TO_PARENT, idStringFormatResource, (LPARAM) NULL ); else HHA_Msg(HHA_SEND_RESID_AND_STRING_TO_PARENT, idStringFormatResource, (LPARAM) pszTempString); } void (WINAPI *pReportOleError)(HRESULT, PCSTR); #ifdef _DEBUG void doReportOleError(HRESULT hres) { if (g_hmodHHA == NULL) { if (g_fTriedHHA || !LoadHHA(NULL, _Module.GetModuleInstance())) return; // no HHA.dll, so not a help author } if (pReportOleError == NULL) { (FARPROC&) pReportOleError = GetProcAddress(g_hmodHHA, MAKEINTATOM(234)); if (pReportOleError == NULL) return; } pReportOleError(hres, NULL); } #endif // _DEBUG void SendStringToParent(PCSTR pszMsg) { #ifdef _DEBUG OutputDebugString(pszMsg); #endif if (g_hmodHHA == NULL) { if (g_fTriedHHA || !LoadHHA(NULL, _Module.GetModuleInstance())) return; // no HHA.dll, so not a help author } ASSERT(pHHA_msg); if (!pHHA_msg) { return; } pHHA_msg(HHA_SEND_STRING_TO_PARENT, (WPARAM) pszMsg, 0); } int HHA_Msg(UINT command, WPARAM wParam, LPARAM lParam) { if (g_hmodHHA && pHHA_msg) return pHHA_msg(command, wParam, lParam); if (g_hmodHHA == NULL) { if (g_fTriedHHA || !LoadHHA(NULL, _Module.GetModuleInstance())) return 0; // no HHA.dll, so not a help author } ASSERT(pHHA_msg); if (!pHHA_msg) { return 0; } return pHHA_msg(command, wParam, lParam); } void CHtmlHelpControl::FillGeneralInformation(HHA_GEN_INFO* pgenInfo) { pgenInfo->m_pszBitmap = m_pszBitmap; // pgenInfo->m_cImages = m_cImages; pgenInfo->pflags = m_flags; pgenInfo->m_hfont = m_hfont; pgenInfo->m_clrFont = m_clrFont; pgenInfo->m_hpadding = m_hpadding; pgenInfo->m_vpadding = m_vpadding; pgenInfo->m_hImage = m_hImage; pgenInfo->m_fPopupMenu = m_fPopupMenu; pgenInfo->m_fWinHelpPopup = m_fWinHelpPopup; /* * A TOC image uses an imagelist, the handle for which is not * interchangeable with a "regular" bitmap. To show what it looks like, * we must load it as a regular bitmap. This instance of the bitmap * will get deleted when the CHtmlHelpControl class is deleted. */ if (m_pszBitmap && !m_hImage) { char szBitmap[MAX_PATH]; if (ConvertToCacheFile(m_pszBitmap, szBitmap)) { pgenInfo->m_hImage = m_hImage = LoadImage(_Module.GetResourceInstance(), szBitmap, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); } } if (m_ptblItems) { pgenInfo->cItems = m_ptblItems->CountStrings(); pgenInfo->apszItems = m_ptblItems->GetStringPointers(); } else pgenInfo->cItems = 0; } void (STDCALL *pViewEntry)(HWND hwndParent, HHA_ENTRY_APPEARANCE* pAppear); void DisplayAuthorInfo(CInfoType *pInfoType, CSiteMap* pSiteMap, SITEMAP_ENTRY* pSiteMapEntry, HWND hwndParent, CHtmlHelpControl* phhctrl) { if (!pViewEntry) (FARPROC&) pViewEntry = GetProcAddress(g_hmodHHA, MAKEINTATOM(262)); if (!pViewEntry) { pDllMsgBox(IDS_DLL_OUT_OF_DATE, "", MB_OK); return; } HHA_ENTRY_APPEARANCE entry; ZeroMemory(&entry, sizeof(entry)); entry.version = HHA_REQUIRED_VERSION; entry.pSiteMap = pSiteMap; entry.pSiteMapEntry = pSiteMapEntry; entry.pszWindowName = pSiteMapEntry->GetWindowIndex() ? pSiteMap->GetEntryWindow(pSiteMapEntry) : pSiteMap->GetWindowName(); entry.pszFrameName = pSiteMapEntry->GetFrameIndex() ? pSiteMap->GetEntryFrame(pSiteMapEntry) : pSiteMap->GetFrameName(); /* * We use a CTable so that we can free all the strings in one fell * swoop. */ CTable tblData; entry.apszUrlNames = (PCSTR*) tblData.TableMalloc( (pSiteMapEntry->cUrls * 2) * sizeof(PCSTR)); SITE_ENTRY_URL* pUrl = pSiteMapEntry->pUrls; for (int i = 0; i < pSiteMapEntry->cUrls; i++) { entry.apszUrlNames[i * 2] = pUrl->urlPrimary ? pSiteMap->GetUrlString(pUrl->urlPrimary) : ""; entry.apszUrlNames[i * 2 + 1] = pUrl->urlSecondary ? pSiteMap->GetUrlString(pUrl->urlSecondary) : ""; pUrl = pSiteMap->NextUrlEntry(pUrl); } // Now add the type names if (pInfoType && pInfoType->HowManyInfoTypes()) { entry.apszTypes = (PCSTR*) tblData.TableMalloc(pInfoType->HowManyInfoTypes() * sizeof(PCSTR)); int end = pInfoType->HowManyInfoTypes(); for (int i = 0; i < end; i++) entry.apszTypes[i] = pInfoType->GetInfoTypeName(i + 1); entry.cTypes = end; } else { entry.apszTypes = NULL; entry.cTypes = 0; } if (phhctrl) phhctrl->FillGeneralInformation(&entry.genInfo); entry.genInfo.pszDefWindowName = pSiteMap->GetWindowName(); entry.genInfo.pszDefFrameName = pSiteMap->GetFrameName(); entry.genInfo.pszBackBitmap = pSiteMap->m_pszBackBitmap; if (phhctrl) phhctrl->ModalDialog(TRUE); pViewEntry(FindTopLevelWindow(hwndParent), &entry); if (phhctrl) phhctrl->ModalDialog(FALSE); } // BUGBUG: remove when everything works! void (STDCALL *pItDoesntWork)(void); void ItDoesntWork() { if (g_hmodHHA == NULL) { if (g_fTriedHHA || !LoadHHA(NULL, _Module.GetModuleInstance())) return; // no HHA.dll, so not a help author } if (!pItDoesntWork) (FARPROC&) pItDoesntWork = GetProcAddress(g_hmodHHA, MAKEINTATOM(296)); if (pItDoesntWork) pItDoesntWork(); } BOOL IsHelpAuthor(HWND hwndCaller) { if (g_hmodHHA == NULL) { if (g_fTriedHHA || !LoadHHA(hwndCaller, _Module.GetModuleInstance())) return FALSE; // no HHA.dll, so not a help author } return TRUE; } void (STDCALL *pDoHhctrlVersion)(HWND hwndParent, PCSTR pszCHMVersion); void doHhctrlVersion(HWND hwndParent, PCSTR pszCHMVersion) { if (!pDoHhctrlVersion) (FARPROC&) pDoHhctrlVersion = GetProcAddress(g_hmodHHA, MAKEINTATOM(323)); if (pDoHhctrlVersion) pDoHhctrlVersion(hwndParent, pszCHMVersion); } void (STDCALL *pShowWindowType)(PHH_WINTYPE phh); void doWindowInformation(HWND hwndParent, CHHWinType* phh) { if (!pShowWindowType) (FARPROC&) pShowWindowType = GetProcAddress(g_hmodHHA, MAKEINTATOM(380)); if (pShowWindowType) { CStr csz(""); if (!phh->pszCustomTabs) { for (int iTab = HHWIN_NAVTYPE_CUSTOM_FIRST; iTab < HH_MAX_TABS+1; iTab++) { if (phh->fsWinProperties & (HHWIN_PROP_TAB_CUSTOM1 << (iTab - HH_TAB_CUSTOM_FIRST))) { if (csz.IsNonEmpty()) csz += "\1"; csz += phh->GetExtTab(iTab - HH_TAB_CUSTOM_FIRST)->pszTabName; csz += " -- "; csz += phh->GetExtTab(iTab - HH_TAB_CUSTOM_FIRST)->pszProgId; } } if (csz.IsNonEmpty()) csz += "\1"; phh->pszCustomTabs = csz.psz; PSTR psz = StrChr(phh->pszCustomTabs, '\1'); while (psz) { *psz = '\0'; psz = StrChr(psz + 1, '\1'); } } pShowWindowType(phh); } else if (pDllMsgBox) pDllMsgBox(IDS_DLL_OUT_OF_DATE, "", MB_OK); }