home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-02-01 | 74.6 KB | 2,047 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 02
- and Mike Wallace Feb 93
- ----------------------------------------------------------------
- A monthly forum for novice-advanced programmers to share ideas and concepts
- about programming in the Windows (tm) environment.
-
- You can get in touch with the editor via Internet or Bitnet at:
-
- HJ647C at GWUVM.BITNET or HJ647C at GWUVM.GWU.EDU
-
- CompuServe: 71141,2071
-
- or you can send paper mail to:
-
- Windows Programmer's Journal
- 9436 Mirror Pond Dr.
- Fairfax, Va. 22032
-
- The two GWUVM IDs are Pete's and CompuServe is Mike's.
-
- We can also be reached by phone at: (703) 503-3165.
-
- 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.
-
- WPJ is available from the WINSDK, WINADV and MSWIN32 forums on CompuServe,
- and the IBMPC, WINDOWS and BORLAND forums on GEnie. 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 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 Editor, Peter J. Davis, and only then after he has obtained
- permission from the individual authors.
-
-
-
-
-
-
-
-
- Table of Contents
-
- Subject Page Author(s)
- -----------------------------------------------------------------
- WPJ.INI ....................................... 3 Pete Davis
-
- Letters ....................................... 5 Readers
-
- Install Program Part II ....................... 7 Pete Davis
-
- Programming a Drag&Drop Server ................ 9 Andreas Furrer
-
- C++ Beginner's Column ......................... 12 Mike Wallace
-
- Beginner's Corner (C) ......................... 14 Pete Davis
- & Mike Wallace
-
- Using LZExpand Library ........................ 18 Alex Fedorov
-
- Implementing a Linked List - Revisited ........ 21 Mike Wallace
-
- An Introductory Look at DLLs and Make Files ... 22 Rod Haxton
-
- The Windows Help Magician ..................... 29 Jim Youngman
-
- Last Page .................................... 30 Mike Wallace
-
- Getting in Touch with Us ..................... 31 Pete & Mike
-
-
-
-
- Windows Programmer's Journal Staff:
-
- Publishers ......................... Pete Davis and Mike Wallace
- Editor-in-Chief .................... Pete Davis
- Managing Editor .................... Mike Wallace
- Contributing Writer ................ Andreas Furrer
- Contributing Writer ................ Alex Federov
- Contributing Writer ................ Rod Haxton
- Contributing Writer ................ Jim Youngman
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- WPJ.INI
- By Pete Davis
-
- Well, welcome to the second issue of the Windows Programmer's Journal.
- I don't really know what to say. We've been totally blown away by the
- response we've been getting. I'm writing this on January 15th and as of
- today, on Compuserve and GEnie (the only two places we can really see how
- many issues are being downloaded) we've counted 873 downloads. That number
- goes up every day and it doesn't include all of the other places that the
- Windows Programmer's Journal is available. We've gotten letters from a lot
- of you with good and bad things to say. (When I say bad, I really mean
- critical.) Criticism is fine and we're even going to publish some of it in
- this issue.
-
- We've also received a terrific response from Andrew Schulman, whose
- book we reviewed in the last issue. We'll show an excerpt from that and
- other letters in the letters column.
-
- One of the criticisms that was most discussed was the Linked List
- article written by Mike. We should be receiving an article from Peter
- Shroesbree for the next issue, showing an alternate way of doing it. We'll
- also have a third article, showing yet another way of doing this in next
- month's issue, done by Rod Haxton, who's writing an article in this issue.
- Since this has become a bit of a hot topic, we're going to do a short
- article in next month's issue about the advantages and disadvantages of
- each of these methods.
-
- We'd also like to welcome David Campbell. In March, he'll be taking
- over the beginner's column. David has a good bit of experience in Windows
- programming and is quite a hacker. He has shareware and commercial software
- on the market, so his experience will be valuable to all of us.
-
- Speaking of experience, I suppose it's time to kind of spill the beans
- about Mike and I. So as not to confuse anyone, neither Mike nor I have a
- lot of experience programming Windows. We are not authorities on the
- subject, but we don't think that means we don't know a few things that we
- can share. We're both learning a lot all the time. The linked list article
- is an example. All I'm trying to say is, don't say, "Well, the Windows
- Programmer's Journal says this, so it must be true." Not that you would,
- but we all can make mistakes and we're not always going to be right. The
- good thing is that there are obviously a lot of you out there reading this
- and with your help, we can make corrections.
-
- We have another article from Andreas Furrer this month. Last month he
- wrote an article about programming a Drag & Drop client in Windows 3.1.
- This month he's going to talk about writing a Drag & Drop server program.
- We've also got an article by Alex Federov of Moscow, Russia on using the
- LZEXPAND.DLL.
-
- Just got my sample issue of Windows Tech Journal. Ahem... How do you
- spell cancel? Nah, it ain't that bad, just not really my type of magazine,
- I guess. Had an offer for Windows NT Developer. 12 issues for a mere $129.
- No thanks, I'll buy the book.
-
- Sorry, I digress. Geez, let's see, I'm going to be writing the second
- part to the install program. I'm basically covering a lot of the stuff Alex
- Federov is covering. His sample, however, is written in Turbo Pascal for
- Windows. I was supposed to do an article on printing, this month, but I've
- been really busy, so I'm going to have to put it off until the next issue.
- I'll share a really wonderful experience with you about my trials in
-
-
-
-
-
-
-
-
- learning to print also.
-
- Ah, and I almost forgot. We're going to do a reader poll next month.
- Here's the question. What format would you like to see WPJ in? We've had
- suggestions for a lot of different formats. Mike is leaning in the Windows
- Write direction. That's ok, but it doesn't quite have the power of a real
- word processor, which is a pain when putting the whole thing together. Dave
- Campbell suggested Windows WINHELP format. I've seen a sample, and I have
- to say, it's pretty damn impressive. We've also had suggestions for
- Postscript and TeX. Now, the problem with Postscript, as I see it, is it's
- BIG. That means it'll take longer for you to download. If you're getting it
- off Compuserve or GEnie, or some other pay system, it costs you. As far as
- TeX, I don't know how popular it is. Personally I've never used it and
- don't know anyone who has (though I've heard good things about it), so
- unless we get a huge outcry for the TeX format, I don't think we'll go that
- way. That leaves the regular text format that you're getting it in now,
- Write format, or WinHelp format. Now, before you cast your votes, we will
- be distributing the March issue in all three of those formats. After March,
- tell us what you think. I just wanted to give everyone a heads-up on that.
-
- One final note: We mentioned our BBS in the last issue. Well, we had
- it up for about 3 days and before anyone had a chance to call, the hard
- drive got wiped out. I've been trying to get the thing back together, but
- the hard drive is really getting unreliable. What it looks like I'm going
- to have to do is get rid of it and replace it. I currently have two 65 meg
- Seagates which have done their time. The main one (C: drive) is just
- getting a little too flakey, so we're going to toss it and probably throw
- in a 600 meg hard drive that we saw a good deal on. (We have two machines,
- so we're going to network them so that Mike can use the 600 meg on his
- machine too.) Anyway, we don't know if we'll have it up this month. If we
- don't, it'll be next month. Sorry for the problems there.
-
- I'd like to thank everyone who's reading the magazine and sending in
- their comments and suggestions. It helps us to do a better job and it helps
- you get a better magazine. We really appreciate your comments and we'd like
- you to keep them coming. Also, as always, please, please, send us your
- articles. We want them!!!!
-
- By the way, it's now January 31 and the number of downloads on GEnie
- and Compuserve alone are about 1200, total. Sorry, just about broke my arm
- patting myself on the back there. 'Scuse me while I pump up our egos a bit.
- We'll try not to do that too often.
-
- And remember, if you read it in the Programmer's Journal, it might be
- right!
-
- _Pete Davis
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Letters
-
- Date: 04-Jan-93 13:48 EST
- From: Andrew Schulman [76320,302]
- Subj: Windows Programmer's Journal
-
- Thanks very much for sending the magazine. Of course, I read the
- review of UndocWin very carefully, and read the rest pretty carefully. I
- guess my main question is, Why the heck are you guys doing this? You both
- write well. The material is interesting and entertaining. So why are you
- giving it away for free? Doesn't make any sense to me. You could be
- making money from your writing, though not necessarily with your own
- magazine. But clearly you could write for MSJ, WDDJ, or Dr. Dobb's (I
- won't mention that other magazine that covers Windows programming...). So,
- like, why give the stuff away?
-
- Thanks for the kind review of UndocWin. If you are looking for more
- stuff on how Windows operates, I think you'll be pleased with the book
- "Windows Internals" that Matt Pietrek is just finishing up. It will appear
- in the series of books I am editing for Addison-Wesley, probably in March
- or April. Most of the book is typeset already. It presents detailed
- pseudocode for many of the key Windows API functions. For example, if you
- want to know what CreateWindow or RegisterClass or GetMessage or ShowWindow
- or GlobalAlloc actually does, in sometimes painful detail, this is it.
-
- UndocNT? Well, that's an interesting question. Microsoft has asked
- me that question too. As you know, the entire NT API (as opposed to the
- Win32 API) is right now undocumented. Helen Custer's book "Inside Windows
- NT" does a good job of showing in a conceptual-overview sort of way how NT
- works, but as she herself says in the preface the book's goal is to how
- "exactly how NT sort of works" Exactly sort of! A brief examination of
- the NT process viewer, PVIEW.EXE, shows that there is some dynamite stuff
- at the NT API layer that currently isn't available via Win32. (Ray Duncan
- was who put me on to looking at PVIEW; I looked at it first with
- Microsoft's COFF -DUMP, and have since been modifying my Windows Source
- product to disassemble PE files.)
-
- So there's a lot of interesting stuff in NT. And Microsoft actually
- seems to look _favorably_ on an Undocumented NT book. This way, they don't
- have to document it!
-
- There's just one problem: to do a book like UndocDOS or UndocWin or
- UndocNT takes a long time. Basically, it's not worth doing such a book
- unless you're going to sell a lot of copies. And I do not think that NT
- anything is going to sell a lot of copies for a few years. To me, the
- whole thing is reminiscent of OS/2 in a lot of ways. (In a lots of ways,
- it's not reminiscent of OS/2 of course: Microsoft has clearly learned a
- lot of lessons, but I think it's also repeating some of the same mistakes.)
- Me, I'm putting my money on Win32s rather than NT. I told one of the guys
- at Microsoft that I would start working on it after they sold a million
- copies of NT. I'm not holding my breath.
-
- In looking over this letter, I realize that the phrases "money" and
- "sell" keep appearing. This must say something about me. :-)
-
- Regards,
- Andrew
-
- [Thanks for the kind review of WPJ, Andrew, and the tip on "Windows
- Internals" - I look forward to reading it. -Mike]
-
-
-
-
-
-
-
-
- Date: 10-Jan-93 03:22 EST
- From: Alex Fedorov [72400,274]
- Subj: WPJ
-
- Mike--
-
- Here is Alex Fedorov from Moscow, Russia. Yesterday I downloaded the
- 1st issue of WPJ. This is great! I've a whole set of Peter's previous
- magazine - Pascal News Letter. I liked it. I'm working as an editor for our
- "Computer Press" magazine - the most popular computer magazine here. Before
- that I've worked as tech support person for Borland Pascal for one of its
- distributors here. Reading WPJ.INI section, I've realized that you are
- looking for authors. I would like to offer a set of articles, dedicated to
- changes in Windows 3.1 - new DLLs, concepts and APIs from Turbo Pascal for
- Windows. These articles were prepared for publication here and can be
- translated in a short time. The articles cover new kernel API functions,
- TrueType fonts, OLE/DDEML, COMMDLG, Drag and Drop, VER and TOOLHELP
- libraries. Beside the texts, there is plenty of examples, which can be
- used like small utilities.
-
- Please let me know if this is interesting for beginner/intermediate
- section of WPJ. Also, I've plenty of hacks for advanced users.
-
- Let me know if you need more
- information.
-
- Sincerely, Alex
-
- [Glad you liked the 1st issue, Alex. Hope the rest go over as well. We've
- included your first article in this issue and plan to include more in
- future issues. -Mike]
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Install Program Part II: File Decompression
- By Pete Davis
-
- Well, I don't know where my head's been, but I think I found it. Last
- time I was discussing how much I was dreading coming up with a
- decompression algorithm and it occurred to me that I don't need to. The
- LZEXPAND.DLL has all the routines we need for decompression. I was still in
- the Windows 3.0 mindset. When I did my first install program the
- LZEXPAND.DLL wasn't available to me, so I didn't even consider it last
- month. Several of you mentioned this to me also. In retrospect, it seems so
- obvious. Oh well.... You should also read Alex Fedorov's article on using
- LZEXPAND under Turbo Pascal in this issue.
-
- Ok, so for those of you that don't know, LZEXPAND.DLL is a set of file
- decompression routines supplied with Windows 3.1. Because I want to
- maintain 3.0 compatibility (a bad habit I pick up from work, I guess) I am
- supplying the LZEXPAND.DLL file with this issue.
-
- This article isn't going to be too long because, thanks to Microsoft,
- the LZEXPAND.DLL takes all the work out of file decompression. They make it
- as easy as opening, reading, and closing a file.
-
- One feature we're going to have in our program is two of those nifty
- little progress bars that shows us how far we are through our installation.
- One is going to show progress for the entire installation. The other is
- going to handle progress for the current file. This is where we run into a
- bit of a problem. In the past I used the .ZIP format and that kept the
- total uncompressed file size internally so I could figure out how many
- bytes the file was going to be uncompressed at run-time. I have been unable
- to find a way to do that with the LZEXPAND.DLL so we're going to have that
- in our SETUP.INF file.
-
- Let me run off on a little tangent here and explain the SETUP.INF. The
- SETUP.INF is going to be the file that makes our installation program
- generic. The SETUP.INF file is going to keep information like the name of
- the Application group, the default destination directory, whether certain
- files will go into sub-directories within the application directory, how
- large each file is un-compressed, what the compressed filename is on the
- installation diskette and so on and so on. We're also going to break the
- rules a bit. I mentioned earlier the trouble that Mike got into with his
- article about doing Global linked lists. Well, we're going to use his 'bad'
- example and in this case, I believe I can justify it. First of all, an
- install program has, in this programmer's mind, every right to hog up the
- CPU. (Just try to run another program while the floppy drive's busy
- anyway.) Second, it's going to be playing around with Program Manager, and
- when that's going on, you don't want the user clicking around everywhere
- and screwing up the installation, so, we're going to hog up the CPU. That
- means that whatever global memory is there is ours for the taking and gosh
- darnit, we're going to take what we want! So, bear with me on our nasty
- little global linked list. (That will be in next months issue).
-
- Well, that little side-track got a little longer than I expected.
- Anyway, back to LZEXPAND. So, we know the uncompressed file size from our
- SETUP.INF. What's left is to get our current progress. That's pretty easy.
- The way it works is that when you read from a compressed file, you have to
- allocate the buffer. That means that if the buffer is, say, 20k, then every
- time 20k of data is decompressed, we have to write out the data in the
- buffer to our uncompressed file on the destination disk. So, all we have to
- do is update our progress bar by 20k and whatever percent of the
- installation that is. The formulas are really simple.
-
-
-
-
-
-
-
-
- The commands we're going to be concerned about are: LZInit,
- GetExpandedName, LZRead, and LZClose.
-
- The LZInit function essentially allocates memory for the decompression
- algorithm and initializes some data that the algorithm uses. The prototype
- is:
-
- HFILE LZInit(HFILE SrcFile)
-
- SrcFile is the file handle received from a regular OpenFile function
- call. We use this handle only for the LZInit, but we keep the file open
- until the end of our decompression. If the return value from LZInit is the
- same as SrcFile, then that means our file isn't compressed. If the return
- value is greater than 0, then it is a special file handle for our
- compressed file. If the return value is less than 0, then we have an error.
-
- After we do the LZInit, we have to do a GetExpandedName to get the
- filename of our file as it was prior to being compressed. We'll use this
- filename when we open the output file to write the uncompressed version of
- the file. The prototype for the GetExpandedName is:
-
- int GetExpandedName(LPCSTR lpszSource, LPSTR lpszBuffer);
-
- lpszSource is a pointer to the string that has the filename of the
- compressed file. lpszBuffer will have the name of the file prior to it's
- compression. This is the filename that we will use when writing the file
- back. The return value is TRUE if successful.
-
- After that, of course, is the LZRead which, again (isn't this just the
- most bizarre thing) is a lot like the _lread function. It's prototype:
-
- int LZRead(HFILE hf, void FAR* lpvBuf, int cb);
-
- hf is the file handle we returned from the LZInit. lpvBuf is our
- buffer to hold the data we read. cb is the number of bytes read from the
- file. This is the number we'll use to write the data out to our output
- file.
-
- Last, but not least, the LZClose. It's simply:
-
- void LZClose(HFILE hf);
-
- where hf is the file handle to close.
-
- That's about all we need. It's pretty simple. There are other LZ
- commands and maybe at some point I'll have a discussion of the entire
- library of commands. At this point, though, it's confession time. I must
- admit I have no code to go with this article this month. Fear not, it will
- be in next months issue. I'm hoping to wrap up the entire thing in next
- months issue, and with several other people helping out in next months
- issue, that just might be possible. Anyway, until then, mer i beaucoup et
- au r voir. (Just trying to be a little international there.)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Programming a Drag&Drop Server for Windows 3.1 with TPW
- by Andreas Furrer
-
- Last issue I explained how to implement a client for Drag&Drop with
- File Manager. This was easy because it is well documented by Microsoft. But
- now, what if we want to be the server for Drag&Drop (e.g. if you want to
- program your own file manager)?
-
- There is no documentation from Microsoft for this, so the following
- can change with the next version of Windows.
-
- The first we have to do is capturing the mouse. This is done by
-
- SetCapture(HWindow);
-
- where HWindow is the handle of the window that should receive the mouse
- messages. Now we will receive WM_MouseMove messages every time the mouse is
- moved even if the mouse is not in your client window.
-
- If the mouse was moved, we have to detect if the window at the point
- of the cursor is registered to accept dropped files.
-
- So we have to process WM_MOUSEMOVE messages:
- 1) You can get the current position of the cursor when the message was
- sent by:
-
- Point.X := LoWord(GetMessagePos);
- Point.Y := HiWord(GetMessagePos);
-
- 2) Now we can get the window at this Point:
-
- DragWnd := WindowFromPoint(Point);
-
- 3) To check if the DragWnd is registered to accept dropped files we have
- to check if the window has the exStyle ws_Ex_AcceptFiles. If the Style is
- set, we will set the cursor to a cross, if not we will set the standard
- cursor:
-
- if GetWindowLong(DragWnd,gwl_ExStyle) and ws_Ex_AcceptFiles =
- ws_Ex_AcceptFiles then
- SetCursor(LoadCursor(0,idc_Cross))
- else
- SetCursor(LoadCursor(0,idc_Arrow));
-
- ws_Ex_AcceptFiles has a value of $00000010;
-
-
- Now if the mouse button is released we have to release the capture and
- set the default cursor with
-
- ReleaseCapture;
- SetCursor(LoadCursor(0,idc_Arrow));
-
- Get the DropWnd under the cursor (see above) and if the window under
- the mouse is a D&D window (see above) we have to post a wm_DropFiles
- message to it. But in this message we have to set wParam to a handle with a
- Drag&Drop structure and the format of this structure is not documented.
-
- I found out that the structure looks like this:
-
-
-
-
-
-
-
-
-
- type PDragDropStruct =^TDragDropStruct;
- TDragDropStruct = record
- DataOffset : word;
- DropPoint : TPoint;
- DropInNonClient : bool;
- Data : array[0..0] of char;
- end;
-
- The meanings of the parts of this structure are:
- 1) DataOffset :
- This is the offset where the filenames begin.
- 2) DropPoint
- This is the point where the mouse was released.
- The coordinates are client coordinates.
- 3) DropInNonClient
- This flag is set if the mouse was released in the non-client area
- of the window (e.g., title bar).
- 4) Data
- Here is the beginning of the data. All filenames are separated by a
- chr(0) and the end of this list is terminated by another chr(0).
-
- Now we have to do the following:
- 1) Allocate memory for the Drag&Drop structure
- 2) Lock the memory
- 3) Set the data
- 4) Unlock the memory
- 5) Use the Handle to the memory as wParam
-
- For example we want to have 3 files in the Drag&Drop structure
-
- const s : array[1..3,0..255] of char=('C:\autoexec.bat',
- 'C:\config.sys',
- 'C:\dos\command.com');
-
- We have to compute the length of all the strings
-
- l := 0;
- for i := 1 to 3 do
- l := l+ StrLen(s[i]);
-
- and have to allocate memory for the whole structure. The memory must be of
- the type gmem_DDEShare.
-
- DataHandle := GlobalAlloc(gmem_DDEShare,sizeof(TDragDropStruct)+l);
-
- To set the data we lock the memory
-
- DataPtr := GlobalLock(DataHandle);
-
- and fill the fields of the structure:
-
- with PDragDropStruct(DataPtr)^ do begin
- DataOffset:=Data-DataPtr;
- DropInNonClient:=(
- DefWindowProc(DropWnd,wm_NCHitTest,0,longint(Point))<>htClient);
- ScreenToClient(DropWnd,Point);
- DropPoint :=Point;
- end;
-
- where
-
-
-
-
-
-
-
-
- DefWindowProc(DropWnd,wm_NCHitTest,0,longint(Point))<>htClient
-
- will test if the cursor is not in the client area of the window.
-
- The last data we have to set are the filenames. We do this with a pointer
- p. Initially we set p to the field data of the structure.
-
- p:=PDragDropStruct(DataPtr)^.Data;
-
- Now we copy each string to p and set p at the end of the string plus one
- (StrLen will not compute the chr(0)).
-
- for i:=1 to 3 do begin
- StrCopy(p,s[i]);
- p:=p+StrLen(s[i])+1;
- end;
-
- If we have copied all strings we have to terminate the list with a chr(0)
-
- p^:=#0;
-
- At the end we have to unlock the memory with
-
- GlobalUnlock(DataHandle);
-
- and post the wm_DropFiles message to the DropWnd:
-
- PostMessage(DropWnd,wm_DropFiles,DataHandle,0);
-
-
- The file D&DSER.PAS is a simple Drag&Drop server. Just press the left mouse
- button in the client area and move it to the window of a Drag&Drop client
- (e.g D&DCLI, see below) and release the button. While moving the mouse the
- cursor will change to a cross, if the window under the cursor is a
- Drag&Drop client.
-
- D&DCLI.PAS is an implementation of a simple Drag&Drop client. It
- will print out the dropped files in a WinCrt window. It is nearly
- the same code as the trash can in the last issue.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- C++ Beginner's Column
- By Mike Wallace
-
- I promised in the last issue I would start a beginner's column on C++,
- and I didn't want to lie to you. I have been reading some books lately on
- C++ because I don't know anything about it. My plan is to learn enough to
- write a "Hello world" program in C++ for Windows (for starters), gradually
- move on to more advanced programs and try to share with you everything I
- learn along the way. Hope this suits you because it's the best way I can
- think of to approach this. If you have any suggestions/complaints please
- don't hesitate to let me know. We have a ways to go before we can start
- coding so be patient for now. This stuff can be a little bizarre, so I'll
- try to explain it as best I can.
-
- I've been programming for about 10 years and have become pretty
- comfortable with Pascal, C, COBOL, FORTRAN, BASIC and the rest of the most
- popular languages, and I've noticed they have a lot of similarities when it
- comes to program structure, data abstraction, etc. If you already know how
- to program and now want to learn C++, forget everything you've learned. If
- you've never programmed before, then you're a step ahead of the rest of us.
- C++ is unlike anything I've seen - it's a whole new approach to
- programming. The best book I've seen on the subject is Borland's excellent
- "Object-Oriented Programming Guide" that came with Turbo Pascal 5.5. I
- hope this guide is still packaged with the latest version of TP - chapter
- one is a great read and helped clear up some of the more mystifying aspects
- of OOP for me.
-
- OOP is something like the sound of one hand clapping - if you don't
- think about it too hard and ignore what you already know, it's easy to
- imagine. Consider an apple. In abstract terms, it's just an object, and
- like any object, it is described by its physical properties (an apple has
- to have weight, for example). Think of these properties as functions of
- the object. It is important to keep in mind that we're not talking about a
- specific apple, but any apple that ever existed. The function describing,
- say, the weight, stays the same - only the values going into the function
- differ. So, the nature of an apple is intertwined with the functions
- describing it - they can be encapsulated to form an object. This is an
- important concept in OOP. "Encapsulation" refers to combining a record
- with the code that manipulates it to form an object.
-
- Let's move on to an example closer related to programming: drawing
- graphics. If we wanted to write a program for drawing lines, circles,
- etc., we could start with defining an object called Point, which has as
- three fields: x coordinate (integer), y coordinate (integer) and on/off
- (boolean). The first two fields give the location of Point and the third
- says if it is displayed (on) or not (off). If we wanted to extend our
- program to include circles, we could a define a new object called Circle
- that had the same fields as Point plus a field for the radius (x and y
- would be the center of the circle). To save time, we could declare Circle
- as an object of type Point with another field for the radius. Circle is a
- descendent of Point because Circle has inherited the properties of Point.
- This is another concept important to understanding OOP. "Inheritance"
- refers to defining an object and using it as a basis for defining
- descendent objects, with each descendent inheriting access to all its
- ancestors' code and data.
-
- Finally, let's say you want to write a routine for drawing a Point and
- another for a Circle. Although the two routines would be implemented
- differently, they're both doing nothing more than showing an object. In
- C++, it is possible to declare two routines with the same name, and here we
-
-
-
-
-
-
-
-
- could do it with the routine "Show." The difference between the two is
- that one would be tied to the object Point and the other would be tied to
- Circle. This is called "polymorphism", and is giving an action (here,
- showing an arbitrary object) a single name (e.g., "Show") that is used by
- different objects in the hierarchy , with each object implementing the
- action in a manner suited to that object.
-
- Well, that's all for this month. I've stayed away from code here
- because it's too early to start with it. C++ is too different than, say,
- C, to jump into code, I think [that's his way of saying he hasn't gotten
- that far either - Pete]. I hope this makes sense so far. If you're
- thinking, "I never did this with Pascal", then you're starting to get the
- point. It's not just a computer language - it's a way of programming that
- reflects the way we think, much more so than C, for example. Don't think
- too hard about it and it should make more sense than what you already know
- about programming. If none of this makes sense, drop me a line and I'll
- see what I can do.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Beginner's Column
- By Mike Wallace and Pete Davis
-
- Last month we covered the .DEF file and started on resources by
- describing dialog boxes. This month we'll finish the .RC file by
- explaining menus, and then begin on the C code for our "Hello World"
- program.
- A Windows program isn't a Windows program without a menu. It's
- probably the first thing you look for when you're running a Windows app.
- If you've wondered how to create one yourself, you've come to the right
- place. You describe your menu in the .RC file using the following format:
-
- <menu-name> MENU
- BEGIN
- POPUP "<popup menu>",
- BEGIN
- MENUITEM "<menu item 1>", <variable>[, options]
- END
- MENUITEM "<menu bar item>", <variable>[, options]
- END
-
- You can have as many menu items as you want (or will fit on the menu
- bar), and even have popup menus inside other popup menus if you want. I
- kept the format simple so it wouldn't be overwhelming. Here's the
- explanation for the codes: anything inside "<>" is required, and anything
- inside "[]" is optional. You have to give your menu a name. You can put
- the POPUPs and MENUITEMs in any order you want, but don't forget the
- BEGIN/END statements that go right after the POPUP statement. Any MENUITEM
- inside the BEGIN/END appears under that popup menu. MENUITEMs that appear
- outside the BEGIN/END of a popup menu appear on the menu bar, but they
- won't have a menu under them. For each menu item, you should give it a
- variable (defined in a .H file included in the .RC file) that you'll use
- when your program checks for which menu item was selected by the user. For
- any menu item, you can include the following options:
-
- CHECKED - The menu item has a check next to it
-
- GRAYED - The menu item text is grayed and inactive
-
- HELP - The item has a vertical line to the left. You can also include
- a "\a" at
- the beginning of the text if you want to item to appear on the
- menu
- bar's far right side.
-
- INACTIVE - The menu item name is displayed but cannot be activated.
-
- MENUBARBREAK - When used on a menu, the item is placed on a new line. On
- popups, the item is placed in a new column. A line separates
- this
- item from the previous one.
-
- MENUBREAK - Same as MENUBARBREAK, except for popup menus : no dividing
- line.
-
-
- A couple of more hints: If you want to make a character in a menu item name
- underscored (to allow for ALT-whatever), add an "&" before the character in
- the name. Also, you can add the line "MENUITEM SEPARATOR" to add a
- horizontal line between popup menu bar items.
-
-
-
-
-
-
-
-
- We're now ready to write the .RC file for "Hello World". Here it is:
-
- /* hello.rc */
- #include <windows.h>
- #include <hello.h>
- amenu MENU
- BEGIN
- POPUP "&Text"
- BEGIN
- MENUITEM "&Write", IDM_WRITE
- END
- MENUITEM "&Quit", IDM_QUIT
- MENUITEM "\a&Help", IDM_HELP, INACTIVE
- END
-
-
- Here's "hello.h":
- /* hello.h */
- /* define menu bar items */
- #define IDM_WRITE 1
- #define IDM_QUIT 5
- #define IDM_HELP 10
-
- /* function prototypes */
- Long FAR PASCAL MainWndProc (HWND, unsigned, WORD, LONG);
-
-
- The "windows.h" file is included with the Microsoft Windows SDK, and is
- required for any Windows program. The above two files will change as our
- program grows, but it should suit our needs for now. We'll describe any
- changes we make to any file we've already created. Here's Pete to tell you
- about the C code.
-
- Ok, so I guess it's my turn to talk about the coding of this thing.
- This is a real bread and water Windows program, but it's got all the basics
- that you're going to find in all Windows programs, and that's what you need
- at this point.
-
- In a normal C program you have your main() function which is the first
- function to get called in a C program. In Windows, instead of main(), you
- have WinMain(). (Real original, eh?) The WinMain function is where you take
- care of all the initialization. The main things you want to do is register
- your window class. Now, this makes it sound like object oriented stuff all
- of a sudden, and I suppose it is, but all you're really doing is telling
- Windows a few things about your window. (You have to keep in mind that
- Windows is essentially an object oriented operating system. Although our
- programming isn't object oriented, per se, we are emulating an object
- oriented programming environment.)
-
- Instead of showing the Window Class structure here, I'll just discuss
- it. I've labeled the members of the structure in the code, so you'll be
- able to relate what I write here to the structure members in the code.
-
- The hCursor is basically done by a load cursor. Most applications jut
- choose the generic IDC_ARROW cursor.
-
- The hIcon is where you really get to have fun. This is the icon that
- is shown when your application is minimized.
-
- The hInstance is simply the instance for this application.
-
-
-
-
-
-
-
-
- The hbrBackground is the class of the background brush, meaning,
- basically, the color or pattern used in your window. This is usually white.
-
- lpszMenuName is a pointer to a null-terminated string which has the
- resource name of your menu.
-
- style has several options, most of which are a little more than we
- need to go into at this point. My suggestion is use CD_HREDRAW |
- CS_VREDRAW. This basically means to redraw the window if the horizontal or
- vertical window sizes change.
-
- The cbClsExtra and cbWndExtra are a bit more complex than we should be
- going into at this point, so like so many other things, we'll hold them off
- for another day. Just keep them NULL for now.
-
- After registering your window class, you have to initialize the
- instance. What this means is that in a Windows program, you can run the
- same program several times at once (not all Windows applications, but ones
- that are written to allow it.) Each copy of the program running is called
- an instance. The reason you have to initialize the instance is because,
- each one of those versions is going to share the same copy of code. (You
- don't have to share the code, but it's bad practice not to, so we're not
- going to say any more about that no no.) Also, because handling multiple
- instances of an application can be a bit tricky for the beginner, we're
- going to set up our code to reject attempts to run multiple instances.
-
- At the end of all of this you set up your message queue. This is
- fairly simple to do and fairly generic. Most programs do this the same way.
- There are reasons for changing it, sometimes, but we're not going to get
- into that either, at this point.
-
- When you initialize the instance, you also tell Windows what the
- procedure is that is going to handle the messages for your main Window.
- Here's where the multi-tasking of Windows takes place. See, what Windows
- does here is that every time something happens in your window, Windows
- calls this procedure and passes along a message describing what happened.
- This could be something like a mouse movement, a menu selection, etc...
- See, you never explicitly call the procedure that handles your main window,
- what you do is tell Windows where the procedure is and it will know when to
- call it.
-
- The best way to handle your main window procedure is to setup a
- switch/case structure where each case of your switch statement handles a
- different message.
-
- example:
- /* Switch structure for message */
- switch(message) {
-
- case WM_CREATE:
- ....
- ....
- ....
- break;
-
- case WM_Another_Message:
- ....
- ....
- ....
- break;
-
-
-
-
-
-
-
-
- etc...
-
-
- Windows messages generally start with WM_. The WM meaning Windows
- Message, oddly enough. After each case would be the code to handle whatever
- that action requires. For example, the WM_CREATE message is called right
- before a window (or dialog box for that matter) is created, so it's a good
- candidate for initializing variables and that kind of stuff that you want
- to do every time your window is created.
-
- A little side note here: There are two types of dialog boxes, Modal
- and Modeless (Yes, one is al and the other is el). The Modal dialog boxes
- are very similar to windows in that they are given a procedure that handles
- messages that are passed to them. (We'll discuss Modal dialog boxes at a
- later time also. One thing at a time.)
-
- I digress... Anyway, the break after each case statement is just a
- quick way out of the switch/case structure. It basically means that you're
- done handling that particular message.
-
- Ok, so what are we learning here? Well, Windows programs aren't linear
- in the sense that you run a procedure which may run another procedure and
- so on. Windows is event driven which means that it reacts to events that
- take place. When you move the mouse, that's an event, so your procedure
- gets called. When you hit a mouse button, that's another event, but the
- same procedure gets called. This procedure should respond differently
- depending on the message it receives.
-
- That should be all you need. I've included the Hello World code and
- I've put as much inline documentation as will make sense. I suggest you
- give it a whirl, and like any of our articles, if you have questions, let
- us know. If we've inadvertently skipped something, send us a message and
- we'll amend our goofs.
-
- Next month you'll have Dave Campbell coming to you directly from
- Arizona. He's a hell of a programmer, so he'll have lots to show you and
- hopefully, give you a little different perspective than Mike and I, that
- way if you don't understand what we're saying, maybe you'll understand it
- when Dave says it. So, so long and thanks for reading. Hope you'll treat
- Dave as well as you've treated us.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Using LZExpand Library
- Alex Fedorov
-
- LZEXPAND.DLL is supplied with Windows to allow programmers to unpack
- files, previously packed with COMPRESS.EXE utility. Here we will look at
- the main functions of this library. Note, that you can use EXPAND.EXE
- utility to unpack files instead of using functions from LZEXPAND library.
- Mostly, this library is used for installation programs. (This article is
- intended for TPW programmers).
-
-
- Data compression
-
- Data compression is a task to lower the file size by converting the
- repeated data with some other sequences. In text files such repeated data
- can be spaces, mostly used chars or even the whole strings. Due the
- compression such repeated sequences are replaced with the shorter one.
- Several data compression algorithms exist. One of the most popular is the
- Huffman algorithm, based on the frequencies of chars repetitions in text.
- Another one is a run-length encoding algorithm, where the repeated chars
- are replaced by pairs: the first nibble contains the count of repetitions
- and the second one the char code itself. Also, the Lempel-Ziv algorithm is
- widely used and the COMPRESS.EXE utility is based on it.
-
-
- Data expansion
-
- Applications use functions from LZEXPAND.DLL to unpack files,
- compressed with COMPRESS.EXE utility. Here is the actions flow to expand
- one or more files.
-
- Unpacking one file:
-
- ~ Open a compressed file with LZOpenFile. Also,
- the file can be opened with OpenFile or LZInit
- functions.
-
- ~ Open a destination file using LZOpenFile or
- OpenFile functions.
-
- ~ Use LZCopy to copy data from source to
- destination using file handles from LZOpenFile
- or LZInit.
-
- ~ Close both files with LZClose.
-
-
- Unpacking several files:
-
- To unpack several files you perform the following actions:
-
- ~ Open source file with LZOpenFile or with
- OpenFile and LZInit functions.
-
- ~ Open destination file using LZOpenFile or
- OpenFile functions.
-
- ~ Allocate memory for copy operations with
- LZStart function.
-
-
-
-
-
-
-
-
-
- ~ Use CopyLZFile to copy source file to destination
- file.
-
- ~ Free allocated memory with LZDone function.
-
- ~ Close all files with LZClose function.
-
-
- Reading data from compressed files
-
- Instead of unpacking the whole file, an application can unpack file
- piece-by-piece, using LZSeek and LZRead functions. These functions can be
- useful when we unpack the huge files.
-
- To use the functions from LZEXPAND.DLL you need the unit LZEXPAND.TPU
- which is supplied with Turbo Pascal for Windows 1.5 or with Borland Pascal
- for Windows.
-
- Here is the example of how to use LZEXPAND.DLL functions
-
- { LZDEMO - The demo of LZEXPAND.DLL functions usage }
-
- uses LZExpand,WinTypes,WinProcs;
-
- Const
- szSrc = 'MYFILE.PAK'; {Packed file name}
- Var
- szFileName : Array[0..127] of Char;
- ofStrSrc : TOfStruct;
- ofStrDest : TOfStruct;
- hSrcFile : THandle;
- hDstFile : THandle;
- Total : LongInt;
-
- Begin
- {Open compressed file}
- hSrcFile := LZOpenFile(szSrc,OfStrSrc,of_Read);
-
- {Get the original name of file}
- GetExpandedName(szSrc,szFileName);
-
- {Create the file with szFileName}
- hDstFile := LZOpenFile(szFileName,ofStrDest,of_Create);
-
- {Unpack file while copying it}
- Total := LZCopy(hSrcFile,hDstFile);
- {LZCopy returns the number of bytes written}
-
- {Close both files}
- LZClose(hSrcFile);
- LZClose(hDstFile);
-
- End.
-
- Note: In the example above, we used the LZOpenFile function, which
- automatically calls LZInit function, which performs some initialization.
- The result code of this function can tell us whether or not the file was
- compressed with COMPRESS.EXE. To do this, you need to open the file with
- the OpenFile function (from KERNEL) and then call LZInit directly, giving
- it the file handle from OpenFile. LZInit returns the file handle. If the
-
-
-
-
-
-
-
-
- value for this handle is not the same as the argument, the file was
- compressed and we can unpack it. Here is the example:
-
- hSrcFile := OpenFile(szSrc,ofStrSrc,of_Read);
- hCompFile := LZInit(hSrcFile);
- If hCompFile <> hSrcFile then
-
- {File was compressed with COMPRESS.EXE}
-
- Else If hCompFile = hSrcFile then
-
- {File was not compressed}
-
- Else
-
- {Some error encountered; must check LZError_XXX codes}
-
-
- Also note, the GetExpandedName function returns the original name only
- when the file was compressed by COMPRES.EXE with /r option.
-
-
- Alex is a freelance programmer
- and the editor for "Computer Press"
- magazine. Alex lives in Moscow, Russia.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Implementing A Linked List - Revisited
- By Mike Wallace
-
- I didn't expect this to happen. I have caused a small uproar by last
- month's article "Implementing a Linked List Using the Global Heap."
- Several people had differing opinions on the best way to do this, and two
- of them have promised articles showing two different ways to do this, which
- we hope to publish soon. Part of it was my fault: at the end of the
- article, I intended to mention that it was very easy to alter the program
- to use the local heap (instead of the global heap) - all you need to do is
- change the Global commands (e.g., GlobalAlloc) to Local commands (e.g.,
- LocalAlloc) and the FAR pointers to NEAR. I arbitrarily chose the global
- heap for the program, and several people pointed out (and for good reasons)
- that it's always better to use the local heap if at all possible. Hope I
- haven't confused anybody. In case anyone is interested in using the method
- I proposed last month, then I have bad news: there was a bug in last
- month's code involving freeing the memory blocks. I have included a
- revised version of the program with this issue.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- An Introductory Look at DLLs and The Use of Make Files
- By Rod Haxton
-
- Whenever one begins learning Windows he/she always seems to hear talk
- about DLLs (Dynamic Link Libraries). Learning Windows is a very long
- process. Like anything in the programming world there's lots to learn, and
- not that much time to learn it in. Thus, many beginning Windows programmers
- bypass Petzold's chapter on DLLs until a later time. This article may not
- be of great help in understanding DLLs for Windows programmers just getting
- their feet wet. But, if you have been writing code for Windows and feel
- competent, and have not yet tackled DLLs, this code may give you a little
- understanding of how DLLs work. Also, if you have some understanding of
- 80x86 assembly language underneath-the-hood workings, this will be useful
- in understanding how DLLs work in Windows. A bonus to this article is that
- it demonstrates how a large application or for that matter any size app
- should be laid out. The programming example accompanying this article shows
- how source code should be broken up into seperate modules. The demo also
- makes use of Make files and shows how they can help speed the development
- of projects, and also demonstrates how to break code up into multiple code
- segments. So often in Windows books the programs demonstrated are built as
- one application with one code and data segment. This isn't really what we
- as developers need.
-
- In learning DLLs there are a few areas that one should focus on to
- gain 'THE KNOWLEDGE'; this conjures up images of some monks sitting around
- reading thick books. Cutting and pasting code samples from on-line articles
- or typing them in will get you something working but, if you do not
- understand what is really going on in Windows you will be held hostage to
- some unknown events and also your own imagination, or the lack thereof.
- Thus, there are some things to focus on when learning about DLLs. They are:
-
- * DS != SS
- * Windows & DLLs entry/exit code
- * Exports & Imports
- * LibEntry & LibMain
- * WEP function
-
-
- DS != SS
- --------
-
- In a regular Windows application program the Stack and Data Segment
- are the same. If you set up your program to have multiple code segments,
- the Code segments can change during Windows function calls, far calls, and
- return from far calls. The changing of the code segments takes place
- because most code segments are flagged as moveable and discardable. If the
- code segment has been flagged as a fixed segment then the code segment will
- stay put. But, in understanding DLLs you need to concentrate on DS and SS.
- As I mentioned, in regular Windows apps DS == SS. Standard C routines can
- be used in non-DLL apps. They do not assume DS == SS, and generally
- reference pointer variables relative to DS. Remember, when functions are
- called a stack frame is created, which holds the passed variables, the
- returning CS:IP address, and space is created to hold any local variables
- to the routine. Thus, references to your passed-in near pointer variables
- are seen by the stack, because C does not make a distinction between stack
- segment-based variables and data segment-based variables.
-
- DLLs on the other hand have their own data segments. This is one of
- the reasons that makes them appealing to those developers writing big
- applications. When a routine to a DLL is called, the calling function's, if
-
-
-
-
-
-
-
-
- its not in the DLL, DS and CS are placed on the stack. The DLL uses the
- stack of the calling function. The DLL's DS and CS are given scope. Thus,
- the calling app (if passing any variables to the DLL) must pass them as far
- pointers in order for the variables to have scope. Also, standard C
- routines cannot be used, because DS != SS, and the standard library
- routines reference the variables from DS. If you do call a standard C
- routine or another DLL's function with near pointers, when the function
- returns the variables will be unchanged. Ways to get around this problem
- are to declare your local variables in your DLL as static or pass them as
- far pointers.
-
-
- APP DLL
- --------------- ---------------
- | | | |
- | CS | | CS |
- --------------- ---------------
- DS DS
-
- SHARED
- SS------------------------------------------------SS
-
-
- A detailed discussion of DS != SS can be found in Charles Petzold's
- 'Programming Windows', and Mike Klein's 'DLLs And Memory Management'. A
- step to really comprehending DLLs is to understand DS != SS.
-
-
-
- Windows & DLLs Entry/Exit Code
- ------------------------------
-
- Another aspect of understanding DLLs is to understand how Windows
- loads application functions and DLLs. Again, here a little understanding of
- how a MS-DOS C compiler handles function loading and assembly language can
- be helpful. Now, if you do not happen to be a low-level system person
- and/or have no desire to be, you may be asking yourself why this is
- important. Well, this really isn't important if you don't mind writing code
- and not understanding what's really taking place. But remember, you will be
- at a real disadvantage when a bug crops up and you go into your debugger to
- find out what is wrong and you have no idea of what you're looking for.
-
- Under DOS the compiler sets up segments as the following:
-
- mov ax, _DATA
- mov ds, ax
-
- And, function entry/exit code saves registers and makes space on the stack
- for passed variables and local variables,
-
- push bp
- mov bp, sp
- sub sp, <number of bytes needed>
- .
- .
- .
- mov sp, bp
- pop bp
- ret ;This can be a near or far return. Also, if
- ;the function was called with the PASCAL
-
-
-
-
-
-
-
-
- ;directive the number of parameters passed
- ;to the stack needs to be added to the
- ;return.
-
- Windows functions are all set up to be far calls. This provides the
- built-in ability to swap and discard code segments in and out of memory.
- The entry exit code for the non-exported far functions looks like the
- following:
-
- push ds -----------------------| same as:
- pop ax -----------------------| mov ax, ds
- nop
- inc bp
- push bp
- mov bp, sp
- push ds ---------------------- save ds again?
- mov ds, ax ---------------------- here again ?
- sub sp, <number of bytes>
- .
- .
- .
- dec bp
- dec bp
- mov sp, bp
- pop ds
- pop bp
- dec bp
- ret <number of passed parameters>
-
- Looking at the Windows entry/exit code above we see that it is really
- similar to the DOS version. It just does extra work. The reason being is
- that Windows modifies the entry code when your exported function is called.
- Windows replaces the first two instructions ('push ds' and 'pop ax') with
- NOPs. If you noticed the code above where I have stated 'here again?', the
- instruction is 'mov ds, ax'. But, now ax contains nothing. Before it held
- the value of ds. What happens is that during LINK Windows places into EXE
- file a table that lists the references to your far calls and Windows
- functions. Thus, when Windows runs and calls your far function the register
- ax has already been loaded with the segment location. Exported functions DS
- are handled during the registering of window class structures created or
- with the MakeProcInstance for call-back functions. The MakeProcInstance
- tells Windows to do some 'thunking'. Thunking handles the setting up of
- code and data segments. Each instance of a Windows function will have its
- own DS, but all instances will refer to one CS.
-
- Far calls and Window functions entry code:
-
- nop
- nop
- nop
- inc bp
- push bp
- mov bp, sp
- push ds
-
- mov ds, ax---------------->'Instance Thunk' located in
- fixed memory position.
- mov ax, <DS for instance>
-
- sub sp, <number of bytes>
-
-
-
-
-
-
-
-
-
-
- DLLs entry code is as simple as the DOS version. Because DLLs have
- their own DS and there can only be one instance of a DLL there's no need to
- determine the DLL's DS at run time or create an instance thunk. The DS is
- already known so it can be set.
-
- mov ax, <DLL DS>
- inc bp
- push bp
- mov bp, sp
- push ds
- mov ds, ax
-
-
-
- Exports and Imports
- -------------------
-
- You should already know about Exported functions if you have written
- Windows code. But, here's a brief tutorial. All Windows functions that
- receive messages must be exported. The export tells the compiler that
- references to the exported functions will be resolved at run-time.
-
- Imported functions are also used to resolve function references. The
- IMPORTS statement in a DEF file tells the Linker that the functions are
- defined elsewhere and relocation info will be resolved at run-time.
- Imported functions can be handled in two ways. One is to list them in a DEF
- file under the IMPORTS statement. The other is to place them in an import
- library and link them into your code. The latter is the approach that I use
- because it reduces the headache of updating DEF files during development.
- Also, listing the import functions in DEF files requires a lot of
- memorization when you start dealing with multiple DLLs. Later, I will show
- how I handle multiple DLLs and imports.
-
-
- LibEntry and LibMain
- --------------------
-
- Every Windows executable modules needs an entry point. When writing
- apps for Windows this code is hidden from the developer. However, when
- writing DLLs the source to the library entry routine, LibEntry(), is
- provided to you by the SDK. Usually, you do not have to touch this code -
- the SDK provides 'libentry' for you to link into your DLL. 'libentry' is
- the object file for LibEntry(). If you are creating a resource-only DLL you
- do have to modify LibEntry() a little bit. LibEntry() also calls a function
- LibMain() that you must supply.
-
- When the application program starts up all DLLs tied to that app get
- called. The initial call for the DLL is the only guaranteed time that the
- library will be called. LibEntry() initializes the DLL's local heap by
- making a call to LocalInit(). Under Windows 3.0, due to Real Mode support,
- LocalInit() locks the DLL's data segment; the locking of the data segment
- does not take place under Windows 3.1. On exit from LocalInit(), LibEntry()
- calls LibMain(). If the data segment was locked your LibMain() function
- must unlock it.
-
- LibEntry() and LibMain() initialize your DLL and are only called once.
- You will see in my Make and DEF files that I place LibMain() in an
- initialization code segment. This way the segment will be flagged after it
-
-
-
-
-
-
-
-
- is used to be discarded and when memory becomes an issue it will be dumped
- by Windows.
-
-
-
- WEP Function
- --------------
-
- The WEP() routine is another function that your DLL is required to
- have. The SDK says that this function gets called once, when a DLL is about
- to be unloaded. This does not seem to be the case under Windows 3.0. When I
- have watched it under Codeview, I have never seen it called. WEP() has an
- input parameter that identifies whether the exit is being caused by the
- system or the application. Whatever the reason for the exit WEP() should
- return 1. You will notice in my examples that I do not do any testing for
- the type of exit: I just return 1. WEP()'s name is made resident in the
- DLL's name table, thus it is always in memory and never gets swapped out.
-
-
- Programming Example
- -------------------
-
- Now that the basics of DLLs have been discussed. I'll focus the rest
- of this article on a sample DLL app that I've written that demonstrates
- DLLs, the use of Near/Far function calls, Near/Far pointers, calling a
- Dialog Box function located in a DLL, how to create an import library, the
- use of Make files, and how to create multiple code segments.
-
- The following DLL example is called RODSAPP (how appropriate). It's
- comprised of an application program and two DLLs. The app files are
- rodsapp.c, winmain.c, and wndproc.c. The file rodsapp.c contains code for
- creating and initializing the Windows application. The file winmain.c
- handles the Windows message dispatcher. The wndproc.c module is a standard
- Windows function that has a menu bar. The menu bar is the entry into the
- DLLs. The menu items are About, One and Two. Clicking on the About option
- demonstrates a dialog box whose function resides inside a DLL (lib2a.c).
- Clicking on menu option One causes a call to the testlib.dll (testlib.c).
-
- The function StepOne inside testlib.dll demonstrates variables that
- are referenced from DS and SS. I've provided total explanations inside the
- source so that understanding would be easier.
-
- Clicking on menu option Two also makes a call to testlib.dll that in
- turn calls the DLL lib2.c. The calls inside these DLLs also demonstrates
- what happens to variables that are referenced from DS and SS.
-
- The Make file used with the program compiles with the Codeview
- debugger options set. I suggest that you run the program under Codeview a
- few times and keep an eye on the DS and SS registers. Also, watch the
- variables inside routines and note their addresses and watch what happens
- to those variables addresses when you step into a routine inside a DLL.
-
- Along with the source files is a batch program DOALL.BAT. It runs all
- the Make files and dumps any warning or error messages out to a file named
- peek.
-
- Also, the Make file LIB.MAK creates an import library 'test.lib'. This
- Make file should be run first in order to create the import library that
- will be linked into the DLLs. Changes to the DEF files will re-make LIB.MAK
- but the *.dll files must be deleted and re-linked with the new import
-
-
-
-
-
-
-
-
- library.
-
-
- Make File Explanation
- ---------------------
-
- The following is a snippet of the rodsapp.mak Make file; note that the
- following statements that begin with '*' do not appear in the actual Make
- file.
-
- TMPDRIVE=c:\tmp
-
- WLIB=libw mlibcew *sets up a macro for the libraries that
- *will be used during linking
-
- IMPLIBS=test *the DLLs import library (see next
- *section for how this library was
- *created).
-
-
- * object code of the modules used in RODSAPP.EXE
- OBJ=rodsapp.obj winmain.obj wndproc.obj
-
- * compiler option flags; a detailed meaning found in source
- CFLAGS=cl /c /AM /D LINT_ARGS /Gws /W3 /Zip /Od /nologo
-
- # Update the executable file if necessary, and if so, add the
- # resource back in. The /NOE must be included when linking with
- # Windows libraries.
-
- rodsapp.exe: $(OBJ) rodsapp.res rodsapp.def
- del $(TMPDRIVE)lk.res
- echo $(OBJ)>>$(TMPDRIVE)lk.res
- echo rodsapp.exe/align:16>>$(TMPDRIVE)lk.res
- echo rodsapp.map/map/NOD/CO/LI>>$(TMPDRIVE)lk.res
- echo $(WLIB) $(IMPLIBS)>>$(TMPDRIVE)lk.res
- echo rodsapp.def>>$(TMPDRIVE)lk.res
- link @$(TMPDRIVE)lk.res
- rc rodsapp.res
-
- # Update the object file if necessary
-
- * The following demonstrates how to seperate your code into code
- * segments. The -NT allows one to name the code segment. This
- * name is then placed in the modules DEF file under the SEGMENTS
- * statement and given the control flags that you wish the code
- * segment to follow.
-
- rodsapp.obj: rodsapp.c rodsapp.h
- $(CC) $(CFLAGS) -NT Initialization_code rodsapp.c
-
- winmain.obj: winmain.c rodsapp.h
- $(CC) $(CFLAGS) -NT Resident_code winmain.c
-
- wndproc.obj: wndproc.c rodsapp.h testlib.h
- $(CC) $(CFLAGS) -NT Resident_code wndproc.c
-
- # Update the resource if necessary
- rodsapp.res: rodsapp.rc rodsapp.h
- rc -r rodsapp.rc
-
-
-
-
-
-
-
-
-
- DEF File Differences
- ---------------------
-
- The differences between a Windows application definitions file and a
- DLL's is that in the Windows app DEF file there is a NAME statement that
- defines the app's name. A DLL has a LIBRARY statement to do the same thing.
- A DLL does not need a STUB statement since it cannot be launched into
- execution without an application calling it. A DLL also has no STACK
- statement. Since the DLL uses the SS of the calling application it needs
- not define a stack size.
-
-
- Conclusion
- -----------
-
- Things to consider when developing applications and using DLLs. DLLs
- are not magical elements to be used for everything. If you can do something
- fast and it's only going to be used by one application, that is the code
- will never really be used in some future app, stay away from DLLs. DLLs are
- slow. It takes numerous cycles to load DLLs, segment adjustments must be
- made. The DLL far call means that the code and data segments must be
- loaded.
-
- Hopefully this article will help you in your understanding of DLLs. I
- hope that the code samples are clear enough to help you. I tried not to
- give too much code, which can be overwhelming when you are trying to learn
- something, but just enough to represent the makeup of real projects.
-
- There are other topics under DLLs that I did not cover like User
- Resource DLLs and the handling of global data across DLLs. Maybe someone
- else will provide an article on User Resource DLLs in a future article. I
- plan to submit for the next issue of WPJ an article that demonstrates a way
- I figured out to handle global variables across DLLs. Good luck!
-
- Rod Haxton can be contacted @ (703) 883-0226 or (202) 269-3780.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The Windows Help Magician
- By Jim Youngman
-
- Since I do not program for the sake of programming, I am always
- looking for shortcuts. The Windows Help Magician has proven to be one of
- the best. I think it was written in Visual Basic, but don't let that put
- you off it. It's a great little application and a real time saver. The
- files it produces can be compiled with Microsoft or Borland Help Compilers
- for Windows 3.0 or 3.1.
-
- I am writing my first fully fledged Windows program. It is to be used
- mainly by computer illiterate people and so a good Help file will be
- essential.
-
- When I started investigating how to prepare such files I was
- overwhelmed by the prospect: all those control characters that have to be
- inserted! The Windows Help Magician eliminates all of that. Using a well
- designed interface, the program does all of the hard work. All I need to
- do is think out the design of the Help system. The friendly Magician gives
- me a great set of tools for creating the index, browse groups, hypertext
- jumps, popups and keywords. You can also include bitmaps in your help
- files.
-
- So far I have only played about a bit with the product. I am looking
- forward to exploring it further with the real job.
-
-
- The Windows Help Magician is available from the publishers:
-
- Software Interphase Incorporated
- 82 Cucumber Hill Road, Foster, RI 02825, USA
- FAX (401) 397-6814
- BBS (401) 397-4601
-
- There is a fully operational demo disk which is limited to help files
- of 7 pages. The full version allows 200 pages.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The Last Page
- By Mike Wallace
-
- This is too cool. Pete and I hoped a couple of hundred people might
- pick up the first issue of WPJ (Official motto: "It's not just for
- breakfast anymore"). After three weeks on various bulletin boards, we
- counted over a thousand, and that doesn't even include Internet (we have no
- way of tracking the number of downloads there). We've gotten mail and
- articles from such faraway places as Russia, Germany, South America and
- central Jersey. We hope the number of downloads goes up every month; if it
- starts to go down, we're in trouble. From the mail we've received, people
- seem to like it and want to help out. It's been overwhelming. If you're
- thinking of writing an article, don't be shy. Others are doing it. You
- don't have to be a professional writer (we sure aren't), and we can always
- use more articles. If you don't feel up to writing an article, send us a
- message and let us know what you think about the magazine. Does it have
- the putrid stench of rotting eggs? Has it helped your Windows programming?
- Inquiring minds want to know. Remember: this is your magazine as much as
- our's.
-
- The only thing I'm disappointed about is I haven't gotten any mail for
- this column. I really hope you people don't make me write this whole page
- by myself! As much as I wish I could fill this page with poetic prose
- every month, that just ain't gonna happen. What's on your mind? The only
- programmers I know all live in Washington, D.C. (Official driving slogan:
- "Death before yielding"), and here everyone is a government contractor, and
- there's only so much you can talk about with a contractor before things get
- really dull. What are programmers doing in, say, California? Texas?
- Europe? I know you people have something on your mind and you're thinking,
- "If only there was some sort of internationally distributed electronic
- forum for sharing my most personal thoughts with people who will write
- about me in their local newspapers and ban me from ever visiting their
- country..." Well, wonder no more, because now you have your chance. You
- can get your 15 minutes of fame simply by writing anything (and I really
- mean ANYTHING [He means within reason -Pete]) that both piques my interest
- and, most importantly, means I don't have to write as much. What could be
- simpler?
-
- While I'm thinking about it, I want to thank the hard-working sysops
- on CompuServe, and especially in the WINSDK forum. I've flooded these
- people with questions lately and they've been great, and I really hope they
- don't mind if I use their answers in future WPJ articles (ha! ha! just
- kidding!). Seriously, these people really know their stuff and will answer
- any question, no matter how inane (take it from someone who's asked more
- than one inane question). An "Honorable Mention" goes to sysop Tammy
- Steele for her wealth of knowledge and great attitude. Stop by the WPJ
- offices anytime to pick up your official WPJ t-shirt, Tammy.
-
- I'm out of room and out of time. Hope to hear from ya'll soon.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Getting in touch with us:
-
- Right now there are only four ways to get in touch with us. If you
- have access to the Internet or BITNET, you can get in touch with us at:
-
- 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.
-
- As soon as we replace the hard drive, the Windows Programmer's Journal
- BBS can be reached at: (703) 503-3021. You can get in touch with either
- Mike or Pete at this number. The BBS is going to be relatively new, so
- don't be surprised if it's a little buggy in the beginning. Right now it's
- only 2400 baud as my 9600 baud modem died on me, soon you can expect it to
- go up to 14,400. You can also expect to see a Fido-net node address in the
- near future..
-
- In future issues we will be posting addresses of contributors and
- columnists who don't mind you knowing their addresses. We will also contact
- any writers from the first two 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.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-