Add beginnings of the Help viewer.

diff --git a/dlls/hhctrl.ocx/help.c b/dlls/hhctrl.ocx/help.c
new file mode 100644
index 0000000..a929556
--- /dev/null
+++ b/dlls/hhctrl.ocx/help.c
@@ -0,0 +1,250 @@
+/*
+ * Help Viewer Implementation
+ *
+ * Copyright 2005 James Hawkins
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "commctrl.h"
+#include "htmlhelp.h"
+#include "ole2.h"
+
+/* Window type defaults */
+
+#define WINTYPE_DEFAULT_X       280
+#define WINTYPE_DEFAULT_Y       100
+#define WINTYPE_DEFAULT_WIDTH   740
+#define WINTYPE_DEFAULT_HEIGHT  640
+
+typedef struct tagHHInfo
+{
+    HH_WINTYPEW *pHHWinType;
+    HINSTANCE hInstance;
+    LPCWSTR szCmdLine;
+    HFONT hFont;
+} HHInfo;
+
+static LPWSTR HH_ANSIToUnicode(LPCSTR ansi)
+{
+    LPWSTR unicode;
+    int count;
+
+    count = MultiByteToWideChar(CP_ACP, 0, ansi, -1, NULL, 0);
+    unicode = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
+    MultiByteToWideChar(CP_ACP, 0, ansi, -1, unicode, count);
+
+    return unicode;
+}
+
+/* Toolbar */
+
+static BOOL HH_AddToolbar(HHInfo *pHHInfo)
+{
+    return TRUE;
+}
+
+/* Navigation Pane */
+
+static BOOL HH_AddNavigationPane(HHInfo *pHHInfo)
+{
+    return TRUE;
+}
+
+/* HTML Pane */
+
+static BOOL HH_AddHTMLPane(HHInfo *pHHInfo)
+{
+    return TRUE;
+}
+
+/* Viewer Window */
+
+LRESULT CALLBACK Help_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    PAINTSTRUCT ps;
+    HDC hdc;
+
+    switch (message)
+    {
+
+        case WM_PAINT:
+            hdc = BeginPaint(hWnd, &ps);
+            EndPaint(hWnd, &ps);
+            break;
+        case WM_DESTROY:
+            PostQuitMessage(0);
+            break;
+
+        default:
+            return DefWindowProcW(hWnd, message, wParam, lParam);
+    }
+
+    return 0;
+}
+
+static BOOL HH_CreateHelpWindow(HHInfo *pHHInfo)
+{
+    HWND hWnd;
+    HINSTANCE hInstance = pHHInfo->hInstance;
+    WNDCLASSEXW wcex;
+    DWORD dwStyles, dwExStyles;
+    DWORD x, y, width, height;
+
+    static const WCHAR windowClassW[] = {
+        'H','H',' ', 'P','a','r','e','n','t',0
+    };
+
+    static const WCHAR windowTitleW[] = {
+        'H','T','M','L',' ','H','e','l','p',0
+    };
+
+    wcex.cbSize         = sizeof(WNDCLASSEXW);
+    wcex.style          = CS_HREDRAW | CS_VREDRAW;
+    wcex.lpfnWndProc    = (WNDPROC)Help_WndProc;
+    wcex.cbClsExtra     = 0;
+    wcex.cbWndExtra     = 0;
+    wcex.hInstance      = hInstance;
+    wcex.hIcon          = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
+    wcex.hCursor        = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
+    wcex.hbrBackground  = (HBRUSH)(COLOR_BACKGROUND + 1);
+    wcex.lpszMenuName   = NULL;
+    wcex.lpszClassName  = windowClassW;
+    wcex.hIconSm        = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
+
+    RegisterClassExW(&wcex);
+
+    dwStyles = WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
+    dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR |
+                 WS_EX_WINDOWEDGE | WS_EX_APPWINDOW;
+
+    /* these will be loaded from the CHM file in the future if they're provided */
+    x = WINTYPE_DEFAULT_X;
+    y = WINTYPE_DEFAULT_Y;
+    width = WINTYPE_DEFAULT_WIDTH;
+    height = WINTYPE_DEFAULT_HEIGHT;
+
+    hWnd = CreateWindowExW(dwExStyles, windowClassW, windowTitleW, dwStyles,
+                           x, y, width, height, NULL, NULL, hInstance, NULL);
+    if (!hWnd)
+        return FALSE;
+
+    ShowWindow(hWnd, SW_SHOW);
+    UpdateWindow(hWnd);
+
+    /* store the pointer to the HH info struct */
+    SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pHHInfo);
+
+    pHHInfo->pHHWinType->hwndHelp = hWnd;
+    return TRUE;
+}
+
+static void HH_CreateFont(HHInfo *pHHInfo)
+{
+    LOGFONTW lf;
+
+    GetObjectW(GetStockObject(ANSI_VAR_FONT), sizeof(LOGFONTW), &lf);
+    lf.lfWeight = FW_NORMAL;
+    lf.lfItalic = FALSE;
+    lf.lfUnderline = FALSE;
+
+    pHHInfo->hFont = CreateFontIndirectW(&lf);
+}
+
+static void HH_InitRequiredControls(DWORD dwControls)
+{
+    INITCOMMONCONTROLSEX icex;
+
+    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+    icex.dwICC = dwControls;
+    InitCommonControlsEx(&icex);
+}
+
+/* Creates the whole package */
+static BOOL HH_CreateViewer(HHInfo *pHHInfo)
+{
+    HH_CreateFont(pHHInfo);
+
+    if (!HH_CreateHelpWindow(pHHInfo))
+        return FALSE;
+
+    HH_InitRequiredControls(ICC_BAR_CLASSES);
+
+    if (!HH_AddToolbar(pHHInfo))
+        return FALSE;
+
+    if (!HH_AddNavigationPane(pHHInfo))
+        return FALSE;
+
+    if (!HH_AddHTMLPane(pHHInfo))
+        return FALSE;
+
+    return TRUE;
+}
+
+static HHInfo *HH_OpenHH(HINSTANCE hInstance, LPCWSTR szCmdLine)
+{
+    HHInfo *pHHInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HHInfo));
+
+    pHHInfo->pHHWinType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HH_WINTYPEW));
+    pHHInfo->hInstance = hInstance;
+    pHHInfo->szCmdLine = szCmdLine;
+
+    return pHHInfo;
+}
+
+static void HH_Close(HHInfo *pHHInfo)
+{
+    if (!pHHInfo)
+        return;
+
+    HeapFree(GetProcessHeap(), 0, pHHInfo->pHHWinType);
+}
+
+/* FIXME: Check szCmdLine for bad arguments */
+int WINAPI doWinMain(HINSTANCE hInstance, LPSTR szCmdLine)
+{
+    MSG msg;
+    HHInfo *pHHInfo;
+
+    if (OleInitialize(NULL) != S_OK)
+        return -1;
+
+    pHHInfo = HH_OpenHH(hInstance, HH_ANSIToUnicode(szCmdLine));
+    if (!pHHInfo || !HH_CreateViewer(pHHInfo))
+    {
+        OleUninitialize();
+        return -1;
+    }
+
+    while (GetMessageW(&msg, 0, 0, 0))
+    {
+        TranslateMessage(&msg);
+        DispatchMessageW(&msg);
+    }
+
+    HH_Close(pHHInfo);
+    HeapFree(GetProcessHeap(), 0, pHHInfo);
+    OleUninitialize();
+
+    return 0;
+}