News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Contextual help project

Started by mywan, July 18, 2012, 07:31:02 AM

Previous topic - Next topic

mywan

I would also like to inquire about the copyright issues if I used some of the help file source code contained in \masm32\help\*.chm to create a more friendly help file structure, as described below. I also think a project like this is worthy of attention in the MASM SDK release.

The ASM/MASM documentation contains a lot of information, yet the process of finding any particular material can be laborious. Even if it wasn't spread around multiple help files they are not searchable. Neither are these series of help files very friendly to embedding in context sensitive help. Such as placing the cursor over "lfcnt" and pressing F1 to go directly to "hh.exe C:\masm32\help\masmlib.chm::/lfcnt.htm". Masmlib.chm tends to be one of the more friendly for this feature, but remains difficult to search and lacks cross referenced linking. Especially to other help files.

I would like to recreate most of these help files in a single well cross linked help system to make finding very specific information as simple as a single keystroke. Various index pages could then group these pages in logical content so that what was previously included as separate help files are categories in the content index. There wouldn't even be a limit on the number of index pages, or even index of index pages. In an uncompiled form it could also be hosted on the web and retain the same functionality for integration into text editors. The forum code tags could also auto-link these keywords to specific mnemonic help files.

Personally a well designed help system would save me more than 90% of my time on the learning curve, and greatly reduce development time forever. This means that every keyword, regardless of how basic or seemingly inane, should have its own page as <keyword>.htm, or <keyword>.chm in compiled form. These can also be back linked to any index page(s) that include them. Also any keywords mentioned in those pages should be crosslinked. This could be done wiki style and simply wrap the keywords in [[[<keyword>]]], such that a macro could expand them into links. It is after all the arcane-ish mnemonics of asm that makes it such an arcane beast for most people. This capacity would massively reduce the difficulties these mnemonics create for people.

The main idea is to provide full and complete integration of a singular MASM help file system into text editors, forum content, web searches, etc. How many others here would be interested in a help system of this nature? I think it would also generate a lot of new interest in the language itself.

jj2007

Here is one way to do it:
- decompile the whole stuff
- load the contents into an array
- do a full text search
- show a list of matches
- let the user click on it
- display the HTML

My first attempt shows that speedwise it can be done, here for MasmLib.chm:

31 ms for loading 201 files
Type a search term (Esc+Enter to exit): bitmap
Found in \masm32\help\MasmLib\BitmapFromFile.htm
Found in \masm32\help\MasmLib\BitmapFromMemory.htm
Found in \masm32\help\MasmLib\BitmapFromResource.htm
Found in \masm32\help\MasmLib\BmpButton.htm
Found in \masm32\help\MasmLib\DisplayBmp.htm
Found in \masm32\help\MasmLib\Image Functions.htm
Found in \masm32\help\MasmLib\Notes On Encryption.htm
Found in \masm32\help\MasmLib\VerticalTile.htm
Search took 1 ms

No problem to do that simultaneously for all 10 CHM files, provided there are no name conflicts. Of course, a fulltext search in the whole package would then cost 10 milliseconds instead of one ;-)

Source & exe attached.

mywan

Every one of those files found to contain "bitmap" are contained in one help file: masmlib.chm. I use a search app to search in files to find references in the compiled chm. To retrieve a page id I can directly access requires a more specialized search though, and the chm files don't even have a search function of their own. So decompiling is really the only way to get direct linking access to a found reference, because otherwise you don't know where in the help file to find the reference.

I think the entire help file system needs a complete rewrite. That would start with a huge list of individual pages and a template to provide a uniform layout.

Edit: Just read your source and realized masmlib.chm was the only one you decompiled. Even without decompiling these strings can be found as plain text. Though it still leaves the main problem unresolved.

hutch--

I don't like to rain on the parade but there is very good reason why the entire MASM32 SDK is a copyright work and will remain that way.

The help files are split up into categories so that the user does not have to climb through a mountain of other stuff to find what they need.

Try and find anything SDK in the current batch of Microsoft help files and you will well understand why I don't want a massive single file for all of the different forms of data.

mywan

I'll respect the copyrights :t It was pretty much to be expected anyway.
I suppose I can still refer to them by name. I am still going to develop my own context sensitive help system simply because I really can't be very productive otherwise. I'm literally spending several hours a day trying to dig out information that should be milliseconds away. Not everything there belongs in context sensitive help anyway.

