Sync with trunk r58740.
[reactos.git] / dll / win32 / hhctrl.ocx / hhctrl.c
index 5aa5e72..303d860 100644 (file)
 
 #include <wine/debug.h>
 
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "htmlhelp.h"
+#include "ole2.h"
+#include "rpcproxy.h"
+
 #define INIT_GUID
 #include "hhctrl.h"
 
@@ -29,6 +41,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
 HINSTANCE hhctrl_hinstance;
 BOOL hh_process = FALSE;
 
+extern struct list window_list;
+
 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, LPVOID lpvReserved)
 {
     TRACE("(%p,%d,%p)\n", hInstance, fdwReason, lpvReserved);
@@ -86,9 +100,41 @@ static const char *command_to_string(UINT command)
 #undef X
 }
 
-static BOOL resolve_filename(const WCHAR *filename, WCHAR *fullname, DWORD buflen)
+static BOOL resolve_filename(const WCHAR *filename, WCHAR *fullname, DWORD buflen, WCHAR **index, WCHAR **window)
 {
+    const WCHAR *extra;
+    WCHAR chm_file[MAX_PATH];
+
     static const WCHAR helpW[] = {'\\','h','e','l','p','\\',0};
+    static const WCHAR delimW[] = {':',':',0};
+    static const WCHAR delim2W[] = {'>',0};
+
+    filename = skip_schema(filename);
+
+    /* the format is "helpFile[::/index][>window]" */
+    if (index) *index = NULL;
+    if (window) *window = NULL;
+
+    extra = strstrW(filename, delim2W);
+    if (extra)
+    {
+        memcpy(chm_file, filename, (extra-filename)*sizeof(WCHAR));
+        chm_file[extra-filename] = 0;
+        filename = chm_file;
+        if (window)
+            *window = strdupW(extra+1);
+    }
+
+    extra = strstrW(filename, delimW);
+    if (extra)
+    {
+        if (filename != chm_file)
+            memcpy(chm_file, filename, (extra-filename)*sizeof(WCHAR));
+        chm_file[extra-filename] = 0;
+        filename = chm_file;
+        if (index)
+            *index = strdupW(extra+2);
+    }
 
     GetFullPathNameW(filename, buflen, fullname, NULL);
     if (GetFileAttributesW(fullname) == INVALID_FILE_ATTRIBUTES)
@@ -115,64 +161,116 @@ HWND WINAPI HtmlHelpW(HWND caller, LPCWSTR filename, UINT command, DWORD_PTR dat
     {
     case HH_DISPLAY_TOPIC:
     case HH_DISPLAY_TOC:
+    case HH_DISPLAY_INDEX:
     case HH_DISPLAY_SEARCH:{
-        static const WCHAR delimW[] = {':',':',0};
-        HHInfo *info;
         BOOL res;
-        WCHAR chm_file[MAX_PATH];
-        const WCHAR *index;
-
-        FIXME("Not all HH cases handled correctly\n");
+        NMHDR nmhdr;
+        HHInfo *info = NULL;
+        WCHAR *window = NULL;
+        const WCHAR *index = NULL;
+        WCHAR *default_index = NULL;
+        int tab_index = TAB_CONTENTS;
 
         if (!filename)
             return NULL;
 
-        index = strstrW(filename, delimW);
-        if (index)
-        {
-            memcpy(chm_file, filename, (index-filename)*sizeof(WCHAR));
-            chm_file[index-filename] = 0;
-            filename = chm_file;
-            index += 2; /* advance beyond "::" for calling NavigateToChm() later */
-        }
-
-        if (!resolve_filename(filename, fullname, MAX_PATH))
+        if (!resolve_filename(filename, fullname, MAX_PATH, &default_index, &window))
         {
             WARN("can't find %s\n", debugstr_w(filename));
             return 0;
         }
+        index = default_index;
+
+        if (window)
+            info = find_window(window);
 
-        info = CreateHelpViewer(fullname);
+        info = CreateHelpViewer(info, fullname, caller);
         if(!info)
+        {
+            heap_free(default_index);
+            heap_free(window);
             return NULL;
+        }
 
         if(!index)
             index = info->WinType.pszFile;
+        if(!info->WinType.pszType)
+            info->WinType.pszType = info->stringsW.pszType = window;
+        else
+            heap_free(window);
+
+        /* called to load a specified topic */
+        switch(command)
+        {
+        case HH_DISPLAY_TOPIC:
+        case HH_DISPLAY_TOC:
+            if (data)
+                index = (const WCHAR *)data;
+            break;
+        }
 
         res = NavigateToChm(info, info->pCHMInfo->szFile, index);
+        heap_free(default_index);
+
         if(!res)
         {
             ReleaseHelpViewer(info);
             return NULL;
         }
+
+        switch(command)
+        {
+        case HH_DISPLAY_TOPIC:
+        case HH_DISPLAY_TOC:
+            tab_index = TAB_CONTENTS;
+            break;
+        case HH_DISPLAY_INDEX:
+            tab_index = TAB_INDEX;
+            if (data)
+                FIXME("Should select keyword '%s'.\n", debugstr_w((WCHAR *)data));
+            break;
+        case HH_DISPLAY_SEARCH:
+            tab_index = TAB_SEARCH;
+            if (data)
+                FIXME("Should display search specified by HH_FTS_QUERY structure.\n");
+            break;
+        }
+        /* open the requested tab */
+        memset(&nmhdr, 0, sizeof(nmhdr));
+        nmhdr.code = TCN_SELCHANGE;
+        SendMessageW(info->hwndTabCtrl, TCM_SETCURSEL, (WPARAM)info->tabs[tab_index].id, 0);
+        SendMessageW(info->WinType.hwndNavigation, WM_NOTIFY, 0, (LPARAM)&nmhdr);
+
         return info->WinType.hwndHelp;
     }
     case HH_HELP_CONTEXT: {
-        HHInfo *info;
+        WCHAR *window = NULL;
+        HHInfo *info = NULL;
         LPWSTR url;
 
         if (!filename)
             return NULL;
 
-        if (!resolve_filename(filename, fullname, MAX_PATH))
+        if (!resolve_filename(filename, fullname, MAX_PATH, NULL, &window))
         {
             WARN("can't find %s\n", debugstr_w(filename));
             return 0;
         }
 
-        info = CreateHelpViewer(fullname);
+        if (window)
+            info = find_window(window);
+
+        info = CreateHelpViewer(info, fullname, caller);
         if(!info)
+        {
+            heap_free(window);
             return NULL;
+        }
+
+        if(!info->WinType.pszType)
+            info->WinType.pszType = info->stringsW.pszType = window;
+        else
+            heap_free(window);
 
         url = FindContextAlias(info->pCHMInfo, data);
         if(!url)
@@ -195,6 +293,67 @@ HWND WINAPI HtmlHelpW(HWND caller, LPCWSTR filename, UINT command, DWORD_PTR dat
         }
         return 0;
     }
+    case HH_CLOSE_ALL: {
+        HHInfo *info, *next;
+
+        LIST_FOR_EACH_ENTRY_SAFE(info, next, &window_list, HHInfo, entry)
+        {
+            TRACE("Destroying window %s.\n", debugstr_w(info->WinType.pszType));
+            ReleaseHelpViewer(info);
+        }
+        return 0;
+    }
+    case HH_SET_WIN_TYPE: {
+        HH_WINTYPEW *wintype = (HH_WINTYPEW *)data;
+        WCHAR *window = NULL;
+        HHInfo *info = NULL;
+
+        if (!filename && wintype->pszType)
+            window = strdupW(wintype->pszType);
+        else if (!filename || !resolve_filename(filename, fullname, MAX_PATH, NULL, &window) || !window)
+        {
+            WARN("can't find window name: %s\n", debugstr_w(filename));
+            return 0;
+        }
+        info = find_window(window);
+        if (!info)
+        {
+            info = heap_alloc_zero(sizeof(HHInfo));
+            info->WinType.pszType = info->stringsW.pszType = window;
+            list_add_tail(&window_list, &info->entry);
+        }
+        else
+            heap_free(window);
+
+        TRACE("Changing WINTYPE, fsValidMembers=0x%x\n", wintype->fsValidMembers);
+
+        MergeChmProperties(wintype, info, TRUE);
+        UpdateHelpWindow(info);
+        return 0;
+    }
+    case HH_GET_WIN_TYPE: {
+        HH_WINTYPEW *wintype = (HH_WINTYPEW *)data;
+        WCHAR *window = NULL;
+        HHInfo *info = NULL;
+
+        if (!filename || !resolve_filename(filename, fullname, MAX_PATH, NULL, &window) || !window)
+        {
+            WARN("can't find window name: %s\n", debugstr_w(filename));
+            return 0;
+        }
+        info = find_window(window);
+        if (!info)
+        {
+            WARN("Could not find window named %s.\n", debugstr_w(window));
+            heap_free(window);
+            return (HWND)~0;
+        }
+
+        TRACE("Retrieving WINTYPE for %s.\n", debugstr_w(window));
+        *wintype = info->WinType;
+        heap_free(window);
+        return 0;
+    }
     default:
         FIXME("HH case %s not handled.\n", command_to_string( command ));
     }
@@ -202,21 +361,47 @@ HWND WINAPI HtmlHelpW(HWND caller, LPCWSTR filename, UINT command, DWORD_PTR dat
     return 0;
 }
 
+static void wintypeAtoW(const HH_WINTYPEA *data, HH_WINTYPEW *wdata, struct wintype_stringsW *stringsW)
+{
+    memcpy(wdata, data, sizeof(*data));
+    /* convert all of the ANSI strings to Unicode */
+    wdata->pszType       = stringsW->pszType       = strdupAtoW(data->pszType);
+    wdata->pszCaption    = stringsW->pszCaption    = strdupAtoW(data->pszCaption);
+    wdata->pszToc        = stringsW->pszToc        = strdupAtoW(data->pszToc);
+    wdata->pszIndex      = stringsW->pszIndex      = strdupAtoW(data->pszIndex);
+    wdata->pszFile       = stringsW->pszFile       = strdupAtoW(data->pszFile);
+    wdata->pszHome       = stringsW->pszHome       = strdupAtoW(data->pszHome);
+    wdata->pszJump1      = stringsW->pszJump1      = strdupAtoW(data->pszJump1);
+    wdata->pszJump2      = stringsW->pszJump2      = strdupAtoW(data->pszJump2);
+    wdata->pszUrlJump1   = stringsW->pszUrlJump1   = strdupAtoW(data->pszUrlJump1);
+    wdata->pszUrlJump2   = stringsW->pszUrlJump2   = strdupAtoW(data->pszUrlJump2);
+    wdata->pszCustomTabs = stringsW->pszCustomTabs = strdupAtoW(data->pszCustomTabs);
+}
+
+static void wintypeWtoA(const HH_WINTYPEW *wdata, HH_WINTYPEA *data, struct wintype_stringsA *stringsA)
+{
+    memcpy(data, wdata, sizeof(*wdata));
+    /* convert all of the Unicode strings to ANSI */
+    data->pszType       = stringsA->pszType       = strdupWtoA(wdata->pszType);
+    data->pszCaption    = stringsA->pszCaption    = strdupWtoA(wdata->pszCaption);
+    data->pszToc        = stringsA->pszToc        = strdupWtoA(wdata->pszToc);
+    data->pszIndex      = stringsA->pszFile       = strdupWtoA(wdata->pszIndex);
+    data->pszFile       = stringsA->pszFile       = strdupWtoA(wdata->pszFile);
+    data->pszHome       = stringsA->pszHome       = strdupWtoA(wdata->pszHome);
+    data->pszJump1      = stringsA->pszJump1      = strdupWtoA(wdata->pszJump1);
+    data->pszJump2      = stringsA->pszJump2      = strdupWtoA(wdata->pszJump2);
+    data->pszUrlJump1   = stringsA->pszUrlJump1   = strdupWtoA(wdata->pszUrlJump1);
+    data->pszUrlJump2   = stringsA->pszUrlJump2   = strdupWtoA(wdata->pszUrlJump2);
+    data->pszCustomTabs = stringsA->pszCustomTabs = strdupWtoA(wdata->pszCustomTabs);
+}
+
 /******************************************************************
  *             HtmlHelpA (HHCTRL.OCX.14)
  */
 HWND WINAPI HtmlHelpA(HWND caller, LPCSTR filename, UINT command, DWORD_PTR data)
 {
-    WCHAR *wfile = NULL, *wdata = NULL;
-    DWORD len;
-    HWND result;
-
-    if (filename)
-    {
-        len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
-        wfile = heap_alloc(len*sizeof(WCHAR));
-        MultiByteToWideChar( CP_ACP, 0, filename, -1, wfile, len );
-    }
+    WCHAR *wfile = strdupAtoW( filename );
+    HWND result = 0;
 
     if (data)
     {
@@ -226,22 +411,46 @@ HWND WINAPI HtmlHelpA(HWND caller, LPCSTR filename, UINT command, DWORD_PTR data
         case HH_DISPLAY_SEARCH:
         case HH_DISPLAY_TEXT_POPUP:
         case HH_GET_LAST_ERROR:
-        case HH_GET_WIN_TYPE:
         case HH_KEYWORD_LOOKUP:
-        case HH_SET_WIN_TYPE:
         case HH_SYNC:
             FIXME("structures not handled yet\n");
             break;
 
+        case HH_SET_WIN_TYPE:
+        {
+            struct wintype_stringsW stringsW;
+            HH_WINTYPEW wdata;
+
+            wintypeAtoW((HH_WINTYPEA *)data, &wdata, &stringsW);
+            result = HtmlHelpW( caller, wfile, command, (DWORD_PTR)&wdata );
+            wintype_stringsW_free(&stringsW);
+            goto done;
+        }
+        case HH_GET_WIN_TYPE:
+        {
+            HH_WINTYPEW wdata;
+            HHInfo *info;
+
+            result = HtmlHelpW( caller, wfile, command, (DWORD_PTR)&wdata );
+            if (!wdata.pszType) break;
+            info = find_window(wdata.pszType);
+            if (!info) break;
+            wintype_stringsA_free(&info->stringsA);
+            wintypeWtoA(&wdata, (HH_WINTYPEA *)data, &info->stringsA);
+            goto done;
+        }
+
         case HH_DISPLAY_INDEX:
         case HH_DISPLAY_TOPIC:
         case HH_DISPLAY_TOC:
         case HH_GET_WIN_HANDLE:
         case HH_SAFE_DISPLAY_TOPIC:
-            len = MultiByteToWideChar( CP_ACP, 0, (const char*)data, -1, NULL, 0 );
-            wdata = heap_alloc(len*sizeof(WCHAR));
-            MultiByteToWideChar( CP_ACP, 0, (const char*)data, -1, wdata, len );
-            break;
+        {
+            WCHAR *wdata = strdupAtoW( (const char *)data );
+            result = HtmlHelpW( caller, wfile, command, (DWORD_PTR)wdata );
+            heap_free(wdata);
+            goto done;
+        }
 
         case HH_CLOSE_ALL:
         case HH_HELP_CONTEXT:
@@ -259,10 +468,9 @@ HWND WINAPI HtmlHelpA(HWND caller, LPCSTR filename, UINT command, DWORD_PTR data
         }
     }
 
-    result = HtmlHelpW( caller, wfile, command, wdata ? (DWORD_PTR)wdata : data );
-
+    result = HtmlHelpW( caller, wfile, command, data );
+done:
     heap_free(wfile);
-    heap_free(wdata);
     return result;
 }
 
@@ -275,6 +483,7 @@ int WINAPI doWinMain(HINSTANCE hInstance, LPSTR szCmdLine)
     int len, buflen, mapid = -1;
     WCHAR *filename;
     char *endq = NULL;
+    HWND hwnd;
 
     hh_process = TRUE;
 
@@ -295,6 +504,9 @@ int WINAPI doWinMain(HINSTANCE hInstance, LPSTR szCmdLine)
 
             ptr += strlen("mapid")+1;
             space = strchr(ptr, ' ');
+            /* command line ends without number */
+            if (!space)
+                return 0;
             memcpy(idtxt, ptr, space-ptr);
             idtxt[space-ptr] = '\0';
             mapid = atoi(idtxt);
@@ -315,6 +527,11 @@ int WINAPI doWinMain(HINSTANCE hInstance, LPSTR szCmdLine)
         len = endq - szCmdLine;
     else
         len = strlen(szCmdLine);
+
+    /* no filename given */
+    if (!len)
+        return 0;
+
     buflen = MultiByteToWideChar(CP_ACP, 0, szCmdLine, len, NULL, 0) + 1;
     filename = heap_alloc(buflen * sizeof(WCHAR));
     MultiByteToWideChar(CP_ACP, 0, szCmdLine, len, filename, buflen);
@@ -322,12 +539,18 @@ int WINAPI doWinMain(HINSTANCE hInstance, LPSTR szCmdLine)
 
     /* Open a specific help topic */
     if(mapid != -1)
-        HtmlHelpW(GetDesktopWindow(), filename, HH_HELP_CONTEXT, mapid);
+        hwnd = HtmlHelpW(GetDesktopWindow(), filename, HH_HELP_CONTEXT, mapid);
     else
-        HtmlHelpW(GetDesktopWindow(), filename, HH_DISPLAY_TOPIC, 0);
+        hwnd = HtmlHelpW(GetDesktopWindow(), filename, HH_DISPLAY_TOPIC, 0);
 
     heap_free(filename);
 
+    if (!hwnd)
+    {
+        ERR("Failed to open HTML Help file '%s'.\n", szCmdLine);
+        return 0;
+    }
+
     while (GetMessageW(&msg, 0, 0, 0))
     {
         TranslateMessage(&msg);
@@ -345,3 +568,19 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
     FIXME("(%s %s %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
     return CLASS_E_CLASSNOTAVAILABLE;
 }
+
+/***********************************************************************
+ *             DllRegisterServer (HHCTRL.OCX.@)
+ */
+HRESULT WINAPI DllRegisterServer(void)
+{
+    return __wine_register_resources( hhctrl_hinstance );
+}
+
+/***********************************************************************
+ *             DllUnregisterServer (HHCTRL.OCX.@)
+ */
+HRESULT WINAPI DllUnregisterServer(void)
+{
+    return __wine_unregister_resources( hhctrl_hinstance );
+}