|
|
// File: nmhelp.cpp
#include <precomp.h>
#ifndef UNICODE
#include <nmhelp.h>
#include <htmlhelp.h>
#include <strutil.h>
#include <intlutil.h>
extern BOOL g_fUseMLHelp;
// The main NetMeeting Help file
static const TCHAR s_cszWinHelpFile[] = TEXT("conf.hlp");
static const TCHAR g_pszHHCtrl[] = TEXT("hhctrl.ocx");
static const TCHAR g_szSHLWAPI[] = TEXT("shlwapi.dll"); const LPCSTR szMLWinHelpA = (LPCSTR)395; const LPCSTR szMLHtmlHelpA = (LPCSTR)396; const LPCSTR szMLWinHelpW = (LPCSTR)397; const LPCSTR szMLHtmlHelpW = (LPCSTR)398;
typedef BOOL (WINAPI * PFN_MLWinHelpA)(HWND hwndCaller, LPCSTR lpszHelp, UINT uCommand, DWORD_PTR dwData); typedef HWND (WINAPI * PFN_MLHtmlHelpA)(HWND hwndCaller, LPCSTR pszFile, UINT uCommand, DWORD_PTR dwData, DWORD dwCrossCodePage); typedef BOOL (WINAPI * PFN_MLWinHelpW)(HWND hwndCaller, LPCWSTR lpszHelp, UINT uCommand, DWORD_PTR dwData); typedef HWND (WINAPI * PFN_MLHtmlHelpW)(HWND hwndCaller, LPCWSTR pszFile, UINT uCommand, DWORD_PTR dwData, DWORD dwCrossCodePage);
#ifdef UNICODE
#define szMLWinHelp szMLWinHelpW
#define szMLHtmlHelp szMLHtmlHelpW
#define PFN_MLWinHelp PFN_MLWinHelpW
#define PFN_MLHtmlHelp PFN_MLHtmlHelpW
#else
#define szMLWinHelp szMLWinHelpA
#define szMLHtmlHelp szMLHtmlHelpA
#define PFN_MLWinHelp PFN_MLWinHelpA
#define PFN_MLHtmlHelp PFN_MLHtmlHelpA
#endif
extern "C" HWND HtmlHelpA(HWND hwndCaller, LPCSTR pszFile, UINT uCommand, DWORD_PTR dwData) { static HMODULE g_hmodHHCtrl = NULL; static HWND (WINAPI *g_pHtmlHelpA)(HWND hwndCaller, LPCSTR pszFile, UINT uCommand, DWORD_PTR dwData);
if (NULL == g_hmodHHCtrl) { g_hmodHHCtrl = NmLoadLibrary(g_pszHHCtrl,TRUE); if (NULL == g_hmodHHCtrl) { return NULL; } }
#ifndef _WIN64
if (NULL == g_pHtmlHelpA) { (FARPROC&)g_pHtmlHelpA = GetProcAddress(g_hmodHHCtrl, ATOM_HTMLHELP_API_ANSI); if (NULL == g_pHtmlHelpA) { return NULL; } }
return g_pHtmlHelpA(hwndCaller, pszFile, uCommand, dwData); #else
return NULL; #endif
}
/* N M W I N H E L P */ /*-------------------------------------------------------------------------
%%Function: NmWinHelp
-------------------------------------------------------------------------*/ BOOL NmWinHelp(HWND hWndMain, LPCTSTR lpszHelp, UINT uCommand, DWORD_PTR dwData) { static PFN_MLWinHelp s_pfnMLWinHelp = NULL;
if (g_fUseMLHelp && (NULL == s_pfnMLWinHelp)) { HINSTANCE hLib = NmLoadLibrary(g_szSHLWAPI,TRUE); if (hLib) { s_pfnMLWinHelp = (PFN_MLWinHelp)GetProcAddress(hLib, szMLWinHelp); if (NULL == s_pfnMLWinHelp) { // must be wrong version of shlwapi.dll
FreeLibrary(hLib); g_fUseMLHelp = FALSE; } } else { // cannot find shlwapi.dll
g_fUseMLHelp = FALSE; } }
if (NULL != s_pfnMLWinHelp) { return s_pfnMLWinHelp(hWndMain, lpszHelp, uCommand, dwData); } else { return ::WinHelp(hWndMain, lpszHelp, uCommand, dwData); } }
/* N M H T M L H E L P */ /*-------------------------------------------------------------------------
%%Function: NmHtmlHelp
-------------------------------------------------------------------------*/ HWND NmHtmlHelp(HWND hwndCaller, LPCSTR pszFile, UINT uCommand, DWORD_PTR dwData) { static PFN_MLHtmlHelp s_pfnMLHtmlHelp = NULL;
if (g_fUseMLHelp && (NULL == s_pfnMLHtmlHelp)) { HINSTANCE hLib = NmLoadLibrary(g_szSHLWAPI,TRUE); if (hLib) { s_pfnMLHtmlHelp = (PFN_MLHtmlHelp)GetProcAddress(hLib, szMLHtmlHelp); if (NULL == s_pfnMLHtmlHelp) { // must be wrong version of shlwapi.dll
FreeLibrary(hLib); g_fUseMLHelp = FALSE; } } else { // cannot find shlwapi.dll
g_fUseMLHelp = FALSE; } }
if (NULL != s_pfnMLHtmlHelp) { return s_pfnMLHtmlHelp(hwndCaller, pszFile, uCommand, dwData, 0); } else { return ::HtmlHelp(hwndCaller, pszFile, uCommand, dwData); } }
static const TCHAR s_cszHtmlHelpApiMarshalerWndClass[] = TEXT("NmUtil_HtmlHelpMarshalWnd");
// HtmlHelp api cannot be called from multiple threads... that is, HtmlHelp must be
// called from the same thread in which the DLL is loaded... This is the non-threadsafe
// entry point to HtmlHelp... this must allways be called in the same thread that
// InitHtmlHelpMarshaller was called....
// This is the window procedure that we use to marshall calls to
// HtmlHelp via calls to ShowNmHelp from arbitrary threads
static LRESULT CALLBACK HtmlHelpWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch( uMsg ) { case WM_USER: { LPCTSTR lpcszHelpFile = reinterpret_cast<LPCTSTR>(lParam); NmHtmlHelp(NULL, lpcszHelpFile, HH_DISPLAY_TOPIC, 0); return(TRUE); } }
return DefWindowProc(hwnd, uMsg, wParam, lParam); }
// the html help Apis are not threadsafe...
// In fact, they call CoInitialize in the DLLProcessAttatch...
// So essentially we are going to marshal all calls to HtmlHelp
// Into the context of the first thread to call InitHtmlHelpMarshaller
HRESULT InitHtmlHelpMarshaler(HINSTANCE hInst) { HRESULT hr = S_OK;
WNDCLASS wc; ZeroMemory( &wc, sizeof( wc ) );
wc.lpfnWndProc = HtmlHelpWndProc; wc.hInstance = hInst; wc.lpszClassName = s_cszHtmlHelpApiMarshalerWndClass;
if( RegisterClass( &wc ) ) { HWND hWnd = CreateWindow(s_cszHtmlHelpApiMarshalerWndClass, NULL, 0, 0, 0, 0, NULL, NULL, NULL, hInst, 0 ); if( NULL == hWnd ) { ERROR_OUT(("CreateWindow failed in InitHtmlHelpMarshaler")); hr = HRESULT_FROM_WIN32(GetLastError()); } } else { hr = HRESULT_FROM_WIN32(GetLastError()); }
return hr; }
VOID ShowNmHelp(LPCTSTR lpcszHtmlHelpFile) { HWND hWnd = FindWindow( s_cszHtmlHelpApiMarshalerWndClass, NULL ); if( hWnd ) { SendMessage( hWnd, WM_USER, 0, reinterpret_cast<LPARAM>(lpcszHtmlHelpFile) ); } else { ERROR_OUT(("Could not find the Help Marshaller Window... Has InitHtmlHelpMarshaller been called yet?")); } }
/* D O N M H E L P */ /*-------------------------------------------------------------------------
%%Function: DoNmHelp
Generic routine to display the normal WinHelp information. -------------------------------------------------------------------------*/ VOID DoNmHelp(HWND hwnd, UINT uCommand, DWORD_PTR dwData) { NmWinHelp(hwnd, s_cszWinHelpFile, uCommand, dwData); }
// "WM_HELP" context menu handler (requires HIDC_* entry on the controls)
VOID DoHelp(LPARAM lParam) { LPHELPINFO phi = (LPHELPINFO) lParam; ASSERT(phi->iContextType == HELPINFO_WINDOW); DoNmHelp((HWND) phi->hItemHandle, HELP_CONTEXTPOPUP, phi->dwContextId); }
// "WM_HELP" handler (with control-to-help id map)
VOID DoHelp(LPARAM lParam, const DWORD * rgId) { HWND hwnd = (HWND)(((LPHELPINFO)lParam)->hItemHandle); DoNmHelp(hwnd, HELP_WM_HELP, (DWORD_PTR) rgId); }
// "WM_CONTEXTMENU" handler (with control-to-help id map)
VOID DoHelpWhatsThis(WPARAM wParam, const DWORD * rgId) { HWND hwnd = (HWND)wParam; DoNmHelp(hwnd, HELP_CONTEXTMENU, (DWORD_PTR) rgId); }
VOID ShutDownHelp(void) { DoNmHelp(NULL, HELP_QUIT, 0); // REVIEW: Do we shut down HTML help as well?
}
#endif /* UNICODE */
|