Perhaps I will simply create a redirector a text editor can use to retrieve the proper command line to get the proper chm page, such as:
hh.exe "C:\masm32\help\hlhelp.chm::/Using%20.REPEAT%20Syntax.htm"
My Drawer program I intend to rewrite in asm is capable of this, if configured right, by default, and requires the user to actually posses the help files from the SDK. I can then include some html, perhaps compiled, files for keywords that are not included and part of the asm core mnemonics.

jj2007

Quote from: mywan on July 18, 2012, 09:05:35 AMEvery one of those files found to contain "bitmap" are contained in one help file: masmlib.chm.
...
Edit: Just read your source and realized masmlib.chm was the only one you decompiled. Even without decompiling these strings can be found as plain text. Though it still leaves the main problem unresolved.

@Even without decompiling these strings can be found as plain text
Yes indeed:
/bin2hex.htm..,..:./BinSearch.htm...:.c./BitmapFromFile.htm....6./BitmapFromMemory.htm....../BitmapFromResource.htm..../BmpButton.htm.../Boyer Moore Algorithms.htm..›../BrowseForFolder.htm...

Now go and find .gif, and you will realise why splitting is the better alternative.
For the time being, I just decompiled one of the chm files, but using all of them is just a question of three lines more or so.

Provided Hutch does not ban us from using the help folder as input to a software that displays them exactly as they would be displayed by the Windows HtmpHelp software :biggrin:

mywan

No banning please, at least not without a warning :greenclp: I promise to be very respectful and law abiding.

I've started down another road. I got a fresh copy of SciTE and started an asm configuration to include a copy of my Drawer program with. To avoid a bloated ini file I'm going to slightly modify a separate slimmer copy of my drawer program to offer a drawer of help option when F1 is pressed. Probably move my compile options menu there to. One of the options will be labeled "Help <keyword>" if one is available in the config file. This will simply open the existing chm needed to get help on that keyword. Requires a dictionary lookup for the proper locations though, hence the concerns about bloat in my windows version which already has a complete dictionary of filetypes. Other options can include local or internet resources, your own separate html or chm files, and including search strings to "Google <keyword>". Perhaps even a "find in file" to search which help files contain certain keywords. It all just depends on what you put in the config file.

Decompiling would certainly help make finding many help entries easier. However, I can paste text into the Drawer's configuration simply by right clicking the GUI. So by programmatically modifying the pasted string a bit I can just right click each page in the chm, select properties, copy the location string and paste it directly in the GUI. From there I get a prompt to accept the keyword the Drawer guessed at or modify it before accepting the entry. "bin2hex" stripped from "/bin2hex.htm" is a valid keyword, but "Using REPEAT Syntax" from "hlhelp.chm::/Using%20.REPEAT%20Syntax.htm" wouldn't be.

Anyway, that's the approach I have decided on.

jj2007

#7
I made some little tests, it seems to work most of the time but the GUI needs to be improved.
Attached version 0.9; version 1.0 should have the option to send a WM_COPYDATA message with the search string, in order to get true context help.

In the Find box, you can use combis à la CreateWindow+Date to limit the search.
Feedback welcome ;-)

The source is in *.asc format, readable in WordPad, MS Word or RichMasm.

P.S.: Works fine with Firefox, but there is a problem with MSIE: Explorer opens the html file in a new tab, not a window. I wonder if that can be programmatically changed...

dedndave

that is an option in IE settings
firefox has a similar setting

mywan

