home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-05-09 | 85.3 KB | 2,166 lines |
-
-
-
-
-
-
- WW WW WW PPPPPPPP JJ
- WW WW WW PP PP JJ
- WW WWWW WW PP PP JJ
- WW WW WW WW PPPPPPPP JJ
- WW WW WW WW PP JJ JJ
- WWWW WWWW PP JJ JJ
- WW WW PP JJJJJ
-
- ----------------------------------------------------------------
- The Windows Programmer's Journal Volume 01
- Copyright 1993 by Peter J. Davis Number 05
- and Mike Wallace May 93
- ----------------------------------------------------------------
- A monthly forum for novice-advanced programmers to share ideas and concepts
- about programming in the Windows (tm) environment. Each issue is uploaded
- to the info systems listed below on the first of the month, but made
- available at the convenience of the sysops, so allow for a couple of days.
-
- You can get in touch with the editors via Internet or Bitnet at:
-
- HJ647C at GWUVM.BITNET or HJ647C at GWUVM.GWU.EDU (Pete)
-
- CompuServe: 71141,2071 (Mike)
-
- GEnie: P.DAVIS5
-
- or you can send paper mail to:
-
- Windows Programmer's Journal
- 9436 Mirror Pond Dr.
- Fairfax, Va. 22032
-
- We can also be reached by phone at: (703) 503-3165.
-
- The WPJ BBS can be reached at: (703) 503-3021.
-
- The WPJ BBS is currently 2400 Baud (8N1). We'll be going to 14,400 in the
- near future, we hope.
-
-
-
-
-
-
-
-
- LEGAL STUFF
-
-
- - Microsoft, MS-DOS, Microsoft Windows, Windows NT, Windows for Workgroups,
- Windows for Pen Computing, Win32, and Win32S are registered trademarks of
- Microsoft Corporation.
-
- - Turbo Pascal for Windows, Turbo C++ for Windows, and Borland C++ for
- Windows are registered trademarks of Borland International.
-
- - WordPerfect is a registered trademark of WordPerfect Corporation.
-
- - Other trademarks mentioned herein are the property of their respective
- owners.
-
- - WPJ is available from the WINSDK, WINADV and MSWIN32 forums on
- CompuServe, and the IBMPC, WINDOWS and BORLAND forums on Genie. It is also
- available on America Online in the Programming library. On Internet, it's
- available on WSMR-SIMTEL20.ARMY.MIL and FTP.CICA.INDIANA.EDU. We upload it
- by the 1st of each month and it is usually available by the 3rd or 4th,
- depending on when the sysops receive it.
-
- - The Windows Programmer's Journal takes no responsibility for the content
- of the text within this document. All text is the property and
- responsibility of the individual authors. The Windows Programmer's Journal
- is solely a vehicle for allowing articles to be collected and distributed
- in a common and easy to share form.
-
- - No part of the Windows Programmer's Journal may be re-published or
- duplicated in part or whole, except in the complete and unmodified form of
- the Windows Programmer's Journal, without the express written permission of
- each individual author. The Windows Programmer's Journal may not be sold
- for profit without the express written permission of the Publishers, Peter
- Davis and Michael Wallace, and only then after they have obtained
- permission from the individual authors.
-
-
-
-
-
-
-
- Table of Contents
-
- Subject Page Author(s)
- -----------------------------------------------------------------
- WPJ.INI ....................................... 4 Pete Davis
-
- Beginner's Column ............................ 6 Dave Campbell
-
- Creating Windows Text File Editors ........... 15 Eric Grass
-
- Midlife Crisis: Windows at 32 ................ 20 Pete Davis
-
- WDASM - Review of a Windows Disassembler ..... 23 Pete Davis
-
- Hypertext, Sex and Winhelp ................... 25 Loewy Ron
-
- Enhancing the WINSTUB Module ................. 30 Rodney Brown
-
- Microsoft Developers Network .................. 33 Dave Campbell
-
- Getting in Touch with Us ..................... 35 Pete & Mike
-
- Last Page .................................... 36 Mike Wallace
-
-
- Windows Programmer's Journal Staff:
-
- Publishers ......................... Pete Davis and Mike Wallace
- Editor-in-Chief .................... Pete Davis
- Managing Editor .................... Mike Wallace
- Contributing Editor ................ Dave Campbell
-
- Contributing Writer ................ Dave Campbell
- Contributing Writer ................ Eric Grass
- Contributing Writer ................ Loewy Ron
- Contributing Writer ................ Rodney Brown
-
-
-
-
-
-
-
-
-
- WPJ.INI
- By Pete Davis
-
- Another month, another issue. Wow, up to number 5. I guess I say
- something along those lines every month, but the response just keeps
- getting better and better and I guess I'm just surprised that we're
- actually getting these things out every month.
-
- I received some questions from our readers about some of the articles
- in the magazine. Their concern was that we seem to try to fit a lot of
- information into short articles and that sometimes it's not in-depth
- enough. Well, to those who think that, let me explain. When we write
- articles for the magazine (and I can only speak for me and Mike), we do try
- to fit the information into rather short articles and we don't go into a
- great deal of depth a lot of the time. The reason for this is that Mike and
- I both work full-time. On top of that, we do several other things outside
- of work and the magazine. Writing in-depth articles means lots of research
- and time. We can't afford that kind of time, unfortunately. It is my hope
- that, someday, I'll have more time to spend writing more in-depth articles.
- Until that day, we can only offer what we can. We try to give as much
- information as is applicable and when a readers asks us to clarify
- something, we try our best to do that. If you ever feel like an article
- needs clarification, let us know and we'll either do that directly, via
- mail, or we'll do an addendum in a future issue.
-
- Next subject: Me! After the last paragraph, now's the time to spill
- the beans about why things are going to be changing a bit for me. I am
- going to be writing a book for Addison-Wesley publishing on Windows
- programming (NT and the 32-bit stuff). Unlike the writing I do in the
- magazine, the stuff in the book will be the kind of writing that requires
- months of research and lots of checking and double-checking (like I said,
- we don't have the time to do that for the magazine). Anyway, the book is on
- Win32 programming and it will be in the Andrew Schulman Programming Series.
- I have to say I'm awfully excited about the whole thing and I'm really
- looking forward to it. I couldn't possibly thank Andrew Schulman enough for
- the chance he's giving me. So, that's what's up with me. What does this
- mean? Well, for one thing, all of my articles are going to be on Win32
- programming for the next few months. I've got to do this just to help keep
- my mind trained on the topic, if nothing else. Also, I might not be able to
- do quite as much writing for the magazine as I'd like.
-
- Also, nothing firm here, but it looks like I might be doing an article
- with Ron Burk of Windows/DOS Developer's Journal. This, like the book, is a
- sort of first for me and I'm really excited about that. I'll give more info
- on this next month, when I know more.
-
- So, that's what's going on with me. After the book is done, perhaps
- I'll start writing about things other than Win32, but hopefully, by then,
- EVERYONE will be programming in Win32. It could happen! By the way, I
- expect each and every one of you to buy my book when it's done.
-
- We've got an article by a guy named Eric Grass in this issue. I've got
-
- - 4 -
-
-
-
-
-
-
- to talk about how I met Eric for a minute. Eric writes a shareware Windows
- disassembler called WDASM. It's a really nice product and I felt I had to
- review it in this issue. Anyway, when I registered WDASM (registration is a
- mere $10, I felt obligated to pay $20, because it's worth at least that) I
- sent in some suggestions for expanding WDASM. In our ensuing e-mail
- volleys, I asked Eric if he'd write an article for the magazine. Anyway,
- read his article on writing an editor in Windows and read my review of his
- disassembler and then get his disassembler! You'll thank me for
- recommending it and you'll thank Eric for writing it.
-
- The last thing I want to talk about is submissions. The number of
- article submissions seems to be on the decline. Unless we start getting
- more articles, this magazine might have to become a bi-monthly affair. I
- know that I won't have as much time as I'd like to do all the work required
- to keep it monthly. Mike, I'm sure, will do his best to write for it, but
- unless we get more submissions, I can't see us staying at a monthly pace.
- The final decision will have to be Mike's since he is going to be stuck
- with doing most of the work for the next few months.
-
- Remember, we don't do this just for us, we do it for you, the readers.
- If you've felt like you've gotten something out of the magazine, try to
- return the favor and give a little of your time to help keep it a monthly
- magazine. I know a lot of you want to see it stay monthly. I know I do.
- Writing an article can take as little as a few hours. Most of you have
- something you've learned somewhere that could help a lot of other people
- out. We're counting on you to share that information.
-
- Until next month, peace.
-
- P.S. I'm writing this the day of the release of this issue to apologize to
- our readers. Things have been incredibly hectic lately for me because of
- the book and now this possible article with Ron Burk. The timing on the
- magazine was just off a bit. Mike has also been really busy, so neither of
- us had the time this month that we'd normally like to put into the
- magazine. Please accept our apologies.
-
-
-
-
-
-
-
-
-
- - 5 -
-
-
-
-
-
- Beginner's Column
- By Dave Campbell
-
- Don't you just hate it when you look at a ton of Windows Applications, and
- they all look alike, and they all do the same things in response to the
- same keystrokes, and YOU DON'T HAVE ANY IDEA HOW THEY DID IT? That's how I
- was about file open dialog boxes. I knew I could do it, I just didn't want
- to. Yeah, right. So, this month, I am going to give one possible example of
- a way to do one (the hard way), and along the way, we'll learn some things
- about list boxes.
-
- First I want to pass along a few things. The code out of which I stripped
- the file open dialog box uses the Borland classes for the dialog box
- displays. I have been trying my best to stay away from any compiler-
- particular code for my articles. Consequently, I was mildly taken aback
- when my dialog box came up with the Borland background in place. How could
- this be? Well...I run a background menu processor that is in Beta at this
- time, (waiting on documentation), and it uses the Borland classes. Since
- that is all instantiated in memory, when our new Hello program came in, and
- tried using the Borland calls, it all worked. Basically I got lucky.
- Usually it works the other way. You forget to put it in, and then try to
- call it.
-
- My reason for mentioning all this is: if you are in a debug cycle, and
- going into and out of Windows relatively often, remember that if you hold a
- shift key down during Windows start-up, you won't get your "run=", "load=",
- or "Startup" files. All you'll get is Windows, and you can then make sure
- that if you need a DLL, you load it yourself.
-
- The second thing is to be sure to read my review of the Microsoft
- Developer's Network program in this issue. This is like the mother-load of
- Windows help.
-
- Now on to a file open box. What I want to do is display a dialog box that
- has a file spec in it, for example "*.EXE", and various areas to display
- paths, and file names, and directory names, and a way to select a file or
- quit. That will just about solve all the requirements (not counting drag-
- and -drop). How this is implemented in my other application is: in a dialog
- box is a text box requesting a file name. If OK is selected, and the file
- name is NULL, then I pop up the file open box. In Hello, we already have a
- File Open menu choice, and are going to use it.
-
- First let me display what this dlg code looks like:
-
- From Hello.DLG
-
-
- FILEOPEN DIALOG 80, 60, 148, 101
- STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION
- CAPTION "Find File"
- FONT 8, "Helv"
- BEGIN
-
- - 6 -
-
-
-
-
-
- CONTROL "File name:", -1, "STATIC"
- SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 2, 4, 144, 10
- EDITTEXT IDD_FNAME, 2, 14, 144, 12, ES_AUTOHSCROLL
- CONTROL "Files in", -1, "STATIC"
- SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 2, 30, 38, 12
- CONTROL "", IDD_FPATH, "STATIC"
- SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 48, 30, 98, 12
- LISTBOX IDD_FLIST, 2, 43, 82, 58, WS_TABSTOP | WS_VSCROLL
- CONTROL "Select", IDOK, "BUTTON",
- BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP,
- 90, 52, 56, 14
- CONTROL "Cancel", IDCANCEL, "BUTTON", WS_GROUP, 90, 76, 56, 14
-
- The first new item to us is the EDITTEXT line. EDITTEXT creates a child
- window of the EDIT class which gives us a place to allow a user to type
- some text for us to capture. The user may move from edit box to edit box,
- and get the focus by clicking the mouse inside it, or we as developers can
- place the user there. In our example, we will place the user in the box.
- When the user sees a flashing prompt in the text box, it is safe to type
- and edit the typing. As with any Windows text box, the mouse may be used,
- along with the backspace key to provide editing features. All this for one
- line in the dialog box!! Isn't it simple to program in Windows?
-
- As with most Windows features, the parameters are many. The only one used
- in this example is ES_AUTOHSCROLL. This does exactly what it sounds like.
- If the text scrolls beyond the right-hand margin during input, the box will
- scroll with it. The default options are: ES_LEFT | WS_BORDER | WS_TABSTOP.
-
-
- LISTBOX
-
-
- The next new control is LISTBOX. A listbox is a child window containing a
- list of character strings, allowing the user to scroll and make selections.
- When a string is selected with a mouse click, the string is highlighted,
- and a message sent to the parent window. I have chosen to allow a vertical
- scrollbar on our listbox, and adding it to the style list is all it takes
- to do that.
-
- Invoking the dialog box is the easy part. In place of the message handling
- of last month in response to the File Open menu, we'll do:
-
- if (DoFileOpenDlg(hInst, hWnd, &of))
- lstrcpy(OutMsg, (char far *)pof->szPathName);
-
- Notice the file open dialog box is embedded in an if statement. In this
- circumstance, we are going to check the return value of the dialog box
- ourselves, and if we return TRUE, we know we have a good value for the
- file, and we display it in the same manner the other data is displayed from
- last month.
-
- Don't be confused as to the parameters passed in this statement.
-
- - 7 -
-
-
-
-
-
-
- 'DoFileOpenDlg ' is NOT a dialog box call. This is simply a launcher for
- the dialog box that we are setting up with some parameters, and from which
- we are going to get a return value.
-
- The real dialog box code inside DoFileOpenDlg looks like our dialog boxes
- from the last two issues:
-
- lpfnFileOpenDlgProc = MakeProcInstance((FARPROC)FileOpenDlgProc, hInst);
- iReturn = DialogBox(hInst, "FileOpen", hWnd, lpfnFileOpenDlgProc);
- FreeProcInstance(lpfnFileOpenDlgProc);
-
- The only difference here is picking up the return value from 'DialogBox'.
-
-
- OFSTRUCT
-
-
- At this point, however, I need to discuss one of the parameters to
- DoFileOpenDlg, and that is &of. of is listed way up in the beginning of
- Hello.C as being of type OFSTRUCT. OFSTRUCT is defined as:
-
- typedef struct tagOFSTRUCT { /* of */
- BYTE cBytes;
- BYTE fFixedDisk;
- UINT nErrCode;
- BYTE reserved[4];
- BYTE szPathName[128];
- } OFSTRUCT;
-
- This structure is the result of opening a file. As you can see, this
- structure tells us if the file is on a hard disk, if there was an error
- opening the file, and the complete pathspec for the file.
-
-
- DoFileOpenDlg
-
-
- Inside DoFileOpenDlg, a few global variables are set:
-
- pof = pofIn;
- lstrcpy(szFileSpec, "*.EXE");
- lstrcpy(szDefExt, "EXE");
- wFileAttr = DDL_DRIVES | DDL_DIRECTORY;
-
- 1) 'pof' is defined above with of as an LPOFSTRUCT
- (or Long Pointer to an OFSTRUCT).
- 2) *.EXE is picked as the default filespec (to begin with).
- 3) the default file extension of EXE is set.
- 4) the global file attribute variable, wFileAttr is set to
- DDL_DRIVES | DDL_DIRECTORY which declares that we are interested in
- files that are drive or directory names (to begin with).
-
-
- - 8 -
-
-
-
-
-
-
- Windows message Loop
-
-
- With all that out of the way, let's start with the WM_INITDIALOG case:
-
- case WM_INITDIALOG :
- SendDlgItemMessage(hDlg, IDD_FNAME, EM_LIMITTEXT, 80, 0L);
- DlgDirList(hDlg, szFileSpec, IDD_FLIST, IDD_FPATH, wFileAttr);
- SetDlgItemText(hDlg, IDD_FNAME, szFileSpec);
- return TRUE;
-
- Remember, this is the first thing that happens to the dialog box. Right
- away we jump into three commands that haven't been discussed before. Two
- are related, and I'll discuss them first:
-
- SendDlgItemMessage(hDlg, IDD_FNAME, EM_LIMITTEXT, 80, 0L);
-
- SendDlgItemMessage sends a message to a specific control in a dialog box,
- identified by, in this case, the IDD_FNAME control ID.
- SendDlgItemMessage does not return until the message has been
- processed. 'EM_LIMITTEXT, 80' sets the control up for receiving up to 80
- characters of text, and the 0L is an empty lParam value for the
- call. The bottom line is that this call did one thing: it set the
- length of the text box to be 80 characters.
-
- SetDlgItemText(hDlg, IDD_FNAME, szFileSpec);
-
- SetDlgItemText sets the title or text of a control in a dialog box. In our
- case, it is the same control as the last call, and this time we send it the
- "*.EXE" default file spec from above.
-
- Now the fun one:
-
- DlgDirList(hDlg, szFileSpec, IDD_FLIST, IDD_FPATH, wFileAttr);
-
- DlgDirList fills a list box with a file or directory listing. What gets
- displayed is controlled by the parameters passed in: szFileSpec and
- wFileAttr, both discussed above. IDD_FLIST is the ID of the listbox control
- itself, and IDD_FPATH is the ID of a static control that will be used by
- Windows to display the current drive and directory. If this is 0, no
- display will be done.
-
- If the filespec is a directory name (or a null string), the string will be
- changed to "*.*". After the box is filled, the filespec is stripped of any
- drive or path information.
-
- At this point, the dialog box is up, and the listbox is full of file
- listings, and the user can move around in there just like any other Windows
- file open box.
-
-
- Mouse Messages
-
- - 9 -
-
-
-
-
-
-
-
-
- This brings us to the fun part of the dialog box code. Of course we want
- OUR dialog box to be just like everyone elses, so double clicks select,
- etc. But then we have to write that code! So here goes(taken liberally from
- Charles Petzold's Great book "Programming Windows"):
-
- case WM_COMMAND :
- switch (wParam)
- {
- case IDD_FLIST :
- switch (HIWORD(Lparam))
- {
- case LBN_SELCHANGE :
- ----code below----
- return TRUE;
-
- case LBN_DBLCLK :
- ----code below----
- return TRUE;
- }
- break;
-
- WM_COMMAND is the workhorse message of Windows. A window receives a
- WM_COMMAND just about anytime the user does something. If the user selects
- a menu item, or a child control sends a note back to 'mom'. In our case, we
- are concerned about messages coming from the list box, so we look for
- IDD_FLIST, our ID for the listbox.
-
- If we receive a message from IDD_FLIST, we are likely to get two things: 1)
- we select an item by single-clicking it with the mouse, or 2) we
- double-click something to not only select it, but SELECT it (in other
- words, do something with it now, I only have enough time to deal with the
- mouse).
-
- This kind of information is passed to the window in the high-order word of
- Lparam. This is officially called 'wNotifyCode'. If the message is from a
- control, this will be a Windows-type message. If the message is from an
- accelerator, wNotifyCode is 1, and if from a menu, it is 0.
-
- This is why there is a secondary switch case inside the outer one. Now we
- have to deal with what is going on with the listbox. Consequently, we have
- our two messages: 1) LBN_SELCHANGE, and 2) LBN_DBLCLK.
-
-
- LBN_SELCHANGE
-
-
- if (DlgDirSelect(hDlg, szFileName, IDD_FLIST))
- lstrcat(szFileName, szFileSpec);
- SetDlgItemText(Hdlg, IDD_FNAME, szFileName);
-
-
- - 10 -
-
-
-
-
-
-
- DlgDirSelect assumes that the listbox identified with the ID (in our case
- IDD_FLIST), has been filled with a DlgDirList function (good thing we did
- that), and returns us the selection currently selected. The second
- parameter should be a pointer to a 128-byte character string (to be fer
- sure, fer sure). By the way, I will change this to 128 bytes before anybody
- else sees it, now that I have looked that one up.
-
- The function returns non-zero if successful, zero otherwise. And, the
- string stuffed into, in our case szFileName, will be a drive letter, or a
- directory name, with any brackets, etc. removed. The function appends a ':'
- to a drive letter and a '\' to a subdirectory name.
-
- So, when we start out, szFileSpec is *.EXE, and if we select [-c-] for
- example, in this loop we concat c: with *.EXE, and send C:*.EXE to
- IDD_FNAME with the SetDltItemText call that is next. Notice this doesn't do
- anything more than save the names in the global strings, and display them
- in the text box. However:
-
-
- LBN_DBLCLK
-
-
- if (DlgDirSelect(hDlg, szFileName, IDD_FLIST))
- {
- lstrcat(szFileName, szFileSpec);
- DlgDirList(hDlg, szFileName, IDD_FLIST, IDD_FPATH, wFileAttr);
- SetDlgItemText(hDlg, IDD_FNAME, szFileSpec);
- }
- else
- {
- SetDlgItemText(hDlg, IDD_FNAME, szFileName);
- SendMessage(hDlg, WM_COMMAND, IDOK, 0L);
- }
-
- The first if message is identical. If we get a good return from
- DlgDirSelect, concat the name, and then...oh yeah, now we need to do
- something, since we double clicked!! Ok, so what would we like it to do?
- Most of us would agree that leaving the szFileSpec alone, *.EXE, and
- changing to the drive or directory, in addition to changing the text in
- IDD_FNAME would be nice.
-
- So that's what we do. The second half is identical to what we did in the
- LBN_SELCHANGE message, just display, but the first part is handled by re-
- executing the DlgDirList call, only passing it the new szFileName we
- concatenated.
-
- This is all well and good if we double click on a directory or a drive
- letter, but what if we double click a file name? That's what the else case
- is for. Remember above I said that a good return from DlgDirSelect gave us
- a drive or subdirectory name? Well, a FALSE return gives us a filename. So,
- if we take the 'else' clause, for FALSE, we know that szFileName is the
- filename that the user double-clicked, and we stuff that into the IDD_FNAME
-
- - 11 -
-
-
-
-
-
-
- box, followed by sending OURSELVES (!!) an IDOK message.
-
-
- IDD_FNAME
-
-
- IDD_FNAME is also user-modifiable, so if the user types something in there,
- we want to know what is going on, so we handle calls originated from there:
-
- if (HIWORD(lParam) == EN_CHANGE)
- EnableWindow(GetDlgItem(hDlg, IDOK),
- (BOOL) SendMessage(LOWORD(lParam), WM_GETTEXTLENGTH, 0, 0L));
-
- Remember above in talking about messages from child controls, how the
- message is passed in the high-order word of lParam?, well here we go again.
- And, this time we are looking for a changed text box, or EN_CHANGE. If this
- is the case, Windows has already updated the text in the box.
-
- The EnableWindow line is a combination of three windows functions, and as
- such is extremely messy. The EnableWindow call really looks like:
-
- EnableWindow(hwnd, fEnable),
-
- where hwnd is the handle of the window to be enabled or disabled according
- to the Boolean equivalence of fEnable (ie, TRUE/FALSE).
-
- The window we want to enable/disable is the one whose handle is returned
- from GetDlgItem(hDlg, IDOK). hDlg is the handle to our dialog box, so
- that's easy, but how about the IDOK? Go back to the .DLG file and look at
- what happens if the user clicks the button "Select". The button returns
- IDOK. It works the same as an OK button, but has Select written on it
- instead. That is the window whose handle we are going after for the
- EnableWindow call.
-
- Now, what are we going to do with it?
-
- SendMessage(LOWORD(lParam), WM_GETTEXTLENGTH, 0, 0L)
-
- SendMessage is going to send the command WM_GETTEXTLENGTH to the window
- whose handle is the LOWORD of lParam. The high word was discussed above
- (twice) as the message sent, the low word is the handle of the control
- sending the message. Therefore, SendMessage is going to send a
- WM_GETTEXTLENGTH command to the IDD_FNAME box which will return the length,
- in bytes of the text in IDD_FNAME.
-
- Whew...let's see now: if we square the result, oops wrong article.
-
- But, it's almost that complicated. The bottom line is we are going to send
- an EnableWindow message to the Select button only if there is text in the
- IDD_FNAME box after it has been modified. This will end up working its way
- back to us as an IDOK, and will select the filename.
-
-
- - 12 -
-
-
-
-
-
-
- Now wasn't that fun?
-
-
- IDOK
-
-
- The IDOK message handler does the following:
-
- 1) Gets the filename from IDD_FNAME. We put it there, remember?
- 2) If szFileName ends in ':' or '\', append szFileSpec to
- szFileName.
- 3) If szFileName ends in a wildcard, execute DlgDirList with the new
- szFileName, and clean up the displays appropriately:
-
- a) copy szFileName to szFileSpec (since it had a wildcard anyway)
- b) write the new szFileSpec into IDD_FNAME
- c) if DlgDirList fails, beep to the user
- d) exit the message loop
-
- 4) If szFileName does not end in a wild-card, concat '\szFileSpec' onto
- szFileName, and re-execute DlgDirList with this new filename.
-
- 5) If DlgDirList finishes successfully, displays are updated, and we
- exit the message loop
-
- 6) If DlgDirList does not finish successfully, it means that the
- szFileName did not contain a drive\directory structure. So, it is
- probably a file name. This is our back-door, so to speak, to get the
- file name.
-
- 7) If we've come this far, we assume we have a full file-spec on our
- hands.
-
- 8) We take two tries at opening the file with OF_EXIST set. This will
- open and close the file just to check for existence of the file.
- The OF_READ for read-only was thrown in as insurance. The first try
- is with the name we have already. If that fails, we try with the
- default file extension on it, just in case. If both fail, we beep to
- the user and exit.
-
- 9) If we are successful in opening and closing the file, we have
- finished what we set out to do, and exit the dialog box. The
- filename is copied from the OFSTRUCT way back up where the
- adventure started with File/Open, and at the bottom of that loop,
- we print execute a MessageBox call with the filename as the child
- window text.
-
- I did gloss over one of Petzold's routines, and neglected to mention a
- couple of other things. Petzold used an internal routine called 'lstrchr'
- to find the existence of a character in a string. That's how we decided if
- there was a wild-card in the filename. He also used lstrcat and
- lstrcpy to let Windows handle the far pointer manipulation without
-
- - 13 -
-
-
-
-
-
-
- messing up.
-
- I know I've gone over the last part pretty quickly, but I tried to cover it
- completely. It's mostly 'C' code, and doesn't have a lot of Windows-
- particular stuff in it. I think I'd rather spend my time explaining the
- hairy Windows parts than mess so much with the 'C' parts.
-
-
- EndDialog
-
-
- That's it for now. As I have said, Please hang in there. If you are beyond
- the scope of this article, stick with me we are going to go places
- together. If you are way beyond this, write us an article. If you are
- bogged down, just compile it, and stare at the source. If you want help
- with something, send me a note.
-
- Next month, unless I get mail not in favor of it, we're going to put this
- month's code into a DLL so we can use it later. Feel free to contact me in
- any of the ways below. Thanks to those of you that have e-mailed me
- questions, keep them coming. Notice that I now have an internet address,
- to make it real easy to get in touch with me. I want to rat out the things
- other people are having questions about, not just what I think people want
- to hear.
-
- Dave Campbell
- WynApse PO Box 86247 Phoenix, AZ 85080-6247 (602)863-0411
- wynapse@indirect.com
- CIS: 72251, 445
- Phoenix ACM BBS (602) 970-0474 - WynApse SoftWare forum
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 14 -
-
-
-
-
-
-
- Programming Techniques For Creating Windows Text File Editors
- by Eric Grass
-
- This article discusses advanced programming techniques for creating
- text editors under Windows. The Edit window class will not be implemented
- in order to focus on how to create more advanced types of editors. We will
- thus be creating a text editor "from scratch", so to speak. As an example,
- the source code for a simple text editor named EditPro has been included
- with this issue of WPJ. EditPro is a smaller version of another editor
- named KeyPro which I wrote recently.
-
- EditPro simply loads and displays files using the Windows system font
- and does paging. This article covers these aspects of file editing, and
- then offers some tips on using the system caret.
-
- The fundamental portions of the program (i.e., the WinMain function,
- etc.) were created using QuickCase:W for Windows. The source code contains
- some in-line assembly language code in order to improve the program's
- execution time in certain places where it is appropriate.
-
- I compiled EditPro using QuickC for Windows. You may or may not get
- the following warnings when you compile:
-
- qcw /AS /G2w /Zp /W3 /D_WINDOWS /Gi /Od /Zi -f A:\EDITPRO.C
- A:\EDITPRO.C(190) : warning C4059: segment lost in conversion
- A:\EDITPRO.C(191) : warning C4059: segment lost in conversion
- A:\EDITPRO.C(195) : warning C4059: segment lost in conversion
- A:\EDITPRO.C(198) : warning C4059: segment lost in conversion
- A:\EDITPRO.C(200) : warning C4059: segment lost in conversion
- A:\EDITPRO.C(208) : warning C4059: segment lost in conversion
- A:\EDITPRO.C(254) : warning C4059: segment lost in conversion
- linkw /ST:5120 /A:16 /CO @$$QCW$$.CRF
- rcw -t EDITPRO.RES EDITPRO.EXE
- cvpackw EDITPRO.EXE
- EDITPRO.EXE - 0 error(s), 7 warning(s)
-
- These warnings can be ignored. This occurs because the code extracts the
- offset from global memory pointers. I tried to figure out a way to use
- casting to avoid these warnings, but I couldn't.
- The source code includes some helper routines (or, file routines) in a
- file named filerout.c. The procedure FileRoutine() merely invokes the Open
- dialog box and retrieves a file path name. The second two routines are
- used to merely display message boxes.
-
- Storing Text
-
- The most important step in designing a file editor is designing the
- data structure for storing the lines of text of the file in memory.
- EditPro uses the following Line structure to store a single line of
- text:
- _
- | ...........22222222222222
-
- - 15 -
-
-
-
-
-
-
- OFFSET:------| 111111111122...........44444444555555
- |_ 0123456789012345678901...........23456789012345
- \/\/|\________________________________________/
- \ \ \ \
- \ \ \ \__Text
- \ \ \________(BYTE) total number of bytes in line structure
- \ \_________(WORD) memory handle of next line
- \__________(WORD) memory handle of previous line
-
-
- For each line we allocate between 5 and 256 bytes of global memory.
- If a line contains just N characters, then we only have to allocate N+5
- bytes. Allocating more memory than this would be a waste of memory. Thus,
- this type of structure allows at most 251 characters per line. The first
- two bytes, bytes 0 and 1, store the memory handle to the previous line
- proceeding the current line. The next two bytes, bytes 2 and 3, store the
- memory handle to the next line following the current line. Thus, we may
- construct a linked list of lines. The byte at offset 4 stores the total
- number of bytes constituting the memory block minus 1, and must therefore
- be a value between 4 and 255. Finally, bytes 5 through 255 are used to
- store the actual text constituting the line. The primary motivation for
- selecting the value 256 as the maximum size of the Line Structure is so
- that we can store the size of the structure (at byte 4) using just one
- byte.
-
- The file loading procedure can be expressed in pseudocode as follows:
-
-
- .
- .
- .
- Open the specified file;
- if( size of file < MAXFILEBUFF)
- Allocate temporary file buffer of size = size of file;
- else
- Allocate a temporary file buffer of size = MAXFILEBUFF;
- Allocate and Lock a new Line Structure of size = 256 bytes;
- Set Line Structure pointer to 0;
- while( End of File not reached)
- { Read portion of file into temporary file buffer;
- Set file buffer pointer to 0;
- while( Not at the end of the temporary file buffer)
- { if( file buffer pointer points to Newline character)
- { Allocate and Lock new Line Structure of size 256 bytes;
-
-
- Store the handle of the previous Line in the new Line
- Structure;
-
- Reallocate the size of the previous Line Structure to
- N+5 bytes;
-
-
- - 16 -
-
-
-
-
-
-
- Store the value N+4 at offset 4 in previous Line
- Structure;
-
- Unlock the previous Line Structure;
- }
- else
- { Copy the character pointed to by file buffer pointer to
- the Line Buffer;
-
- Increment the Line Buffer Pointer and the file buffer
- pointer;
- }
- }
- }
- Reallocate the size of the new Line structure to N+5 bytes;
- Store the size of the new Line Structure (i.e., N+4) at offset 4 in
- Line Structure;
- Unlock the new Line Structure;
- .
- .
- .
-
-
- The corresponding source code is located in the file named editpro.c.
- For EditPro, the value of MAXFILEBUFF is 0x00003FFFL bytes. This value can
- be made larger, if desired, to reduce the amount of disk reads required.
- If you look at the source code, you'll notice that when line number 32,767
- (7FFFH) is reached, EditPro displays a message notifying that the file will
- be truncated at that point, because of Windows' scroll bar
- range limit of 32,767. Also, when the user exits EditPro or selects Close
- from the menu, we must free the memory associated with all of the Line
- structures.
-
- Painting the Screen
-
- Painting the screen involves drawing only a portion of the text in the
- window. Which portion is a drawn depends on the line which the user has
- scrolled to and the invalidated rectangle specified by the PAINTSTRUCT
- structure that is filled out by the BeginPaint() function. To output the
- appropriate text one can use either the TextOut() or TabbedTextOut()
- function. EditPro uses the TabbedTextOut() function since it must expand
- the tabs in the file. One thing to remember about the TabbedTextOut()
- function is that it uses up a lot of CPU cycles whenever it is called.
- Therefore, you'll want to call this function as few times as possible
- whenever you're painting/repainting the screen. To keep track of the line
- to which the user has scrolled, we use a global variable, hCurrentLine,
- which holds the memory handle of the Line Structure of the line to which
- the user has scrolled. This value is set to the handle of the very first
- line when the file is first opened.
-
- The variable xoffset holds a non-positive value between 0 and -32,767
- which determines the text's displacement relative to the x-axis. This is
-
- - 17 -
-
-
-
-
-
-
- used in case the window has been horizontally scrolled by the user toward
- the right. xoffset is changed (decreased) whenever the user scrolls the
- screen horizontally, and the window must be updated accordingly.
-
- You'll notice that the text is displayed in the system font. This
- choice is purely arbitrary and can actually be any font that you want.
-
- Paging The Screen
-
- To page up/down, whenever the user clicks the vertical scroll bar, we
- merely "chase pointers" either backwards or forwards from our current
- position in the file until we reach the line that is at the bottom of the
- screen or at the top of the screen. We use the client rectangle to help us
- find the desired line. Every time we chase a pointer to the next
- consecutive line, we simply add the text height of that line to our
- variable, CurrentLine, which initially is set to zero. When CurrentLine is
- greater than the client rectangle's top/bottom, then we know we've found
- the right line.
-
- For horizontal paging, we merely change increment/decrement the
- xoffset variable and scroll the client window in the proper direction.
-
- Tips On Using The Caret
-
- The topics covered thus far provide a minimum foundation for creating
- editors. The resulting editor merely loads and displays files. What is
- missing is the implemention of the system caret into the program and some
- basic editing operations, which are topics I cannot cover in depth in this
- article due to a limited amount of time. However, just to get you started
- on using the caret, here's a few tips:
-
- - The caret is a shared resource. You must create the caret whenever
- you're window receives the input focus, and destroy the caret whenever
- your window loses input focus (which is signaled by the WM_SETFOCUS
- and WM_KILLFOCUS messages).
-
- - It is important to hide the caret before erasing the window's
- background. The WM_ERASEBKGND message signals when the background must
- be repainted. By default (via the DefWindowProc() function) Windows
- paints the background. If you don't do this, what happens is that
- occasionally the caret will leave an "imprint" on the window. That is,
- you'll have two carets appearing on the screen, except only one of
- them will actually be the caret and the other will be just an image of
- the caret.
-
- The following code is an example of how to hide the caret before the
- background is repainted:
-
- switch( wParam)
- { .
- .
- .
-
- - 18 -
-
-
-
-
-
-
- case WM_ERASEBKGND:
- // if window has input focus, hide the caret before
- // erasing...
- if( hWnd == GetFocus())
- { HideCaret( hWnd);
- dwTemp = DefWindowProc(hWnd, Message, wParam,
- lParam);
- ShowCaret( hWnd);
- return dwTemp;
- }
- else goto DEFAULTACTION;
- case WM_PAINT:
- .
- .
- .
- default:
- DEFAULTACTION:
- /* For any message for which you don't specifically provide a */ /*
- service routine, you should return the message to Windows */ /* for
- default message processing. */
- return DefWindowProc(hWnd, Message, wParam, lParam);
- }
- return 0L;
-
- - The GetTextExtent() function must be used to calculate the new
- position of the caret whenever the user moves the caret.
- - It's important to save the position of the caret before losing input
- focus in order to know where to display the caret again after
- regaining input focus.
-
-
- Closing Remarks
-
- If time permits, I may write another article in the future which
- covers the caret and the implementation of basic editing operations.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 19 -
-
-
-
-
-
-
- Midlife Crisis: Windows at 32
- By Pete Davis
-
- I decided I needed to back-track this month. Last month's article was
- done out of a sheer need for me to know about threads and synchronization
- without much thought given to you, the reader. I apologize. I'm going to do
- my best to start from the beginning on this Win32 stuff and explain the
- different areas of Win32 programming. This month, in particular, I'm going
- to discuss the differences between the different environments, Win32 for
- Windows 3.1, 'Chicago', and NT). This difference is particularly important
- right now as far as the difference between NT and Windows 3.1 when doing
- Win32 programming.
-
- One of the key differences as far as environment is that Win32
- applications running under Windows 3.1 share memory with Windows 3.1
- applications and Win32 applications and Win32 applications share memory
- with other Win32 applications. This is from a virtual point of view, if you
- get my meaning, and it's just what we expect from regular Windows 3.1
- programs. The difference is with NT and later, 'Chicago'. Win32 programs
- running under NT each have their own virtual 4 GB (that's gigabytes, for
- those of you not used to seeing numbers of that magnitude) of RAM to work
- in. That means that Program Manager has its own 4 GB of RAM and File
- Manager has its own 4 GB of RAM, even when they're both running at the same
- time. Actually, when I say 4 GB, you're really limited to a mere 2 GB of
- that memory. The other 2 GB belongs to the Kernel. Also, keep in mind,
- that's 'Virtual' memory, not real memory. You're still limited by how much
- you have in your machine and how big your swap file is. Under NT, you have
- only one swap file and its the permanent swap file.
-
- Anyway, I digress, the point is that without some sort of IPC
- (interprocess communication, which we'll get into in a second), NT
- applications wouldn't be able to see each other's memory. This makes it
- slightly more difficult to share memory between applications but it pays
- off in that one process can't damage another process' memory and cause
- everything to fall to pieces. Instead, under NT, the one process can hurt
- itself and die, but everything else goes on unaffected.
-
- When designing Win32 applications under Windows 3.1, however, it's
- important to keep in mind that the applications CAN wipe each other out. If
- you want your applications to run under both environments, you need to be
- sure to keep this in mind. Under Windows 3.1, Win32 applications, like 16-
- bit applications, share the same memory with all the other processes
- running. This can be a problem when porting Win32 applications to Win32s
- that make assumptions about the memory.
-
- Well, that's enough of that, I think you get the picture. Under
- Windows 3.1, 32-bit apps share the same memory, under Windows NT, they
- don't. Clear?
-
- Ok, so what if you want to share memory? Well, DDE is still there, but
- I wouldn't recommend it for most situations. It's just too much of a pain
- for most applications. The old method of using GlobalAlloc and then passing
-
- - 20 -
-
-
-
-
-
-
- the handle in lParam of a message and the other application using
- GlobalLock to access it no longer works because that 'Global' memory isn't
- so global anymore, it's not shared between applications (except in Win32s,
- but we don't want to make that assumption, right?). In the Windows NT
- environment, there are memory-mapped files. These are an excellent method
- of IPC and the good news is that Microsoft is working on implementing it
- for Win32s (that's 32-bit Windows for Windows 3.1, as opposed to Win32
- which is for NT and Win32c for 'Chicago'). This means there will be a
- simple, common method for sharing data between applications.
-
- I won't go too in-depth into it this month, but memory-mapped files
- are essentially files that are treated as if they're regular memory, except
- a sort of temp file is created to hold the data. The way it works is that
- you have a file that you treat as if it's memory. You simply have a pointer
- that you can point and move anywhere in the file as if it were a regular
- pointer to memory and Win32 picks up the tab on the file I/O work. It's
- basically just another type of virtual memory. All the other program has to
- know about is the file mapping object name. There are other uses for
- memory-mapped files which I'll cover in a later column, likely one devoted
- to memory-mapped files.
-
- Preemptive Multitasking vs. Non-Preemptive Multitasking
-
- Windows NT (and Windows 4.0, when it gets here) is a preemptive
- multitasking operating system. You've probably seen those buzzwords
- mentioned in every review or discussion of NT. What does this mean exactly?
- Preemptive multitasking is where the CPU decides how much time your program
- has to run. After that time is up, your program is stopped, the register
- contents are saved and another program is given control. And then another
- and then another until it gets back to the first. Then its registers are
- reset and it is sent on its way for its particular time slice.
-
- Windows 3.x use a non-preemptive multitasking system where each
- program is responsible for giving the other programs in the system time to
- run. This cooperation takes place in the message queue where messages are
- passed around the system from one program to another until it finds its way
- to the program that needs it. In Windows 3.x it's simple to write a program
- that doesn't release the CPU to other applications. Just try writing an
- infinite loop and you've locked up the entire system.
-
- Under Windows NT, the message queue is still used, but the system
- doesn't rely on it to provide CPU time to other programs. If your program
- has an infinite loop, then your program will lock up. The rest of the
- system will continue running with no effect from your program.
-
- I should mention that Windows 3.x is not an entirely non-preemptive
- multitasking system. There are a couple parts that are, or can be,
- preemptive. The DOS box, for example, is preempted by Windows. The DOS box
- receives its time slice to run and that's it. Then Windows gets some time
- for a while and then it gives another time slice to the DOS box. Another
- place than can be preemptive is VxDs or .386 drivers. The reason is that
- these run at what is called Ring 0. Ring 0 is where the low-level system
-
- - 21 -
-
-
-
-
-
-
- control stuff takes place in 386, 486 and now Pentium chips. (There are
- four rings, 0-3. Rings 0 and 3 are the only ones used by Windows).
- Actually, this area isn't exactly preemptively multi-tasked but is
- available for it. The software running at Ring 0 has complete control over
- the system, so it can really do whatever it wants.
-
- That's all for this month, I'm afraid. I'm really sorry if my articles
- seem a bit anemic for the next few months. I'm afraid I have little choice
- in that. We'll see how much time I actually have over the next few months,
- but this book is really going to take a lot of work.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 22 -
-
-
-
-
-
-
- WDASM
- Review of a Windows Disassembler
- By Pete Davis
-
- WDASM is the only Windows disassembler I know of that's available for
- shareware. The product is amazing and well worth it's mere $10 registration
- fee. The version I have been using is 1.2, which is the unregistered
- version. I am awaiting version 1.6 which is on it's way.
-
- WDASM is available from many sources, including the CompuServe WINSDK
- forum, WSMR-SIMTEL20.ARMY.MIL in the PD:<MSDOS.WINDOWS> directory, and from
- FTP.CICA.INDIANA.EDU in the pub/pc/win3/programr directory.
-
- When you run WDASM you get a window with a small and simple menu. The
- menu structure is:
-
- File Edit View Help
- ---- ---- ---- ----
- Open Set Bytes Segment Index
- Save Text As Goto About
- ---- Address Offset
- Exit Far Call Names
-
-
- WDASM will disassemble both .EXEs and .DLLs. As soon as you open an
- executable, the WDASM window shows the disassembly of Segment 1 of the
- executable. To change to different segments, simply go to View and select
- the segment you want.
-
- Set Bytes allows you to set a range of bytes to data, instructions,
- labeled instructions.
-
- Goto, of course, takes you to a certain address. Address Offset is a
- nice feature. Normally, the only address offsets that show up in the code
- are the labels. All labels are in the form:
-
- LxxxxH: where xxxx is the offset.
-
- Far call names toggles between labeling far calls and showing the
- actual address of the call.
-
- When you're done you can use Save Text As to save the assembly
- language code generated by WDASM to a .ASM file.
-
- There are some things I'd like to see in WDASM and, in fact, after
- talking to Eric, it appears some of them are there (in the registered
- version). These include some minor bug fixes and some expansion of the
- program. I'd like to see a little commenting in the code about what's going
- on. Sometimes it's a simple operation to find out what some code is doing.
- It would be nice if the disassembler did some of those for you.
-
- Also, I'd like to be able to do some editing in WDASM. For example, if
-
- - 23 -
-
-
-
-
-
-
- I figure out what a certain routine does, I'd like to name it in WDASM and
- have it go through and correct all references to that label.
-
- I'd like support for the PE file structure, which, actually, when I
- suggested it to Eric, he was more than happy to get some information on PE
- file structures from me and plans to upgrade the software to handle them.
-
- Other upgrades which I'm aware of that are in the works (or done?)
- include support for 386/486 instructions and support for floating point
- instructions.
-
- I have a wish list of things to be added and I have passed a lot of
- them to Eric. This is where Eric's product sticks out the most. I've talked
- to other shareware authors about improvements in their products. Few have
- been as receptive to new ideas as Eric. Eric does his product for the end-
- user, not himself. That's really not as common as you might think. A lot of
- shareware authors ask for your comments and when you send them in, just
- ignore them. Eric really wants to do a product that will be useful for his
- users. He's already done that.
-
- I can't recommend this program highly enough. If you do Windows
- disassembly, consider this program. For the price, it's an absolute
- bargain. And if you like it, PLEASE REGISTER it. It's only $10, which is
- inexpensive, even for shareware. It's worth every penny.
-
- Happy disassembling.
-
- [Ed. Note: Just prior to the release of this issue I received Version 1.6
- of the disassembler. Not enough time to really use it a lot or to rewrite
- the review. I will only say that 1.6 has some major improvements. I also
- know Eric is in the process of making more. Get this disassembler and try
- it out.]
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 24 -
-
-
-
-
-
-
- Hypertext, Sex and Winhelp
- By Loewy Ron
-
- Hi, this article is about hypertext, help systems and winhelp. If you
- ask yourself what has this kind of article to do in a programming
- magazine, and tell yourself (and everyone around you) that you are a
- programmer and not a technical writer, I can only tell you of a
- sentence I heard at a recent conference I attended, from a Rep. of a firm
- that markets a database development tool. The guy told us that
- in user surveys they learned that people that evaluated their
- product, gave the quality of the documentation the same weight they gave
- to the functionality of the product. (Hearing this stuff, and
- knowing I'm not as good as I should be at writing documentation, I
- decided I had to stop while I'm at the top - so this is the end of this
- article, bye. Well, no - this was just a joke, we will continue from now
- ..).
-
- An important part of your application's documentation is the on-line
- help. One of the advantages of programming for Windows, is that
- Windows includes a built-in help engine, with a (well?) documented
- interface. This engine is both easy for the users to use, standard
- among applications, and yet is powerful and extendible.
-
- This article will talk a bit about hypertext systems in general, and
- will try to focus on the Windows implementation.
-
- Hypertext is a term used to describe large amounts of textual data,
- that have embedded references to other textual elements of the
- database. These other elements have some connection to the text element
- that is currently read by the user, and might interest him.
- The difference of hypertext systems from traditional documentation is that
- reading a hypertext document, the reader (user) can read in a non linear
- order, and jump around the database according to his will (and the
- references that were created in the document by the system's
- designer).
-
- We usually define a piece of textual information that can be regarded
- as a single unit - a Topic. Our help "database" is a collection of
- Topics, that most (if not all) of them, have references (called
- Links) to other Topics, that have some connection to them.
-
- You have probably used some hypertext systems, such as the on-line
- help that came with your development package/language/compiler. (if
- you still use GW-BASIC as your main development tool - you are
- advised to upgrade, or you might find some of the other articles in
- this journal hard to follow).
-
- In order to incorporate help (using winhelp) into your application,
- you (roughly) have to go through the following steps :
-
- 1. Design the layout of your hypertext help database.
-
-
- - 25 -
-
-
-
-
-
-
- 2. Create the winhelp source files, and compile them to create the
- .HLP file(s) for use with the winhelp application.
-
- 3. Create a help menu/button/toolbar or other interface element from your
- application to the winhelp database, and code the winhelp API
- calls to activate that database from your application.
-
- 4. Optionally - If you want to create context-sensitive help (help
- that is activated when a user presses the F1 key for example, and
- receives help about the operation/options that he is currently
- doing/having), code the key interception and calls to the winhelp
- database.
-
- Step 1 is really something that should be left to people that know
- more about user interfaces, usability studies and these sort of
- things than me. I have included some references that might be of
- interest at the end of this article.
-
- Steps 3 and 4 will be discussed in a future article (If the editor
- will want me to write any more after some angry readers will e-mail
- him some threats, or knock on his door at the middle of the night).
-
- In order to create .HLP files - that contain your help database, you
- have to create source files for Microsoft's help compiler. There are
- actually 2 help compilers - HC30.EXE that creates help topics in
- Windows 3.0 format, and HC31.EXE that creates help topics in Windows 3.1
- format. While HC31 help databases can be more sophisticated than HC30
- created databases, you will not be able to use them on Windows
- 3.0 platforms, while winhelp that came with Windows 3.1 can display
- help from .HLP files in both formats.
-
- The input to the help compiler is a project description (.HPJ) file,
- and a set of Rich Text Format (.RTF) files, with special code to
- describe Topics, Links, Search keywords etc..
-
- RTF is a document description standard that can describe (any?)
- word-processor file using only 7 bit characters. Unfortunately RTF is a
- language that is very hard to read and maintain manually. You would
- probably want to use a word processor that can output RTF files, or a tool
- that can translate plain readable ascii files into RTF output.
- If you have Word for Windows, several help authoring templates,
- styles and macros are available in the commercial and shareware
- market, that can help in the creation of help databases. At the end
- of this article you will find a list of the help authoring packages I am
- aware of, I have not tried or used all of them, I'm just trying to bring
- them to your attention.
-
- In the RTF file, use page breaks between Topics. Your Topics can be
- longer than one page, but when you use a page break - you tell the
- Help Compiler that this is the end of the text that belongs to this
- Topic. For each Topic include a # and $ footnotes to describe its
- name, and reference, so that other topics will be able to include
-
- - 26 -
-
-
-
-
-
-
- Links to it. Links are included using a text with double underline
- attribute, followed by a hidden Topic reference name. I will give a
- RTF example that will help you understand the mechanism.
-
- We will define 2 Topics - TOP1 and TOP2 and create Links between
- them. The following code example is part of a RTF file.
-
- {\f2
- #{\footnote \pard\plain \fs20 # TOP1}
- ${\footnote \pard\plain \fs20 $ TOP1}
- }
- \pard{This is the first paragraph of Topic 1, with no Link here}
- \pard{This is the 2nd. paragraph of topic 1, we will include a
- {\f2\uldb Link}{\v\f2 TOP2} here to Topic 2}
- \page
- {\f2
- #{\footnote \pard\plain \fs20 # TOP2}
- ${\footnote \pard\plain \fs20 $ TOP2}
- }
- \pard{This is Topic 2, Click {\f2\uldb Here}{\v\f2 TOP1} to reach
- topic 1 }
- \page
-
- As can be seen - Each topic starts with a # and $ footnotes, and
- ends with a page break (\page). Whenever we want to create a Link, we use
- the \uldb (double underline) attribute with the text we want to
- display, and follow it with a hidden (\v) text with the reference to the
- Topic it is linked to.
-
- It should be explained at this point - that this code is not enough
- to create a help database that contains only these 2 Topics, it is,
- however, beyond the scope of this article to describe all the RTF
- commands needed to create a help document. I have, however, included the
- source to a simple help database with only 3 Topics, and Links
- between them. You will have to refer to the RTF specifications
- (available from Microsoft, or - if you have the MSDN CD-ROM, you can find
- it there), and the help compiler documentation that comes with
- the SDK or with your compiler.
-
- The next file that should be created for the help compiler is the
- project file. The following code is an example of such a file :
-
- [OPTIONS]
- INDEX=TOP1
- COMPRESS=TRUE
- TITLE=Demo Help Project
-
- [FILES]
- DEMOPROJ.RTF
-
- [MAP]
-
-
- - 27 -
-
-
-
-
-
-
- [BITMAPS]
-
- This is a file that have a structure that resembles a .INI file, with
- sections and options in it. The [OPTIONS] section include general
- options that are used by the help compiler during the .HLP file
- generation. In the example above our Topic 1 is defined as the index
- topic - the one that winhelp will display first when it loads the
- help file, the compress entry tells the help compiler to compress the help
- text, and the title entry instructs winhelp what to display in
- the title of the help window. It is important to notice that the .WPJ file
- syntax is different between HC30 and HC31. The example above is good for
- HC30, and in HC31 the index entry should be replaced by a
- contents entry to achieve the same results.
-
- The [FILES] section lists all the RTF source files used to build the
- help database. There are additional sections and entries in section
- that are used to create and set options to the help database. It is
- advised that you refer to the Microsoft SDK documentation, or the
- documentation that came with your compiler for a complete discussion of all
- the features and options of the help project file.
-
- Summary
- -------
-
- O.k, this was just an introduction that touched the surface of what
- it means to create help databases for use with winhelp, and this
- should probably get you started. I might add additional articles on
- this subject in the future. Good luck, and have fun helping others.
-
- If you wonder about the title of the article - hey, this is my first
- one, and I covered 2 of the 3 subjects - that is pretty good, don't
- you think?
-
- References :
- ------------
-
- 1. Microsoft Press - Microsoft Windows 3.1 Programming Tools, Chapter 3
- and Appendix B.
-
- 2. Borland Pascal With Objects 7.0 - Tools and Utilities Guide,
- Chapter 6 and Appendix A.
-
- 3. Windows Help Authoring Guide - A Microsoft publication available
- on the internet as WHAG.ZIP in CICA.
-
- 4. RTF Specifications - I have mine from the Microsoft MSDN CD-ROM.
-
- Help Authoring Tools :
- ----------------------
-
- This is a list of tools I know that exist. I have not used all of
- them, nor do I know if they all work. I only included this list in
-
- - 28 -
-
-
-
-
-
-
- order to help you get a jump start in creating help databases. All of the
- opinions I express - are mine, and mine only.
-
- 1. Microsoft Windows Help Authoring Tools - a combination of a help
- project editor and winWord templates and macros. Available on the
- internet in CICA as WHAT.ZIP.
-
- 2. SYNTAX.ZIP - A tool to convert WP documents to windows help.
- Available in the misc directory of CICA on the internet.
-
- 3. HELP.ZIP - A tool to convert OS/2 IPF files to RTF documents.
- Available in the nt directory of CICA on the internet.
-
- 4. HAG.ZIP, WHAG.ZIP - Windows help authoring guide in winword and
- .HLP formats. Available in the programr directory of CICA.
-
- 5. WFWHLP.ZIP - Info on Constructing Windows Help Files.
- Available on the program directory of CICA, also in CIS, WINSDK
- forum, Lib. #16.
-
- 6. HWAB21.ZIP - Help Writer's Assistant for Windows (This is cute).
- Available on the util directory of CICA.
-
- 7. QDHELP.ZIP, QDTOOL.ZIP - Use DOS Editors to Create WinHelp Files.
- This is a really nice tool. Available on the util directory of
- CICA. Also on CIS WINSDK Forum, Lib 16.
-
- 8. DRHELPEV.ZIP - Macro to translate Word files to WinHelp files.
- Available on the winword directory of CICA.
-
- 9. HLPDK30.ZIP, HLPDK40.ZIP - My own Help Development Kit. I'm biased so I
- will not say any further word. Available on SIMTEL hypertext directory,
- GARBO programming directory, Compuserve WINSDK forum, and an undefined
- place (currently in uploads) on CICA.
-
- 10. Doc-To-Help - A commercial tool. A press release can be found in
- D2HPRS.TXT and D2HNEW.ZIP in library 3 of the WINSDK forum on COMPUSERVE.
-
- 11. HELP.DOT - WFW 2.0 Template for Creating WINHELP RTF Files -
- Library 3, WINSDK Forum, CIS.
-
- 12. RoboHELP - A Commercial Tool (I have heard some nice things about
- this one). HELPTO.TXT on CIS WINSDK forum (Lib 3) has a reference to it.
-
- 13. BOOKHL.ZIP - Developing Online Help for Windows - The Book.
- WINSDK forum, Lib 16, CIS.
-
- 14. CH102.ZIP - CreateHelp! HLP authoring tool.
- WINSDK forum, Lib 16, CIS.
-
- 15. HCMAC1.ARC - HC1.DOT template and support files to build help.
- WINSDK forum, Lib 16, CIS.
-
- - 29 -
-
-
-
-
-
-
- There are more tools and references in CIS WINSDK Forum, LIB 16, as
- well as other places.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 30 -
-
-
-
-
-
-
- Enhancing the WINSTUB Module
- By Rodney Brown
-
- When I was reading over the first issue of WPJ, I came upon an article
- that was talking about the possibilities of the WINSTUB module. This got
- me thinking and I started working on enhancing WINSTUB. WINSTUB is a DOS
- program that is placed at the front of your Windows application. When you
- try to load a Windows program from DOS, it is the culprit that gives you
- that nasty little message "This program requires Microsoft Windows," then
- drops you back to DOS to pay for your sin<g>.
-
- The first WINSTUB program I designed automatically loaded up Windows
- if the program was started from DOS. I then decided to change it a little
- bit because some users may not like that. The second WINSTUB module asks
- the user whether they want to load Microsoft Windows or exit to DOS. This
- allows the user to back out of the program if they made a mistake in typing
- the program name, etc.. The WINSTUB program was written in Turbo C++ for
- DOS. The source code and project file are provided in the WPJ archive, but
- the C++ code is discussed below for those with other C/C++ compilers.
-
-
- // Enhanced WINSTUB.EXE for Windows applications
-
- #include <process.h>
-
- The process.h header file contains the information for the spawn command,
- the spawn command allows you to call an external program.
-
- #include <stddef.h>
-
- This header file is used solely for the definition of the NULL statement.
-
- #include <iostream.h>
-
- This is the C++ version of stdio.h
-
- char answer;
- int returncode;
-
- These two statements initialize an answer variable of type char, and a
- returncode variable of type int.
-
- int main(void)
- {
- cerr << "\nThis program requires Microsoft Windows to run.";
- cerr << "\nWould you like me to start Microsoft Windows for you? ";
-
- The cerr << "text" command is the C++ equivalent of sending text to stderr.
-
- cin >> answer;
-
- The cin >> variable command is the C++ equivalent of retrieving data from
-
- - 31 -
-
-
-
-
-
-
- stdin.
-
- if (answer == 'y' || answer == 'Y')
- {
- returncode = spawnlp(P_WAIT,"win.com","","myprog",NULL);
-
- The statement above tries to call win.com (Windows). If the call is not
- successful, the spawn command returns a negative integer number. The "l"
- in spawnlp signifies that the number of parameters sent to called program
- is known. The "p" in spawnlp tells spawn to search the DOS path for the
- program being called.
-
- if (returncode<0)
- {
- cerr << "\n\nError, could not start Microsoft Windows.";
- cerr << "\nExiting back to DOS...";
- }
- }
- else
- cerr << "\n\nExiting back to DOS...";
-
- return returncode;
- }
-
- The purpose of the rest of the program should be obvious, if the user
- answered yes and the spanwnlp call was not successful, an error message is
- displayed and the program drops back to DOS. If the user answered no, the
- program exits to DOS.
-
-
- Once you have written and compiled your DOS WINSTUB program, you need to
- return to window and modify your .def file to put everything together. A
- sample .def file looks like this:
-
-
- NAME MYPROG
- DESCRIPTION 'Description of program goes here...'
- EXETYPE WINDOWS
- STUB 'WINSTUB.EXE'
- CODE PRELOAD MOVEABLE
- DATA PRELOAD MOVEABLE MULTIPLE
- HEAPSIZE 4096
- STACKSIZE 5120
-
-
- After reading the last 4 WPJ's, you should know what most of the above code
- does. The main parameter we are concerned with is the STUB parameter. In
- Turbo C++ for Windows (and I assume Borland C++), the STUB parameter is not
- required unless you are using a WINSTUB module other than Borland's. Turbo
- C++ for Windows also does not require the EXPORT parameter if you are using
- ObjectWindows.
-
-
- - 32 -
-
-
-
-
-
-
- There are other possibilities for WINSTUB, the program above was just a
- simple enhancement of WINSTUB. If you thought the comments of the source
- code above was overkill, I'm sorry, but I just wanted to explain the
- program to people who may not know C++, or are just starting out in C.
-
- About the author
-
- Rodney M. Brown is a civilian employee at Charleston Air Force Base, South
- Carolina. His job involves operating and maintaining minicomputers and POS
- Systems, programming and repairing microcomputers. He also gives computer
- lessons to fellow employees.
-
- He can be reached through the following services:
-
- GEnie: R.BROWN141
-
- CompuServe: 72163,2165
-
- Internet: 72163.2165@compuserve.com
-
- If you are connected to more than one of these services, communication
- through CompuServe is preferred.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 33 -
-
-
-
-
-
-
- Microsoft Developers Network
- Dave Campbell
-
- How would you like to have all the latest information about Windows
- programming, OLE, ODBC, etc. at your fingertips? This would include sample
- code from the people that wrote the compiler and defined the interface, and
- books by leaders in the industry. So far I'm talking about 2-layers of
- documentation deep on my desk.
-
- That's what I usually get into when I get rolling on my article, or
- get deep into a development sequence. Sometimes it gets downright
- embarrassing.
-
- There is a solution, though. If you haven't heard about the Microsoft
- Developer's Network yet, you're missing out on a valuable resource. I have
- had the pre-release CD since December, but didn't get a CD-ROM drive until
- this month. This is the scenario: I got into Windows, then Word, and opened
- up my article, and my source code. Then back to Resource Manager, and
- opened the CD. Now for the rest of the article, I worked back and forth
- between the two Windows applications, cutting and pasting, and rewording,
- and basically saving me a ton of time.
-
- The Developer's Network is a subscription program in which Microsoft
- sends a CD out quarterly which uses a great user interface to search out
- information. The pre-release CD contains technical information and example
- code to use in writing applications for C/C++, DDE, OLE, using the
- Clipboard. NT and VB 2.0 sample code, VB 2.0 Professional documentation,
- Excel SDK, MAPI, ODBC, and RTF specifications. Additionally you'll find
- Charles Petzold's Programming Windows 3.1 book in its entirety, including
- code with hyperlinks out to the SDK. There's a few years worth of Microsoft
- Systems Journal magazines, and Ray Duncan's "Advanced MS-DOS Programming"
- book in its entirety. When you open up a section of the CD for
- inspection, you can view the code, run the executable, or cut and paste
- directly into your application from the CD.
-
- I think you get the idea.
-
- The installation was extremely smooth...all contained on the CD
- itself. My CD-ROM drive normally comes alive as drive I:, so I just ran
- I:\SETUP.EXE. It is taking up about 10M of my hard disk because I let it do
- the most it wanted, for speed of access later. Once it was finished, the
- whole thing was available for use.
-
- The cost of the program is $200/yr now that the pre-release program is
- over. Petzold's book alone is $50 if you buy high-dollar retail, so that
- covered the cost of the first one for us in the pre-release. I'm sure I
- won't be disappointed with the remainder of them.
-
- Of course, you'll need a CD-ROM drive to play the CDs, and that isn't
- cheap yet. But, if you know someone with a Gateway 2000 customer ID, you
- can buy a Sony drive, which is AX, CDI, multisession, and Kodak
- compatible, drive, cables, and interface card for $225 plus $5 shipping. I
-
- - 34 -
-
-
-
-
-
-
- highly recommend finding someone that can order this for you. I got mine in
- 5 days, and it took about 20 minutes to install. It plays audio and digital
- CDs, and works great with the Developer's network.
-
- If you have any questions, feel free to send me e-mail:
-
- Dave Campbell
- WynApse PO Box 86247 Phoenix, AZ 85080-6247 (602)863-0411
- wynapse@indirect.com
- CIS: 72251,445
- Phoenix ACM BBS (602) 970-0474 - WynApse SoftWare forum
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 35 -
-
-
-
-
-
-
- Getting in touch with us:
-
- Internet and Bitnet:
-
- HJ647C at GWUVM.GWU.EDU -or- HJ647C at GWUVM.BITNET (Pete)
-
- GEnie: P.DAVIS5 (Pete)
-
- CompuServe: 71141,2071 (Mike)
-
- WPJ BBS (703) 503-3021 (Mike and Pete)
-
- You can also send paper mail to:
-
- Windows Programmer's Journal
- 9436 Mirror Pond Drive
- Fairfax, VA 22032
- U.S.A.
-
- In future issues we will be posting e-mail addresses of contributors
- and columnists who don't mind you knowing their addresses. We will also
- contact any writers from previous issues and see if they want their mail
- addresses made available for you to respond to them. For now, send your
- comments to us and we'll forward them.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 36 -
-
-
-
-
-
-
- The Last Page
- by Mike Wallace
-
- Some background: Taoism is a very old philosophy that originated in
- China, and one of its major writers was a man named Chuang-tse. This
- month's column starts off with a story from his writings:
-
- Hui-tse said to Chuang-tse, "I have a large tree which no carpenter
- can cut into lumber. Its branches and trunk are crooked and tough,
- covered with bumps and depressions. No builder would turn his head to
- look at it. Your teachings are the same - useless, without value.
- Therefore, no one pays attention to them."
-
- "As you know," Chuang-tse replied, "a cat is very skilled at capturing
- its prey. Crouching low, it can leap in any direction, pursuing
- whatever it is after. But when its attention is focued on such
- things, it can be easily caught with a net. On the other hand, a huge
- yak is not easily caught or overcome. It stands like a stone, or a
- cloud in the sky. But for all its strength, it cannot catch a mouse.
-
- "You complain that your tree is not valuable as lumber. But you could
- make use of the shade it provides, rest under its sheltering branches,
- and stroll beneath it, admiring its character and appearance. Since
- it would not be endangered by an axe, what could threaten its
- existence? It is useless to you only because you want to make it into
- something else and do not want to use it in its proper way."
-
-
- Why am I writing about Taoism? Well, I'm not, really. I was reminded
- of this story a couple of weeks ago after reading a review of IBM's OS/2
- 2.1. The focus of the article seemed to be that OS/2 could run Windows
- programs almost as well as Windows. Sounded like the reviewer wanted to
- make OS/2 something it's not: Windows. Thus, the story. Now, I'm not here
- to harp on that useless operating system OS/2, but if I want to run
- Windows, I'm not going to buy a 486 with 12MB of RAM and a 100MB hard drive
- to support OS/2. I've seen Windows run fine on a 386 with 4MB and a much
- smaller hard drive. My computer could run OS/2, but I installed Windows NT
- on it, and it runs Win3.1 programs without a problem. Windows NT has about
- the same memory requirement as OS/2 but needs less space on your hard
- drive.
-
- Windows and OS/2 are different operating systems, and I think they
- were each designed with a different kind of end user in mind. If you want
- to run Windows, why buy OS/2? OS/2 should have a better selling point than
- "it runs Windows apps almost as well as Windows." Anyone buying OS/2 based
- on this promise will only be disappointed, I think. An operating system
- should be able to stand on what makes it unique, or it will end up being
- nothing more than a cheap imitation.
-
- Hey, enough ranting and raving. This issue is already late enough.
- Talk to you next month.
-
-
- - 37 -
-
-
-