Module: win32-duim Synopsis: Win32 help implementation Author: Jason Trenouth, Scott McKay, Andy Armstrong Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND /// Win32 Help management // We could potentially have several FFI declarations for WinHelp // One for each type of data (4th argument). This way the FFI would // automatically take care of translating things like Dylan strings // into Char*'s (addresses of C strings). However, the code in this // file was already divided up to use a single call to WinHelp so I // just added explicit conversions (eg calls 'pointer-address', etc) // into the various 'help-data' methods. (Jason -- 26th March 1997) /// Help Systems define abstract class () end class ; define sealed class () keyword name: = "WinHelp"; end class ; define sealed class () keyword name: = "HTMLHelp"; end class ; // Initialize the default help system on Windows *default-help-system* := make(); /// Windows help display define constant = ; define constant = ; define macro with-help-data { with-help-data (?data:name = ?system:expression, ?command:expression) ?:body end } => { do-with-help-data(?system, ?command, method (?data) ?body end) } end macro with-help-data; define sealed method do-with-help-data (system :: , command :: , continuation :: ) => (#rest values) continuation(help-data(system, command)) end method do-with-help-data; define sealed method do-with-help-data (system :: , command :: , continuation :: ) => (#rest values) with-c-string (data = help-data(system, command)) continuation(pointer-address(data)) end end method do-with-help-data; define sealed method do-with-help-data (system :: , command :: , continuation :: ) => (#rest values) with-c-string (data = help-data(system, command)) with-stack-structure (alink :: ) init-alink(alink, data); continuation(pointer-address(alink)); end with-stack-structure; end with-c-string; end method do-with-help-data; define inline method init-alink (alink :: , data :: ) => () alink.cbstruct-value := safe-size-of(); alink.freserved := #f; alink.pszkeywords-value := data; alink.pszurl-value := null-pointer(); alink.pszmsgtext-value := null-pointer(); alink.pszmsgtitle-value := null-pointer(); alink.pszwindow-value := null-pointer(); alink.findexonfail-value := #t; end method init-alink; define sealed method display-help (framem :: , frame :: , command :: ) => () block () let system = frame-manager-help-system(framem); check-help-system-installed(system); let top-sheet = top-level-sheet(frame); when (top-sheet) with-help-data (data = system, command) do-display-help(system, window-handle(top-sheet), help-path(system, command), help-id(system, command), data) end end; exception (condition :: ) notify-user(format-to-string("%s", condition), owner: frame); end end method display-help; /// Registry utilities define class () keyword format-string: = "Registry entry lookup error \"%s\" with code: %d"; end class ; define method make (class :: subclass(), #key name, result) => (condition :: ) next-method(class, format-arguments: vector(name, result)) end method make; define macro with-open-registry-subkey { with-open-registry-subkey (?subkey:name = ?key:expression, ?name:expression) ?body:body end } => { do-with-open-registry-subkey(?key, ?name, method (?subkey) ?body end) }; end macro with-open-registry-subkey; define method do-with-open-registry-subkey (key, subkeyname, body :: ) => (#rest values) let (result, subkey) = RegOpenKeyEx(key, subkeyname, 0, %logior($KEY-ENUMERATE-SUB-KEYS, $KEY-QUERY-VALUE)); if (result = $ERROR-SUCCESS) block () body(subkey) cleanup RegCloseKey(subkey); end else error(make(, name: subkeyname, result: result)) end end method do-with-open-registry-subkey; define macro with-open-registry-path { with-open-registry-path (?subkey:name = ?key:expression, ?path:*) ?body:body end } => { do-with-open-registry-path(?key, list(?path), method (?subkey) ?body end) } end macro with-open-registry-path; define method do-with-open-registry-path (key, path, body :: ) => (#rest values) if (empty?(path)) body(key) else with-open-registry-subkey (subkey = key, first(path)) do-with-open-registry-path(subkey, rest(path), body) end end end method do-with-open-registry-path; /*---*** No longer used ... define method read-registry-string (key, name) => (value) let buffer-size :: = 2048; with-stack-structure (buffer :: , size: buffer-size) with-stack-structure (count :: ) pointer-value(count) := buffer-size; let (result, type) = RegQueryValueEx(key, name, null-pointer(), buffer, count); if (result ~= $ERROR-SUCCESS | type ~= $REG-SZ) error(make(, name: name, result: result)) else as(, buffer) end end end end method read-registry-string; */ /// Installation checking define generic check-help-system-installed (system :: false-or()) => (); define sealed method check-help-system-installed (system :: ) => () unless (help-system-installed?(system)) error(make(, system: system)) end end method check-help-system-installed; define sealed method check-help-system-installed (system == #f) => () error(make()) end method check-help-system-installed; /// See which /// describes how to check for the presence of HTML Help. define constant $HHCTRL-OCX = "{ADB880A6-D8FF-11CF-9377-00AA003B7A11}"; define sealed method help-system-installed? (system :: ) => (installed? :: ) block () with-open-registry-path (hh-key = $HKEY-CLASSES-ROOT, "CLSID", $HHCTRL-OCX) // If the key exists, HTMLHelp is installed... #t end; exception (condition :: ) #f end end method help-system-installed?; /// Help display /// 'do-display-help' methods define sealed method do-display-help (system :: , handle, path, id, data) => () WinHelp(handle, path, id, data) end method do-display-help; define sealed method do-display-help (system :: , handle, path, id, data) => () HtmlHelp(handle, path, id, data) end method do-display-help; /// Help path define sealed method help-path (system :: , command :: ) => (path :: ) "" end method help-path; define sealed method help-path (system :: , command :: ) => (path :: ) let path = as(, help-source-locator(help-source(command))); if (path-has-window?(path)) path else let window = help-path-window(system, command, path); if (window) concatenate(path, ">", window) else path end end end method help-path; define method path-has-window? (path :: ) => (window? :: ) member?('>', path); end method path-has-window?; /// Help path window define sealed method help-path-window (system :: , command :: , path :: ) => (window :: false-or()) help-secondary-window(command) end method help-path-window; /// Help ID (WinHelp) define sealed method help-id (system :: , command :: ) => (id :: ) $HELP-HELPONHELP end method help-id; define sealed method help-id (system :: , command :: ) => (id :: ) $HELP-FINDER end method help-id; define sealed method help-id (system :: , command :: ) => (id :: ) $HELP-INDEX end method help-id; define sealed method help-id (system :: , command :: ) => (id :: ) $HELP-CONTENTS end method help-id; define sealed method help-id (system :: , command :: ) => (id :: ) if (help-popup?(command)) $HELP-CONTEXTPOPUP else $HELP-CONTEXT end end method help-id; define sealed method help-id (system :: , command :: ) => (id :: ) $HELP-KEY end method help-id; define sealed method help-id (system :: , command :: ) => (id :: ) $HELP-COMMAND end method help-id; define sealed method help-id (system :: , command :: ) => (id :: ) $HELP-SETWINPOS end method help-id; define sealed method help-id (system :: , command :: ) => (id :: ) $HELP-QUIT end method help-id; /// Help ID (HtmlHelp) define sealed method help-id (system :: , command :: ) => (id :: ) $HH-DISPLAY-TOPIC end method help-id; define sealed method help-id (system :: , command :: ) => (id :: ) $HH-DISPLAY-TOPIC end method help-id; define sealed method help-id (system :: , command :: ) => (id :: ) $HH-DISPLAY-TOPIC end method help-id; define sealed method help-id (system :: , command :: ) => (id :: ) $HH-HELP-CONTEXT end method help-id; define sealed method help-id (system :: , command :: ) => (id :: ) $HH-ALINK-LOOKUP end method help-id; /// Help data define sealed method help-data (system :: , command :: ) => (data :: ) 0 end method help-data; define sealed method help-data (system :: , command :: ) => (data :: ) help-topic-id(command) end method help-data; define sealed method help-data (system :: , command :: ) => (data :: ) help-keyword(command) end method help-data; define sealed method help-data (system :: , command :: ) => (data :: ) help-macro(command) end method help-data; /*---*** This won't work yet! define sealed method help-data (system :: , command :: ) => (data :: ) let region = help-window-region(command); let (left, top, right, bottom) = box-edges(region); let info = make(, x: left, y: top, dx: right - left, dy: bottom - top, wMax: $SW-SHOWNA); info end method help-data; */