Nice start  :t
In all my browsers, when I redirected to another page after opening a previous page, it would simply close my browser (*Note: after switching to standard windows behavior), requiring reclicking to reopen the browser. Hence I lost a large group of tabs opened on various subjects I was studying when I tested your app. It also refused to open any browser maximized, even if that was the previous state of an already opened browser. My .htm files are not (by default) associated with any browser on my machine, rather to my own app (Drawer.exe) giving me a choice of any of my browsers, editors, etc., to open with. When I bypassed my Drawer app your app was highly inconsistent in what occurred from one click to the next. Sometimes a separate window, other times a new tab, other times closing browser it never opened to begin with while failing to open the selection I chose. This problem persisted for all browsers. This was due, apparently, to the default behavior of wanting to close previously opened instances of my browser without first knowing whether that previous instance was still open or not or whether it involved opening a new tab in an existing browser. My default open pointing at Drawer.exe actually completely tamed this behavior (if parent/child redirection wasn't specified), since it automatically closes after any choice is made removing the handle for your app to close.

If you stripped "xHelp/" from the full path and replaced the last instance of "/" with ".chm::/" and ShellExecute that string it will open the proper <filename>.chm location, at the page location, using the standard windows help file reader, hh.exe. The browser then wouldn't be an issue. You can also avoid ShellExecute by prepending the path string with "hh.exe ", but not really necessary. If the same .chm file is being redirected to another page, and a previous instance has been opened, then passing the Hinstance from the previous ShellExecute should allow you to avoid opening a separate instance of hh.exe, and wouldn't require that you exit the previous instance. For multiple <filename>.chm opened you would need an array of previous Hinstance's from ShellExecute with the previous <filename> associated with its own Hinstance. Even in the event that a separate instance of hh.exe is required, for a differing <filename>.chm, I would not want the previous instance automatically closed under any circumstances.

If you want to stick with opening the .htm files using the browser I would still absolutely avoid closing the previous instance, and merely let the new .htm open in another tab, or browser, per the users browser configuration. Firefox even has plugins to avoid multiple instances of the same page. There are also techniques for reusing the same tab in various browsers, but requires knowing which browser is being used, and in some cases using command line switches, activeX for IE, or possibly addons in FireFox. Too much trouble in general.

Personally I would go with the default hh.exe on the existing .chm files, to maintain consistency of expectations. Then use the Hinstance arg to avoid multiple windows without closing the previous window, but with checks to see whether that Hinstance still exist or not and/or corresponds to a differing <filename>.chm. I would never outright close a previous instance of anything under any circumstances. These things need fixed before a consistent operation can be achieved irrespective of the local user configuration. In my own configuration fixing these configuration dependencies for various standard user configurations would also greatly extend my configuration options using my Drawer app beyond simply taming the inconsistent behavior.

After writing a single app to completely replace all file associations in windows, with configurable per selection standard input/output redirection, I am exceptionally good at this stuff. Though I never used ShellExecute to accomplish it, since that defeated my goal of entirely replacing windows file association system and would create an infinite open with loop of choices, because Drawer.exe would then always point back to itself. Though this is allowed, per choice configuration, if you want to open a second set of choices for a given Drawer, and can chain parent/child redirection, if needed, through any arbitrary number of Drawer.exe instances.

jj2007

Thanks, mywan, that was a very detailed feedback :t

Re "I would never outright close a previous instance" - that is the standard behaviour of a browser when you click on a link: open a new page and close the old one simultaneously. This works in my configuration (where ShellExecute opens a new browser instance), but it fails with user settings where closing the old page closes a bunch of tabs (I hate tabbed browsing :bgrin:).

Note it should not close a page opened by the user for other purposes. My code checks the title tags inside the page to be opened, then, after ShellExecute, waits a while until that title appears online, saves the handle; in the next round, after opening a new page the old one gets closed. You may experience that one of your pages was closed simply because you were working with your own app and the exact same title... ;-)

Here is the snippet that performs these actions:

ShowHTML proc uses edi
LOCAL ct
   mov ecx, Matches[4*eax]    ; index passed in eax
   mov edi, hhTitle$(ecx)      ; load window title as identified via title tags
   invoke ShellExecute, 0, 0, Files$(ecx), 0, 0, 0   ; If lpFile specifies a document file, nShowCmd should be zero
   and ct, 0
   .Repeat
      inc ct
      invoke Sleep, 50
   .Until WinByTitle(edi) || ct>127   ; 50*127=6 seconds
   .if lastWin
      push eax
      .if rv(IsWindow, lastWin)
         invoke SendMessage, lastWin, WM_CLOSE, 0, 0
      .endif
      pop eax
      and lastWin, 0
   .endif
   .if ct<=127
      mov lastWin, eax
      invoke SetForegroundWindow, hMain
      invoke SetFocus, hListbox
   .endif
   ret
ShowHTML endp

