Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'windows/help.c')
-rw-r--r--windows/help.c250
1 files changed, 250 insertions, 0 deletions
diff --git a/windows/help.c b/windows/help.c
new file mode 100644
index 00000000..d087c722
--- /dev/null
+++ b/windows/help.c
@@ -0,0 +1,250 @@
+/*
+ * help.c: centralised functions to launch Windows HTML Help files.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "putty.h"
+#include "putty-rc.h"
+
+#ifdef NO_HTMLHELP
+
+/* If htmlhelp.h is not available, we can't do any of this at all */
+bool has_help(void) { return false; }
+void init_help(void) { }
+void shutdown_help(void) { }
+void launch_help(HWND hwnd, const char *topic) { }
+void quit_help(HWND hwnd) { }
+
+#else
+
+#include <htmlhelp.h>
+
+static char *chm_path = NULL;
+static bool chm_created_by_us = false;
+
+static bool requested_help;
+DECL_WINDOWS_FUNCTION(static, HWND, HtmlHelpA, (HWND, LPCSTR, UINT, DWORD_PTR));
+
+static HRSRC chm_hrsrc;
+static DWORD chm_resource_size = 0;
+static const void *chm_resource = NULL;
+
+int has_embedded_chm(void)
+{
+ static bool checked = false;
+ if (!checked) {
+ checked = true;
+
+ chm_hrsrc = FindResource(
+ NULL, MAKEINTRESOURCE(ID_CUSTOM_CHMFILE),
+ MAKEINTRESOURCE(TYPE_CUSTOM_CHMFILE));
+ }
+ return chm_hrsrc != NULL ? 1 : 0;
+}
+
+static bool find_chm_resource(void)
+{
+ static bool checked = false;
+ if (checked) /* we've been here already */
+ goto out;
+ checked = true;
+
+ /*
+ * Look for a CHM file embedded in this executable as a custom
+ * resource.
+ */
+ if (!has_embedded_chm()) /* set up chm_hrsrc and check if it's NULL */
+ goto out;
+
+ chm_resource_size = SizeofResource(NULL, chm_hrsrc);
+ if (chm_resource_size == 0)
+ goto out;
+
+ HGLOBAL chm_hglobal = LoadResource(NULL, chm_hrsrc);
+ if (chm_hglobal == NULL)
+ goto out;
+
+ chm_resource = (const uint8_t *)LockResource(chm_hglobal);
+
+ out:
+ return chm_resource != NULL;
+}
+
+static bool load_chm_resource(void)
+{
+ bool toret = false;
+ char *filename = NULL;
+ HANDLE filehandle = INVALID_HANDLE_VALUE;
+ bool created = false;
+
+ static bool tried_to_load = false;
+ if (tried_to_load)
+ goto out;
+ tried_to_load = true;
+
+ /*
+ * We've found it! Now write it out into a separate file, so that
+ * htmlhelp.exe can handle it.
+ */
+
+ /* GetTempPath is documented as returning a size of up to
+ * MAX_PATH+1 which does not count the NUL */
+ char tempdir[MAX_PATH + 2];
+ if (GetTempPath(sizeof(tempdir), tempdir) == 0)
+ goto out;
+
+ unsigned long pid = GetCurrentProcessId();
+
+ for (uint64_t counter = 0;; counter++) {
+ filename = dupprintf(
+ "%s\\putty_%lu_%"PRIu64".chm", tempdir, pid, counter);
+ filehandle = CreateFile(
+ filename, GENERIC_WRITE, FILE_SHARE_READ,
+ NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (filehandle != INVALID_HANDLE_VALUE)
+ break; /* success! */
+
+ if (GetLastError() != ERROR_FILE_EXISTS)
+ goto out; /* failed for some other reason! */
+
+ sfree(filename);
+ filename = NULL;
+ }
+ created = true;
+
+ const uint8_t *p = (const uint8_t *)chm_resource;
+ for (DWORD pos = 0; pos < chm_resource_size; pos++) {
+ DWORD to_write = chm_resource_size - pos;
+ DWORD written = 0;
+
+ if (!WriteFile(filehandle, p + pos, to_write, &written, NULL))
+ goto out;
+ pos += written;
+ }
+
+ chm_path = filename;
+ filename = NULL;
+ chm_created_by_us = true;
+ toret = true;
+
+ out:
+ if (created && !toret)
+ DeleteFile(filename);
+ sfree(filename);
+ if (filehandle != INVALID_HANDLE_VALUE)
+ CloseHandle(filehandle);
+ return toret;
+}
+
+static bool find_chm_from_installation(void)
+{
+ static const char *const reg_paths[] = {
+ "Software\\SimonTatham\\PuTTY64\\CHMPath",
+ "Software\\SimonTatham\\PuTTY\\CHMPath",
+ };
+
+ for (size_t i = 0; i < lenof(reg_paths); i++) {
+ char *filename = get_reg_sz_simple(
+ HKEY_LOCAL_MACHINE, reg_paths[i], NULL);
+
+ if (filename) {
+ chm_path = filename;
+ chm_created_by_us = false;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void init_help(void)
+{
+ /* Just in case of multiple calls */
+ static bool already_called = false;
+ if (already_called)
+ return;
+ already_called = true;
+
+ /*
+ * Don't even try looking for the CHM file if we can't even find
+ * the HtmlHelp() API function.
+ */
+ HINSTANCE dllHH = load_system32_dll("hhctrl.ocx");
+ GET_WINDOWS_FUNCTION(dllHH, HtmlHelpA);
+ if (!p_HtmlHelpA) {
+ FreeLibrary(dllHH);
+ return;
+ }
+
+ /*
+ * If there's a CHM file embedded in this executable, we should
+ * use that as the first choice.
+ */
+ if (find_chm_resource())
+ return;
+
+ /*
+ * Otherwise, try looking for the CHM in the location that the
+ * installer marked in the registry.
+ */
+ if (find_chm_from_installation())
+ return;
+}
+
+void shutdown_help(void)
+{
+ if (chm_path && chm_created_by_us) {
+ p_HtmlHelpA(NULL, NULL, HH_CLOSE_ALL, 0);
+ DeleteFile(chm_path);
+ }
+ sfree(chm_path);
+ chm_path = NULL;
+ chm_created_by_us = false;
+}
+
+bool has_help(void)
+{
+ return chm_path != NULL || chm_resource != NULL;
+}
+
+void launch_help(HWND hwnd, const char *topic)
+{
+ if (!chm_path && chm_resource) {
+ /*
+ * If we've been called without already having a file name for
+ * the CHM file, that might be because we've located it in our
+ * resource section but not written it to a temp file yet. Do
+ * so now, on first use.
+ */
+ load_chm_resource();
+ }
+
+ /* If we _still_ don't have a CHM pathname, we just can't display help. */
+ if (!chm_path)
+ return;
+
+ if (topic) {
+ char *fname = dupprintf(
+ "%s::/%s.html>main", chm_path, topic);
+ p_HtmlHelpA(hwnd, fname, HH_DISPLAY_TOPIC, 0);
+ sfree(fname);
+ } else {
+ p_HtmlHelpA(hwnd, chm_path, HH_DISPLAY_TOPIC, 0);
+ }
+ requested_help = true;
+}
+
+void quit_help(HWND hwnd)
+{
+ if (requested_help)
+ p_HtmlHelpA(NULL, NULL, HH_CLOSE_ALL, 0);
+ if (chm_path && chm_created_by_us)
+ DeleteFile(chm_path);
+}
+
+#endif /* NO_HTMLHELP */