I had already a version working with DDE and WWW_OpenURL, but you ran basically into the same problems. Another option would have been to open once an instance of FF/MSIE/xx, then send WM_DROPFILES to navigate to the next user choices. For reasons I have not fully understood, both MSIE and FF refuse to react to the WM_DROPFILES, so for the time being I am stuck with ShellExecute or. and this I may try soon, CreateProcess.

Re using HH.exe: I hate the interface :(

mywan

Oh, I see. There was no source code for me to know what was happening. I use tabbed browsing extensively. However, my FireFox does not close by default when the last tab is closed. This is the result of "invoke SendMessage, lastWin, WM_CLOSE, 0, 0" in your code. Another problem is the title match you use. I'll try to outline what's happening at the application level.

1) WM_CLOSE pertains to the application, not to any tab within the application.
2) The title of the application is dependent on which tab is active within the application.

This means that if I open a help file and remain on that tab, your program returns the proper title attribute. However, if I either switch tabs, or the local default behavior dictates that the new tab opens in the background, then your match by title will never match, even though the previous help file remains open. Your "invoke SendMessage, lastWin, WM_CLOSE, 0, 0" then closes ANY instance of ANY browser that intercepted your attempt at opening a new window.

For instance, you have a browser open with Hinstance=1. It's configured to open new pages from ShellExecute in new tabs. Therefore ShellExecute  will not return a new Hinstance, rather it simply attaches itself to Hinstance=1. lastWin then does not refer to a window you opened, but rather to the window that intercepted the window you attempted to open. The inverse problem exist when you attempt to use WinByTitle. The title a property of the tab, not the window, yet is passed to the window if and only if that tab is active. "invoke SendMessage, lastWin, WM_CLOSE, 0, 0" will never simply close a tab, it'll close the browser regardless of how many or few tabs are opened in it. It'll even close my browser in spite of the fact that my browser is configured to remain open even if the last tab in it is closed. So it's not just a default browser behavior closing the browser in this instance.

I'm about to create some test scripts to figure out the best way to deal with the no tabs choice you prefer. The problem is not with any given browser, but the differences in how different browsers handle it. Here's the test I think might work best:

1) ShellExecute normally returning Hwind1.
2) ShellExecute next window returning Hwind2.
3) If Hwind1 matches Hwind2 then tabs used.

There is likely a more elegant solution though, but you likely need to use the Hinstance argument to ShellExecute to take advantage of it.

An even better solution would be to avoid browsers altogether, using hh.exe with an Hinstance argument. Then you can easily just forward the location within "<filename>.chm::/<location>.htm" to a new <location>, and the user can also still use the back button to get back to the previous page. To handle multiple "<filename>.chm" you have a set of "key"="value" pairs where "key" is <filename> and "value" is an Hwind. Then the max number of windows you would open would not exceed the number of differing <filename>.chm files opened no matter how many different locations were opened within a given <filename>.chm.

jj2007

Quote.... then your match by title will never match, even though the previous help file remains open. Your "invoke SendMessage, lastWin, WM_CLOSE, 0, 0" then closes ANY instance of ANY browser that intercepted your attempt at opening a new window

lastWin is set only if WinByTitle returns a window with that title (as the name of the macro says). So no browser window will be closed arbitrarily.

The problem is tabs - if a new tab is added, and from then on the browser window has the HH title, then my proggie will indeed afterwards close that window including older tabs. MSIE and FF give a warning before closing multiple tabs, by the way, but you may have disabled that warning.

There are ways to close tabs (MSIE, FF) but they seem very clumsy. The FindExecutable road looks more promising.

mywan

Quote from: jj2007 on July 25, 2012, 07:24:04 PMlastWin is set only if WinByTitle returns a window with that title (as the name of the macro says). So no browser window will be closed arbitrarily.
Maybe I messed up the description a bit, but this was understood. However, if I open a window which is intercepted as a tab within an existing window, then if I click another selection in your app all my existing tabs, unrelated to your app, gets closed if and only if the tab your app last opened remains the active tab. Hence the inconsistent behavior.

mywan

Also, I just spotted the conditions under which your app closes the browser apparently without opening the selected file, leaving nothing opened at all. If you select the same choice twice then a new tab is added that is identical (including title) to the lastWin. WM_CLOSE then closes the window in which the new tab was just created because it's the same window, with the same title as lastWin.