home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-04-04 | 111.6 KB | 2,788 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 04
- and Mike Wallace Apr 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) 71644,3570 (Pete)
-
- Delphi: PeteDavis
-
- 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
-
- Letters ....................................... 6 Readers
-
- Midlife Crisis: Windows at 32 ................. 9 Pete Davis
-
- Beginner's Column ............................. 14 Dave Campbell
-
- Owner-Drawn List Boxes ........................ 25 Mike Wallace
-
- Beginner's Column for Turbo Pascal for Windows 30 Bill Lenson
-
- Hacker's Gash ................................. 31 Readers
-
- Microsoft's Windows Strategy .................. 34 Pete Davis
-
- Accessing Global Variables Across DLL ......... 38 Rod Haxton
-
- Getting A Piece Of The Future ................. 41 Peter Kropf
-
- The "ClickBar" Application .................... 44 WynApse
-
- Getting in Touch with Us ..................... 45 Pete & Mike
-
- Last Page .................................... 46 Mike Wallace
-
- (If you're wondering where the C++ Beginner's column is, it's because we
- haven't heard from the column's author. We hope to have it next month. See
- WPJ.INI for further explanation.)
-
- 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 Editor ................ Bill Lenson
-
-
- Contributing Writer ................ Rod Haxton
- Contributing Writer ................ Peter Kropf
-
-
-
-
-
-
-
-
- WPJ.INI
- by Pete Davis
-
- Crazy, crazy, crazy. That's the only way to describe how things have
- been lately. Got some good news, some bad news and a bit in-between. First
- of all, I'll pour out some of the bad news.
-
- We've been unable to get in touch with the author of the C++ beginners
- column. This happens sometimes with a magazine like this and it could be
- for any number of reasons. We will continue to try to get in touch with him
- and hopefully have an article for next months issue.
-
- The second piece of not-so-good news is about me and you may think of
- it as good news, depending on your opinion of me. I probably won't be able
- to do quite as much writing for the magazine for the next 7-10 months. I
- will get in at least one article (for the Win 32 column) each month, but
- other than that, I won't be able to do much else. For one thing, I'm going
- to have to cancel the Install program. I'll discuss some points for the
- Install program in a sec. I can't say yet why I won't be able to write as
- much but hopefully, by the next issue, I will be able to tell you what it
- is. Of course, things might not work out, and I'll be writing as much as
- ever for the next 7-10 months. Well, I guess that was cryptic enough. I'll
- discuss it next month.
-
- As for the install program, it looks like I won't be able to continue
- it. I've looked into the question of installing DLLs while the something is
- using them. It seems that Windows'install program puts the files in a
- temporary directory and copies them in before a restart or shutdown of
- Windows. This is what I have been told by several people, including someone
- from Microsoft. I have been through Microsoft's Install code in the past
- and I don't remember seeing anything about that, but I wasn't really
- looking in the right places, in retrospect. I will post this code on the
- WPJ BBS if you're interested.
-
- I would love for someone to pick up the install program and finish it
- off for me. If anyone's interested, please, get in touch with us.
-
- Let's try to get into some good news now. The good news is that we're
- going to be covering Win32 A LOT! This doesn't just mean Windows NT, but
- also Win32s and, eventually, Win32c (won't be released for another year or
- so). This month I'm starting off with some NT and Win32c specific stuff.
- Later I'll going into using the Win32s API to write 32-bit apps for Windows
- 3.1. There's really a lot of promise in the 32-bit application arena and we
- intend on showing you all about it.
-
- We've also got Peter Kropf who will also be doing a Win32 column. Most
- of his is going to be discussing Windows NT so after this month, I'll try
- to leave that to him and I'll move on to Win32s and some less NT-specific
- stuff.
-
- We've got Bill Lenson who will be doing a new column on Turbo Pascal
- for Windows for beginners. We've all been waiting for this, so we're glad
-
- - 4 -
-
-
-
-
-
- to have him aboard.
-
- Rod Haxton is back with a really interesting way to handle Global
- variables in Windows DLLs. As with all these sort of under-the-covers weird
- things, it's not a recommended, it's just a method. DLLs shouldn't use
- Global variables from the main program, but sometimes you don't have much
- of a choice, as Rod will explain.
-
- Well, that's about it for me, just to say that next month I hope to
- have some really good news for all of you. Peace.
-
- Pete Davis
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 5 -
-
-
-
-
-
- Letters
-
- Date: 21-Mar-93 22:07 EST
- From: Eric Fildebrandt [76326,1470]
- Subj: WPJ Format
-
- I have read your past three issues and can't thank you enough. I am
- venturing into the Windows programming environment and need all the
- assistance I can get. As to the format, I really like the WinHelp format.
- It is easily navigated and can be placed in a Program Group in Windows.
- This way it can be used as a reference when programming.
-
- I wonder if you could discuss the best way to change the background color
- of a window since everyone else simply used the default white background
- using GetStockObject. I have tried using CreateSolidBrush and it works
- basically, however, after I close the window, the chosen background color
- remains as the background color for the icons in the Program Manager window
- until that window is somehow refreshed.
-
- I am also interested in knowing how to drag and place bitmaps in a window.
- I am also really confused on how to use the WM_PAINT message to send output
- to the window, especially when that output changes during the run-time of
- the program. Let's take the windows solitaire game as an example. How
- would the WM_PAINT message be used to change the display as each card is
- played, or is it?
-
- Thank you for providing a forum for those of us trying to get acquainted
- with Windows.
-
- Eric Fildebrandt
- Electrical Engineer/Computer Programmer
-
- Editor [P.D.]: Eric, let me see what I can do for you here. I messed around
- with some code that was supposed to be the basis for a solitaire game that
- I was going to write. The world conspired against me and limited a day to
- 24 hours, so I didn't have time to finish it, but here's what I learned. My
- first attempt was to just draw the bitmaps in their locations. When a mouse
- button was pressed, I would check the mouse position. If it was over a
- card, I would pick it up and the move it by BitBlt-ing it with the XOR
- operator so that you could draw it over itself to erase it. This is used in
- moving. You have two positions, old and new. You draw over the old (with
- XOR) and draw in the new position (also with XOR) and your card just moved.
- THIS IS NOT THE RECOMMENDED WAY. This was a disaster and it was a lot
- slower than it had to be.
-
- If I were to go back and do this, my first move would be to place the
- card bitmaps inside of static objects. You could keep track of what the
- mouse is currently above by checking the WM_SETCURSOR message and storing
- the result in a static variable. Then when a WM_LBUTTONDOWN message comes,
- check to see what the cursor was above. For a sample of using the
- WM_SETCURSOR, see WPJV1N3 Hackers Gash, topic #2. I hope this helps. If
- anyone else has some ideas, please send them in.
-
- - 6 -
-
-
-
-
-
- Date: 24-Mar-93 16:15 EST
- From: Francois Bruneau [100113,1156]
- Subj: Adapt the old Memory functions of Turbo C++
-
- I have some code that works with Turbo C++. I don't know how adapt the
- memory functions "memmove","memset","realloc" to the Windows 3.1 Borland
- C++ .
-
- For example I have code about matrix class:
-
- class matrix{
- protected:
- int lgn,col;
- double* coeff;
- void init(int l,int c,double* cf=0);
-
- public:
- matrix(int l,int c,double* cf) { init(l,c,cf); }
- }
-
- void matrix::init(int l,int c,double* cf)
- { lgn=col=0; coeff=0; coeff=new double[l*c]; lgn=l; col=c;
- if (cf) memmove(coeff,cf,l*c*sizeof(double));
- else memset(coeff,0,l*c*sizeof(double)); }
-
- Elsewhere: coeff=(double*) realloc(coeff,lgn*col*sizeof(double));
-
- I have no idea for the translation to GlobalLock,GlobalFree...
-
- Can you help me?
- Francois Bruneau.
-
-
- Editor [P.D.]: Well, Francois, I'm not sure if I understand your question
- exactly, but I'll we what I can do. First of all, for allocating the
- memory, you're better of using Local memory if you can, but if you're data
- is large, use Global. You'll need to lock the data before you can
- manipulate it. That means before doing a memmove or memset, use the
- Local/GlobalLock function (This assumes you've done your Local/Global Alloc
- with LMEM/GMEM_MOVEABLE!) Next, if you're using LocalAlloc, then you can
- use memmove and memset or their equivalent functions which are available in
- all compilers. If you are using GlobalAlloc, you need to use functions that
- will work on FAR pointers. If these functions aren't available in your
- compiler, you'll have to write your own. Also, be aware the
- Local/GlobalAlloc will return a handle, not an address. To get the address,
- you need to do a Local/GlobalLock.
-
-
-
-
-
-
-
- - 7 -
-
-
-
-
- Date: 31-Mar-93 00:52 EST
- From: James F. Stoves [72561,746]
- Subj: Replacing DLL's
-
- Chris,
- I was just reading your letter in WPJ regarding the replacement of
- DLLs. I just installed EXCEL and WORD on a PC at work, and in thinking
- about it, the Install Program took over the machine.
-
- What I mean is that "MICROSOFT" logo appeared on the top,
- miscellaneous propoganda in the middle, and a progress bar on the bottom.
-
- The window had no "system menu" or minimize/maximize block. There was
- a cancel pushbutton, but ostensibly that would have shut down the entire
- install process. My clock (which is set to "always on top") did not
- appear. I did try "Ctrl+ESCape" once during the install process and it did
- not work. Yet the "setup" program is launched from within Windows, so it
- must be there somewhere...
-
- I was wondering if the way Microsoft gets around the "used DLL"
- problem is by making sure that all DLL's are unused by booting them out. In
- other words, causing everything to somehow be magically unloaded while the
- install is running, replacing the DLLs, then a reload when the install
- process ends. Just a thought, probably of minimal value, but presented for
- your amusement.....
-
- Jim
-
- Editor [P.D.]: Jim, I mentioned in WPJ.INI that I've seen the code for the
- install program. I don't remember this part either, but I can think of a
- way it could be done. First of all, to get rid of everything else on the
- screen and get a bitmap on the screen, all you need is a dialog box with no
- SYSMENU, no CAPTION bar and no border to be sized for the entire screen.
- Next, draw your bitmap on top of it. Now, why isn't your clock showing up?
- Well, for your clock to be on top, it has to get a message letting it know
- it was covered up so it can redraw itself on the top. Since Windows is a
- non-preemptive multi-tasking system, all the Install program has to do is
- not release control until it's done. You are taught from day one to keep
- your programs nice and have them yield time on a regular basis. If you
- don't yield the queue, nothing else will run (except the kernel and any
- calls you make). So, your clock would stay hidden. That's how I would do
- it, and I wouldn't be suprised if that's how the install program handles
- it. If anyone else has comments on this, I'd love to hear them.
-
-
-
-
-
-
-
-
-
-
- - 8 -
-
-
-
-
-
-
- Midlife Crisis: Windows at 32
- By Pete Davis
-
- So, what's this new column all about? Well, Win32 obviously, and yes,
- this column will get into the nitty gritty of Win32 programming. I'm not
- sure how much appeal this will have because I don't know how many people
- out there actually have it. Mike and I have had it for a couple months now
- and I just recently got the Win32 API Programmer's Reference (Pre-Release).
- This wallet-buster collection of a whole two books (at a mere $90) has
- almost everything you need, NOT. Ok, well, as you saw in the last issue,
- Microsoft's not known for their amazing book deals, but hey, when the
- choices are Microsoft's API reference or Microsoft's API reference, I tend
- to take the former, or was that the latter? Oh well, I think you get the
- picture.
-
- Second question: A whole column for Win32? Well, yes. Even Microsoft
- thinks Windows NT will only take a small percentage (10-20 percent) of the
- Windows 3.1 market. But, as the title implies, this isn't just a Windows NT
- column, this is a Win32 column. Win32 includes the Win32s API which allows
- Windows 3.1 to run 32-bit applications. This has a lot of promise, and
- we'll be talking in detail about all of this.
-
- Actually, there are going to be two Win32 columns. The second one is
- going to be more NT specific.
-
- Ok, let's get a little terminology covered first. You've got your
- Windows 3.1, Windows NT, Win32 and Win32s. Windows 3.1, well, if you don't
- know what it is, maybe you're reading this magazine by accident. Windows
- NT, of course, is Microsoft's Windows New Technology (NoT, whatever).
- Windows NT is a 32 bit operating system. It's more than just a faster
- Windows, though. It's a huge departure from Windows 3.x. Windows NT is its
- own operating system and runs without MS-DOS underneath (although an MS-DOS
- clone runs underneath Windows NT). Windows NT, unlike Windows 3.x, is a
- pre-emptive multi-tasking operating system. This means that while in
- Windows 3.x, if a program locks up, so does Windows, while, under Windows
- NT, if an application locks up, it doesn't affect the rest of the system.
- The reason is that in Windows 3.x, the multi-tasking is based on the
- message queue and when the message queue stops, so does Windows. (There is
- one exception: MS-DOS sessions under Windows 3.x are pre-emptively multi-
- tasked). Windows NT handles everything based on time-slicing instead of the
- message queue. This means that each application gets a short period of time
- to run, then the next application gets a bit of time, and then the next,
- and so on, until the first one gets to go again. This is what pre-emptive
- multi-tasking is all about.
-
- Oops, where were we, oh yeah, the last two: Win32 and Win32s. These
- are both about the same thing. Both are the 32-bit APIs for programming
- Windows. Win32 is the 32-bit API that you use to program under Windows NT.
- The Win32s is the same thing, except that it allows your 32-bit
- applications to run under Windows 3.x through the use of some trickery of
- VxDs (32 bit device drivers) and some DLLs. The Win32s API is actually a
- subset of the Win32 API. It doesn't have threading, security, and some
-
- - 9 -
-
-
-
-
-
-
- other things. Actually, the functions are in the API, but since they can't
- be supported under Windows 3.1, they simply return a failure. This means
- that you can program in the features for NT, but if it's being run under
- Windows 3.1, certain features just won't work.
-
- So, Windows 3.x is covered with the rest of the magazine. The other
- three, Windows NT, Win32 and Win32s are covered by this column and the NT
- column. So, that's it for the little intro on terminology.
-
- Win32 is big, and when I say big, I mean REAL BIG. It's about twice as
- complex, programming-wise, as Windows 3.x. Now, that might not be exactly
- right, there are some things that are made easier, but there are so many
- new features, that it can be very overwhelming. I'm not going to write a
- general overview of Win32 programming because I don't have 6 months to do
- that. The best way to handle this whole thing, I guess, is to take it a bit
- at a time, so each month I'll pick a topic to cover and after about 600
- issues, we'll start to get comfortable with the Win32 API.
-
- Before we get too deep into this (and believe me, we're going to get
- in over my head, a bit), I want to make one thing very clear. I am not a
- Win32 expert. I've been going by what is quite possibly out-of-date
- documentation. I don't have the $360 for Windows NT Manuals. Microsoft says
- to use the online documentation, to which I say, 'Yeah, you try going
- through a 3 meg help file on a CD-ROM drive with 800ms access time!'. I am
- going to try to get the rest of the documentation as soon as I can. I also
- have Helen Custer's 'Inside Windows NT' which is a great book, but it isn't
- exactly specific on the programming aspects. It does, however, provide an
- excellent discussion on how NT works in a general sense.
-
- Today we're going to talk about Processes and Threads and
- Synchronization, and all that fun stuff. Damn, that means more terminology,
- doesn't it? Well, this will be short. Processes, in terms of Windows NT,
- are programs. Each program is a process. Within a single process you can
- have multiple threads. Threads are basically just procedures. The only
- difference is that you can have multiple threads execute simultaneously.
- This is a really nice feature if you have multiple processors in your
- machine, because with Windows NT, you can have different threads running on
- different processors, which makes for some really nice multi-tasking.
- Synchronization is something that comes up when you have multiple threads
- running at once. Synchronization keeps things from getting out of control.
- Since synchronization is such an integral part of concurrent thread
- programming, we'll be talking about it quite a bit here.
-
- I'm picking threads and syncronization as a starting point for several
- reasons. It's one of the most important, yet difficult, obstacles to
- overcome in programming for the higher end Win32 systems (Windows NT and
- the yet-to-come 'Chicago'). Understanding how threads and syncronization
- work will give you a good understanding of how many parts of NT work and
- interact which is essential to programming for it. In later articles I will
- move to less NT-specific subjects, however.
-
- Let's look at an example:
-
- - 10 -
-
-
-
-
-
-
- Let's say you have a database program. As a feature of your database,
- a user can go print a report, and even if it's not done spooling your
- report, it lets you go on to work with the database. So, you go select your
- print report option and then decide to make some changes to some of the
- records in the file. Well, what happens if you update a record in the file
- at the same time that the reporting thread is reading that record? Well,
- that's a problem (and admittedly, not the most realistic, but bear with
- me). Synchronization allows your update thread to keep all other processes
- from touching that record until the record is updated. It's kind of like a
- database record lock, which is usually handled by the operating system
- (hence the lack of realism), but it's the idea that I'm trying to get
- across.
-
- Here's another example, you have a a program that does a bunch of
- repetetive calculations. To take advantage of your muliple CPUs (getting
- realistic now, aren't I.) you decide to break it up into threads that run
- concurrently to speed things up. Well, you could send off a thousand
- threads at once, but sooner or later you're going to run out of memory,
- performance will go through the floor, etc. So, you need to keep the number
- of threads limited.
-
- First, going to our last example of the calculations, that kind of
- synchronization requires a Semaphore. A Semaphore keeps a count of how
- many threads are currently using a resource (in this case, the CPU). When a
- certain number of threads, as determined by the programmer, are using this
- reousource, no other threads can get to it until one of the ones currently
- using it ends, or gives up their lock.
-
- Theres also the event object which is set when a particular event
- takes place. This will release all threads waiting for the event when it's
- set to the signalled state.
-
- When you've got a few applications that want to use a single resource,
- say a printer, you need to use a different type of synchronization called a
- mutex. A mutex is a kind of synchronization, like Semaphores in a way,
- except only one thing can use the resource at a time. Since we've just
- discussed Mutex, let's go on to Critical Sections.
-
- Critical Sections are a lot like Mutex objects. Critical Sections work
- with blocking a single resource at a time. The Critical Section, however,
- is different from the other three objects we've talked about in a few very
- important ways. First of all, Critical Sections only work within a single
- process (also known as a program, damn I love these fancy words). The other
- synchronization objects will work within a single process, but they'll also
- work across all processes. If you want to use mutual exclusion in a single
- process and not globally, go with the Critical Section. If for no other
- reason, it's faster, and we're all speed mongers, aren't we?
-
- I'd like to back up just a bit, for a second. I've been saying a lot
- of stuff like, 'multiple threads is great if you have multiple processors',
- and you're probably thinking, well, I don't have multiple processors, so
- why go through all the trouble of threading if it's not going to speed
-
- - 11 -
-
-
-
-
-
-
- things up? Well, there are other reasons for threading and that's what I
- want to discuss for a second. In a multiple processor enironment, the
- better the threading, the more the operating system can utilize all the
- processors, so it's obviously a good idea there, I think we've established
- that. In a single processor environment, however, situations can arise
- where threading can still speed up applications. Let's say you have a
- program that has to read in some data from a file and then create a report
- from that data. Let's also say that before the report can be generated,
- some initialization steps need to occur. Well, disk usage can really slow
- down a program. Why not send off a thread to read in the file, and then go
- on to do the initialization while it's reading the file and then both of
- you meet back and do the report? Kind of a 'you take the high road and I'll
- take the low road' idea. This way, the main program's not bogged down by
- the speed of the hard drive quite as much. Threads are also excellent
- candidates for server software in a client-server system. Each thread
- could, say, handle a client.
-
- I joked earlier about how we all have multi-processor machines, right?
- Well, actually, don't be too surprised if they start showing up at
- reasonable prices over the next few years. Don't laugh, look how much a 386
- runs these days. You'd probably have laughed 2 years ago if I told you the
- prices would get that low. Don't be to surprised if you see add-on cards,
- at reasonable prices, that carry, say, 3 additional 486s as co-processors
- for your 486, or 5 486s as co-processors, or whatever. The point being, it
- could happen, and I'm betting that it will, especially now that there's an
- operating system that can handle it.
-
- So, on to the next thing, thread priorities. There are five levels of
- thread priority that you can assign. Now, in Unix, the way that this works,
- if I recall correctly (if you ask anyone, they'll tell you my recollection
- is as reliable as bathroom graffiti) Unix will accept a thread priority,
- but modifies it based on the kind of things the thread does, like disk I/O
- lowers a thread priority, and the longer a thread runs, the lower it's
- priority gets. Something like that. Anyway, NT lets you set your thread
- priority at one of the 5 levels. The highest priority threads go first. As
- each thread in the higher levels completes, threads in the lower levels are
- run at each level one at a time, like the first. All of this is calculated
- against the process' (not the thread, but process) base priority, which is
- assigned by the operating system. This is modified by various factors, such
- as a process running in the foreground has it's base priority raised,
- whereas a process in the background has it's priority lowered. Also, to
- make sure all threads get to run, NT will temporarily raise the priorities
- of threads that have been waiting for a long time. It's all pretty complex,
- but the idea of assigning priorities is just to give the operating system
- an idea of how important you think a particular thread is. The best way to
- think of it is this. Take the processes' (not the thread, again) base
- priority. Your thread can be assigned a priority of -2 to +2 against the
- processes' base priority. i.e. the lowest thread priority is the base
- thread priority-2. This is the lowest priority your thread will ever see.
- If, however, your thread's been sitting around for a while waiting to run,
- NT will give it a little boost to make sure it runs.
-
-
- - 12 -
-
-
-
-
-
-
- I keep looking over this and I see a million ways to improve this
- article, but given the time I can't do it this month. I know it's a lot to
- absorb and it's really just meant to give you a taste. Next month I'll have
- some code that actually uses threads and I'll explain how it works. I'm
- also going to start talking about Win32s and give you some code that you
- can run on your Windows 3.1 system with the Win32s DLLs. To avoid adding
- the space of the API to the magazine, for those that aren't interested,
- I'll have the code available on the BBS along with the necessary Win32s
- DLLs and VxDs.
-
- Don't let this months column scare you off. I probably could have
- explained things a little better, with a little more time. Things should
- become more clear when you see some code.
-
- I suggest that if you have the means you do get a copy of the Win32s
- API and DLLs. The future of Windows is going to be 32-bits. I hate to sound
- like a Microsoft Rep, but they're right. 32-bits is the next logical step
- and everyone's going to have to make it eventually. Better to hop on now
- and get a jump on the competition.
-
- I'm sure I'll get lots of questions on this article to clarify just
- about everything I've written so sloppily here. That's fine, send me the
- mail and I'll be sure to respond, if not personally, as part of the
- magazine. The real problem was I bit off a bit more than I can chew this
- month and I'll try not to do that again. See ya and don't forget to write.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 13 -
-
-
-
-
-
-
- Beginner's Column
- By Dave Campbell
-
- Remember last month I made some silly comment about getting buried in
- work? I must be a prophet!! Anyway, here we are again, and with any kind of
- luck next month you'll also find a review of Microsoft Visual C++ by me. I
- have been using it since January, and am convinced it is a great way to go.
-
- This month we are going to add an "ego" box with a live compile date
- in it to the hello application, and talk some about menus.
-
-
- Ego Box
-
-
- I like to call the "About" box an Ego box, because when was the last
- time you saw someone (me included) that put something other than 'Look who
- wrote this' into an 'About' box? For that reason, we HAVE to do an Ego
- box, or what would people think? Thanks to Jeffrey M. Richter in his great
- book "Windows 3: A Developer's Guide", we can add a little bit of
- usefulness to the Ego box by showing a live compile date. I find this very
- useful for configuration management, when I have two (or more) copies of
- the same thing floating around for testing.
-
- The dialog box declaration looks very much like the setup dialog box
- from last month:
-
- ABOUT DIALOG 37, 10, 144, 92
- STYLE WS_POPUP | WS_DLGFRAME
- FONT 8, "Helv"
- BEGIN
- CONTROL "Copyright (C) 1993 WynApse", -1, "STATIC", SS_CENTER |
- WS_CHILD | WS_VISIBLE | WS_GROUP, 7, 8, 130, 11
-
- CONTROL "CompuServe: 72251,445", -1, "STATIC", SS_CENTER | WS_CHILD |
- WS_VISIBLE | WS_GROUP, 17, 17, 109, 8
-
- CONTROL "Version Timestamp:", -1, "STATIC", WS_CHILD | WS_VISIBLE,
- 36, 35, 71, 12
-
- CONTROL "", ID_VERSION, "STATIC", WS_CHILD | WS_VISIBLE, 22, 45, 100,
- 9
-
- CONTROL "OK", IDOK, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD |
- WS_VISIBLE | WS_TABSTOP, 54, 63, 36, 24
- END
-
- Starting at the top, the STYLE line is different from the setup box.
- Instead of WS_CAPTION, we have WS_DLGFRAME. For Ego boxes, I don't
- generally put a caption. It doesn't serve a lot of purpose, other than
- being able to move the box around, and how often do you do more than click
- OK on an About box? This is personal preference, you understand. The
-
- - 14 -
-
-
-
-
-
-
- WS_DLGFRAME puts a nice frame around the box, and serves no purpose other
- than aesthetics also.
-
- The top three lines of the dialog are essentially identical in their
- properties:
-
- CONTROL "text", ID, "class", style, x-position, y-position,
- x-width, y-width
-
- This is the form of the generalized control statement. The first three
- lines have an ID of -1. This is because they are static controls, and do
- not send messages back to the parent window.
-
- There are six control classes:
-
- button
- static
- edit
- scrollbar
- listbox
- combobox
-
- At this time, we are only dealing with two of them: button and static.
- The version number will be written to the dialog box, but that is done by
- the WinApp, not by the user, so it isn't an edit box.
-
- The style parameter can consist of logical OR chains of individual
- style declarations, of which there are a multitude. I am going to just talk
- about them as we get to them.
-
- The first control line contains:
-
- SS_CENTER | WS_CHILD | WS_VISIBLE | WS_GROUP
-
- where
-
- SS_CENTER : Center the text in the box
- WS_CHILD : child window
- WS_VISIBLE : control is initially visible
- WS_GROUP : first item in a group [we'll deal with this later]
-
- The fourth control contains:
-
- BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP
-
- where
-
- BS_DEFPUSHBUTTON : Default pushbutton, the one selected upon startup
- WS_TABSTOP : goes along with the group declaration
-
- The fourth control is different in that it has "" for the displayed
- text, and has a defined control ID, ID_VERSION. ID_VERSION is defined in
-
- - 15 -
-
-
-
-
-
-
- hello.h, and is used in hello.c to place the text properly.
-
- HELLO.DEF has a slight change: DON'T FORGET TO PUT THE DIALOG BOX
- PROCEDURE IN THE DEF FILE!! This means the exports list of the def file
- becomes:
-
- EXPORTS WndProc @1
- HelloDlgProc @2
- AboutDlgProc @3
-
- Now we're ready to discuss displaying the box. This takes place
- identically to the invocation of the setup box from last month. A menu
- choice is made, and a message is sent to our main Windows Procedure,
- telling us the user wants to see a dialog box. This time, we have added a
- message IDM_HELPABOUT to hello.h to handle this. The function prototype
-
- BOOL FAR PASCAL AboutDlgProc(HWND, WORD, WORD, LONG);
-
- is listed with the other prototypes above the main body of code. "About" is
- added to the system menu, which will be explained later in this article. A
- static FARPROC for the pointer to the dialog procedure is declared early in
- WndProc, inline with the one to the setup box. Then, just below the case
- statement for IDM_SETUP, is one for IDM_HELPABOUT. The two case statements
- match with the exception of the name of the dialog template to use from
- hello.dlg. The About box code is:
-
- case IDM_HELPABOUT :
- lpfnAboutDlgProc = MakeProcInstance(AboutDlgProc, hInst);
- DialogBox(hInst, "About", hWnd, lpfnAboutDlgProc);
- FreeProcInstance(lpfnAboutDlgProc);
- return 0;
-
- We must get a long pointer to a function, lpfnAboutDlgProc, to use in
- the DialogBox function call. This is actually playing a game with memory
- segments and far pointers, and segment reloading to enable Windows to find
- our dialog box function in memory. All the segmentation manipulation that
- Windows gives you for free is through small pieces of memory called
- "thunks", or instance thunks, or reload thunks which binds a data segment
- to the address of a function. MakeProcInstance takes the procedure in the
- first parameter, and binds it to the data segment of the application whose
- handle is in the second parameter. The return value from MakeProcInstance
- is actually an address of a reload thunk.
-
- Aren't you glad you know this? Now you do.......
- .....now you've forgotten it, and can get on with programming Windows.
-
- Since you know this, you'll realize how important it is to release
- that "thunk" when you're finished with it by executing the FreeProcInstance
- call. In DOS, we could be fairly certain that once our program exited,
- things would get cleaned up. That wasn't good programming practice then
- either, but it worked. If we make that kind of error in Windows, we leave
- all manner of little potholes in memory, and very often run out.
-
- - 16 -
-
-
-
-
-
-
- The parameter "About" in the call is the title of the dialog box we
- built in Hello.DLG. Because of the 'DialogBox' call, this dialog box will
- be modal, and control will not return to the main window until OK is
- pressed in the dialog box.
-
- We do a return 0 here since we have handled the message, and have no
- need to execute the default operation.
-
- That gets us to the dialog box procedure itself, 'AboutDlgProc':
-
- BOOL FAR PASCAL AboutDlgProc (HWND hDlg, WORD message, WORD wParam,
- LONG lParam)
- {
- char szBuffer[100];
-
- switch (message)
- {
- case WM_INITDIALOG :
- wsprintf(szBuffer, "%s at %s", (LPSTR) __DATE__, (LPSTR) __TIME__);
- SetWindowText(GetDlgItem(hDlg, ID_VERSION), szBuffer);
- return TRUE;
-
- case WM_COMMAND :
- switch (wParam)
- {
- case IDOK :
- EndDialog(hDlg, wParam);
- return TRUE;
-
- default :
- return TRUE;
- }
-
- default :
- return FALSE;
- }
- } /* AboutDlgProc */
-
- The WM_COMMAND switch case is virtually identical to the setup box
- from last time, the new stuff being the WM_INITDIALOG case. The
- WM_INITDIALOG message is the first message a dialog box receives. At that
- point in time, we fill in a message buffer with compile date and time in
- this manner:
-
- wsprintf(szBuffer, "%s at %s", (LPSTR) __DATE__, (LPSTR) __TIME__);
-
- __DATE__ and __TIME__ are predefined global identifiers that contain the
- date and time that processing began on the current file.
-
- This line of text is inserted into the ID_VERSION control on the face
- of the dialog by the following line:
-
-
- - 17 -
-
-
-
-
-
-
- SetWindowText(GetDlgItem(hDlg, ID_VERSION), szBuffer);
-
- GetDlgItem returns the child window's handle for the control, and
- allows us to insert our text into the dialog box.
-
-
- Menus
-
-
- Now let's discuss menus. Because everyone is familiar with them, we
- should be able to beat them to death pretty soundly. How many menus are
- there in Windows and how do we enable/disable them? Anybody? Ok, I'll
- address it: There is a system menu which may be part of any window or
- dialog box (which is just a child window). Then there is a menu that may be
- declared in the window class declaration. There are popup menus that can be
- used pretty much anywhere.
-
-
- System Menu
-
- The system menu is enabled/disabled with the properties of the window
- declaration. This is invoked by clicking the dashed line boxed in on the
- left of the caption bar (the System Menu button). This is also the menu you
- get when you single click an icon.
-
- The system menu is enabled by including the WS_SYSMENU style in the
- window creation.
-
-
-
- Application Menu
-
- The Application menu is declared at class-registration time of the
- window:
-
- wc.lpszMenuName = szAppName;
-
- Normally, the name of the program is also the name of the menu, so
- szAppName is useable here.
-
- The ninth parameter in the CreateWindow call is of type HMENU, and
- this overrides the menu in the menu class. This gives you the option of
- having multiple windows use the same class, and have different menus. If
- the one in the class is the one you want (as we are doing) leave the ninth
- parameter as NULL.
-
-
- Popup Menus
-
- Popup menus are declared either as part of the main menu, or possibly
- on the fly during run-time, and may displayed as an action from the main
- menu, or possibly a run-time event.
-
- - 18 -
-
-
-
-
-
-
-
- CUA
-
-
- As with any user interface, and more importantly, an interface that is
- shared, you want to provide your users (it might be you) an easily
- recognizeable way to use your product. It may be cute to put the help pull
- down on the left side of the main menu, and it certainly would grab
- people's attention, but not in the way most of us would like!
-
- All of this melts down into me stating that in the case of menus, if
- you want one, make it look like everyone elses. At least for the major
- pieces. This is called CUA, which stands for Common User Access. The
- orignial standard of CUA was developed by IBM. The current standard is
- Microsoft's "Application Design Guide" (ISBN 1-55615-384-8). The most
- important point being to be standard! The hello.rc code for the menu is
- quite long, and only pieces of it will be show here:
-
- Hello menu
- begin
- popup "&File"
- begin
- menuitem "&New", IDM_FILENEW
- menuitem "&Open...", IDM_FILEOPEN
- .
- end
-
- popup "&Edit"
- begin
- menuitem "&Undo\tCtrl+Z", IDM_EDITUNDO
- menuitem "&Repeat", IDM_EDITREPEAT
- .
- end
-
- popup "&Sample"
- begin
- menuitem "&Dialog", IDM_SAMPLEDLG
- menuitem separator
- menuitem "&Alternate..." IDM_ALTERNATE
- end
-
- popup "&Help"
- begin
- menuitem "&Index", IDM_HELPINDX
- menuitem "&Keyboard", IDM_HELPKBD
- .
- menuitem "&About Hello", IDM_HELPABOUT
- end
- end
-
- The menu has a basic structure:
-
-
- - 19 -
-
-
-
-
-
-
- "Name" menu
- begin
- end
-
- inside the begin..end pair is the menu itself. Each entry in our menu is
- listed as 'popup'. This means that each of the entries is a kick-off point
- for a popup, or pull-down type of menu whose structure follows.
-
- The structure for the popup menus is identical to that of the main
- menu with the exception of the word 'popup':
-
- popup "Name"
- begin
- menuitem "Sub1", IDM_SUB1NAME
- menuitem "Sub2", IDM_SUB2NAME
- .
- end
-
- Popups can have popups can have...you get the idea.
-
- Each menu item has three parts:
-
- 1) The text that appears on the menu
- 2) The ID number of the menu item
- 3) An attribute for that item
-
-
- Menu Text
-
- The menu text is copied directly to the menu in the manner you type
- it, with the addition that any character preceeded by an ampersand, "&", is
- underlined in the menu. The underlined characters, when combined with the
- Alt key, provide the user a 'hot-key' method to that item. Without the "&"
- the user may still use the Alt key with the first letter of any menu item.
-
- Two control characters '\t' and '\a' are optionally used inside the
- text. The tab character, '\t' will space the menu item in a new column far
- enough to the right to make room for the longest text line in an
- accompanying popup menu. The '\a' is normally used with HELP, and will
- right-justify the menu selection.
-
-
- Menu ID
-
- The menu IDs are defined as normal in the .H file, as we are doing
- with Hello.H.
-
-
- Menu Attributes
-
- The attributes are a small enough number I will list them:
-
-
- - 20 -
-
-
-
-
-
-
- 1) CHECKED - displays a check mark to the left of the menu text
- 2) GRAYED - grays out the text, and is also INACTIVE
- 3) INACTIVE - does not gray out the text, but sends no message to the
- application
- 4) MENUBREAK - This item, and following appear in a new column
- 5) MENUBARBREAK - This item, and following appear in a new column,
- separated by a vertical line
-
- In order to keep the main menu standard, I didn't add any of this
- stuff to it, however, there is a secondary menu, "Hello2", defined in
- hello.rc that shows GRAYED and CHECKED items.
-
- I took one slight excursion from the "standard" menuing, and to the
- 'Sample' popup, I added:
-
- menuitem separator
- menuitem "&Alternate..." IDM_ALTERNATE
-
- Alternate is used in Hello.c to bring up the secondary menu. When the
- second menu is being used, Grayed/Ungrayed, and One/Two show the use of the
- attributes in your code.
-
-
- System Menu
-
-
- The system menu is not really there for us to add to, but many people
- do, and it is definitly a quick way to get an about box up. Since the menu
- is not defined in our code, we need to add to it at run time. This is done
- by using the AppendMenu command. A menu pointer (of type HMENU) is
- declared, and a pointer to the System Menu is captured:
-
- hMenu = GetSystemMenu(hWndMain, FALSE);
-
- Then the append is accomplished as follows:
-
- AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
- AppendMenu(hMenu, MF_STRING,IDM_SETUP, "Setup...");
-
- I like to put a separator (a horizonal line) between the default setup
- items and anything I add. There are a few things that need to be handled
- when using the system menu:
-
- 1) the IDs used must be < F000H to avoid conflict with the normal system
- menu commands
-
- 2) any WM_SYSCOMMAND messages not captured must be passed to the default
- window processor, or else they won't get executed.
-
- From hello.c, in WndProc, we find the following code:
-
- switch (message)
-
- - 21 -
-
-
-
-
-
-
- {
- .
- case WM_SYSCOMMAND :
- switch (wParam)
- {
- case IDM_SETUP :
- lpfnHelloDlgProc = MakeProcInstance(HelloDlgProc, hInst);
- DialogBox(hInst, "Hello", hWnd, lpfnHelloDlgProc);
- FreeProcInstance(lpfnHelloDlgProc);
- return 0;
- }
-
- break;
- .
- }
- return DefWindowProc(hWnd, message, wParam, lParam);
-
- the message passed is WM_SYSCOMMAND if a menu item from the system menu is
- selected. The item selected is passed in wParam. Therefore, a second switch
- case is necessary to capture the system menu commands. In the above
- example, IDM_SETUP is handled locally by displaying the setup dialog box,
- but any other system commands are sent along to the default window
- procedure DefWindowProc. This will ensure that nothing is lost.
-
- You could 'trap' out certain system menu commands at this point by
- executing the function yourself and returning 0. the normal system menu
- options and their IDs are:
-
- Restore SC_RESTORE
- Move SC_MOVE
- Size SC_SIZE
- Minimize SC_MINIMUM
- Maximize SC_MAXIMUM
- Close SC_CLOSE
- Switch To SC_TASKLIST
-
- Menu Modification
-
-
- Just as the system menu was appended above, there are other commands
- that may be executed to modify menus:
-
- 1) AppendMenu
- 2) DeleteMenu - deletes a menu item, and destroys the item
- 3) InsertMenu - Inserts an item
- 4) ModifyMenu - changes an item
- 5) RemoveMenu - removes an item from a menu
-
- Delete Menu would destroy a POPUP menu for example, and RemoveMenu
- would only remove the ability to bring it up from the main.
-
-
-
- - 22 -
-
-
-
-
-
-
- Hello.C
-
-
- Now let's look a little closer at the code from Hello.C this month
- that handles menus:
-
- As explained above, the main application menu is declared at
- class-registration time of the window. That's all it takes to put the menu
- up in your app. In the WM_CREATE case of WndProc, we added the line:
-
- hMainMenu = GetMenu(hWnd);
-
- This gives us a handle to restore back to the main menu "Hello", after
- we have been using the alternate one. We normally wouldn't have had to
- capture this handle. WM_COMMAND is where the action all takes place. wParam
- is the menu entry selected by the user. Since we are going to be messing
- around with the attributes in the sub-menu, we capture a menu handle inside
- this case statement for that purpose.
-
- For the menu items, all I did was to setup a print line for each menu
- entry, and fall through to the MessageBox routine at the bottom.
-
- IDM_ALTERNATE simply executes a SetMenu command which switches us to the
- alternate menu defined in hello.rc.
-
- ALTONE/ALTTWO and ALTGRAY/ALTUNGRAY use a brute-force method of toggling
- each other on and off.
-
- IDM_ALTRESTORE restores the main menu we started with.
-
- Since we have only one Windows Application, you'll notice that
- independent of which menu is alive at the time, we still have to handle all
- the cases for both, all the time.
-
-
- End.
-
-
- I think it probably takes two issues before the feedback comes in, so
- this column is running slightly open-loop at this point. In other words, I
- am still steering. I want some help steering, so get me some feedback. In
- particular, I am looking for ideas on a useful WinApp we can build from
- scratch explaining as we go, hopefully building off what we've already done
- here.
-
- I have one correction, or addition to last month's article. I talked
- about Borland programmers needing to add:
-
- #define WINVER 0x0300
-
- ahead of your include of windows.h in your hello.c file to compile under
- the 3.1 compiler for Windows 3.0. This holds true for Microsoft programmers
-
- - 23 -
-
-
-
-
-
-
- also. Additionally, changing
-
- wc.lpfnWndProc = WndProc; /* Name of proc to handle window */
-
- to be:
-
- wc.lpfnWndProc = (WNDPROC)WndProc; /* Name of proc to handle window */
-
- holds true for Microsoft, too.
-
- One other thing I noticed is that I held a pretty hard line on not
- going beyond the page width for long lines. Since that was my first
- article, I didn't realise that I had a line length of about 75, and while I
- was complaining about long lines, I was displaying them, too...sorry!!
- 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.
-
- That's it for this time. Next month we're going to add a file list box
- the hard way, and discuss list boxes in general, and how to manipulate
- text/filenames in them. Feel free to contact me in any of the ways below. 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
- CIS: 72251, 445
- Phoenix ACM BBS (602) 970-0474 - WynApse SoftWare forum
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 24 -
-
-
-
-
-
-
- Owner-Drawn List Boxes
- By Mike Wallace
-
- If you've ever wanted to liven up your list boxes with color, then you
- need to know about owner-drawn list boxes. I recently wanted to create a
- list box and color-code each item in the list based upon its value. The
- only way to do this is with an owner-drawn list box, which is just what the
- name implies - the owner (i.e., the programmer) has to draw the list box
- himself. It's a little bit of work, but well worth the effort. The basis
- for any owner-drawn control is the DRAWITEMSTRUCT structure, which is
- declared as follows:
-
- typedef struct tagDRAWITEMSTRUCT {
- UINT CtlType;
- UINT CtlID;
- UINT itemID;
- UINT itemAction;
- UINT itemState;
- HWND hwndItem;
- HDC hDC;
- RECT rcItem;
- DWORD itemData;
- } DRAWITEMSTRUCT;
-
- The owner of the owner-drawn control receive a pointer to this
- structure as the lParam parameter of the WM_DRAWITEM message. This
- structure is described completely in the Microsoft documentation, but I
- want to describe a few (the important ones) so you won't have to get out
- your manuals just to read this article:
-
- hDC : the device context for the list box (very important)
-
- itemID : the index of the itme in the list box
-
- itemAction : describes the drawing action required by the
- owner and will have one of the following values:
-
- ODA_DRAWENTIRE : The entire list box needs to be drawn
-
- ODA_FOCUS : The list box has gained or lost focus
-
- ODA_SELECT : The selection status has changed
-
- itemState : describes what the item will look like after it's
- been drawn; it will have one of the following values:
-
- ODS_CHECKED : The menu item is to be checked
-
- ODS_DISABLED : The item is to be drawn as disabled
-
- ODS_FOCUS : The item has input focus
-
-
- - 25 -
-
-
-
-
-
-
- ODS_GRAYED : The menu item is to be grayed
-
- ODS_SELECTED : The item has been selected by the user
-
- itemData : contains the value last assigned to the list box by
- an LB_SETITEMDATA message. If the list box has the
- LBS_HASSTRINGS style, this value is initially zero; else,
- this value is initially the value passed to the list box
- in the lParam parameter of either the LB_ADDSTRING or
- LB_INSERTSTRING message.
-
-
- Enough small talk. On to the program...
-
- For this example, I'm using a dialog box containing only a list box
- and an "OK" button. If the user selects an item in the list box, give the
- item a different color. In the function handling this dialog box, we only
- care about the following four messages: WM_INITDIALOG, WM_COMMAND,
- WM_DRAWITEM and WM_MEASUREITEM. Here's a brief description of how the
- program will handle each of these messages:
-
- WM_INITDIALOG : The dialog box is getting created, so we have to do
- two things: a) use the GetDlgItem() function on the list box control to get
- a handle to the list box; and b) use that handle to fill the list box with
- an array of strings using the SendMessage() function and the LB_ADDSTRING
- message.
-
- WM_COMMAND : If the user presses the OK button, exit the function.
-
- WM_DRAWITEM : If the status of any item in the list box gets changed
- (including the initial filling of the list box), this message gets sent to
- your function. Check the value of the itemAction field. For this example,
- I'll handle the ODA_DRAWENTIRE and ODA_SELECT cases with the same code that
- handles both the selected and unselected states. For the ODA_FOCUS case, I
- will just call DrawFocusRect().
-
- WM_MEASUREITEM : This message gets sent so you can set the height of
- the items in the list box. Create a device context for the dialog box and
- then use the GetTextMetrics() function to determine the font height.
-
- The definition for the dialog box also needs to be discussed.
- Primarily, the list box must have either the LBS_OWNERDRAWFIXED or the
- LBS_OWNERDRAWVARIABLE styles. The latter allows each item to have a
- different height. I'm using the former for this program. Here's the
- "ODLBOX.DLG" file:
-
-
- ODLISTBOX DIALOG LOADONCALL MOVEABLE DISCARDABLE 60, 25, 120, 120
- STYLE WS_CAPTION | WS_DLGFRAME | WS_POPUP
- CAPTION "Owner-Drawn List Box"
- BEGIN
- CONTROL "", IDB_LISTBOX, "listbox", LBS_OWNERDRAWFIXED |
-
- - 26 -
-
-
-
-
-
-
- LBS_HASSTRINGS | LBS_STANDARD | WS_VSCROLL | WS_GROUP |
- WS_TABSTOP | WS_CHILD, 25, 10, 75, 85
- CONTROL "OK", IDB_OK, "button", BS_DEFPUSHBUTTON |
- WS_TABSTOP | WS_CHILD, 40, 100, 40, 14
- END
-
- I've defined ODLISTBOX, IDB_LISTBOX and IDB_OK in the "ODLBOX.H" file.
- All that leaves is the code for the function itself. Here it is:
-
-
- // Function to handle an owner-drawn list box
- #include <windows.h>
- #include "odlbox.h"
-
- BOOL FAR PASCAL ODListBox(HWND hDlg, unsigned message, WORD wParam,
- LONG lParam) {
-
- // define some colors for the selected text and background
- #define GREEN RGB(0,255,0)
- #define BLUE RGB(0,0,255)
-
- HWND hLst; // handle to the list box
- HDC hDC; // device context handle
- LPDRAWITEMSTRUCT lpDIS; // long pointer to DRAWITEMSTRUCT
- LPMEASUREITEMSTRUCT lpMIS; // long pointer to MEASUREITEMSTRUCT
- TEXTMETRIC tm; // text info structure
-
- HBRUSH hBrush; // draws text background
- DWORD OldTextColor; // saves old text color
- DWORD OldBkColor; // saves old background color
-
- int NumItems; // number of items in list box
- int i; // temporary variable
-
- char textStr[80]; // list box item string buffer
- char *textItems[] =
- { // strings going into the list box
- "One",
- "Two",
- "Three",
- "Four",
- "Five",
- "Six",
- "Seven",
- "Eight",
- "Nine",
- "Ten"
- };
-
- NumItems= 10;
-
- switch (message) {
-
- - 27 -
-
-
-
-
-
-
- case WM_INITDIALOG:
- hLst= GetDlgItem(hDlg, IDB_LISTBOX);
- for(i = 0; i < NumItems; ++i)
- SendMessage(hLst, LB_ADDSTRING, 0, (LONG)
- (LPSTR) textItems[i]);
- SetFocus(GetDlgItem(hDlg, IDB_OK));
- break;
-
- case WM_COMMAND:
-
- if(wParam == IDB_OK) {
- EndDialog(hDlg, NULL);
- return TRUE;
- }
- break;
-
- case WM_DRAWITEM:
-
- // copy the DRAWITEMSTRUCT pointer from lParam
- lpDIS= (LPDRAWITEMSTRUCT)lParam;
-
- // if no items in the list box yet, set focus
- if(lpDIS->itemID == -1) {
- DrawFocusRect(lpDIS->hDC, (LPRECT)&lpDIS->rcItem);
- return TRUE;
- }
-
- // draw items in list box and check for selection
- if((lpDIS->itemAction & ODA_DRAWENTIRE) ||
- (lpDIS->itemAction & ODA_SELECT)) {
-
- // Get the text string and save in textStr
- SendMessage(hLst, LB_GETTEXT, (WORD)lpDIS->itemID,
- (LONG) (LPSTR) textStr);
-
- // Handle the selection state
- if (lpDIS->itemState & ODS_SELECTED) {
-
- // text was selected, so make it green on blue
- // first, draw and fill background
- hBrush= CreateSolidBrush(BLUE);
- FillRect(lpDIS->hDC, (LPRECT)&lpDIS->rcItem,
- hBrush);
- DeleteObject(hBrush);
-
- // set colors and output the text
- OldTextColor= SetTextColor(lpDIS->hDC, GREEN);
- OldBkColor= SetBkColor(lpDIS->hDC, BLUE);
- TextOut(lpDIS->hDC, (int)(lpDIS->rcItem.left),
- (int)(lpDIS->rcItem.top), (LPSTR)textStr,
- lstrlen(textStr));
-
-
- - 28 -
-
-
-
-
-
-
- // restore old colors
- SetTextColor(lpDIS->hDC, OldTextColor);
- SetBkColor(lpDIS->hDC, OldBkColor);
-
- }
- else {
-
- // item not selected, so make it black on white
- // first, draw and fill background
- hBrush= GetStockObject(WHITE_BRUSH);
- FillRect(lpDIS->hDC, (LPRECT)&lpDIS->rcItem,
- hBrush);
-
- // next, draw the text
- TextOut(lpDIS->hDC, (int)(lpDIS->rcItem.left),
- (int)(lpDIS->rcItem.top), (LPSTR)textStr,
- lstrlen(textStr));
-
- }
-
- // Check for focus state
- if(lpDIS->itemState & ODS_FOCUS)
- DrawFocusRect(lpDIS->hDC, (LPRECT)&lpDIS->rcItem);
-
- return TRUE;
-
- }
-
- if(lpDIS->itemAction & ODA_FOCUS) {
-
- DrawFocusRect(lpDIS->hDC, (LPRECT)&lpDIS->rcItem);
- return TRUE;
-
- }
- break;
-
- case WM_MEASUREITEM:
-
- /* get and use height of current font */
- lpMIS= (LPMEASUREITEMSTRUCT)lParam; // copy info ptr
- hDC= GetDC(hDlg); // create a DC
- GetTextMetrics(hDC, &tm); // get text info
- lpMIS->itemHeight= tm.tmHeight; // get text height
- ReleaseDC(hDlg, hDC); // free the DC
- return TRUE;
-
- } /* switch(message) - end */
- return FALSE;
-
- } /* ODListBox() - end */
-
-
-
- - 29 -
-
-
-
-
-
-
- Beginner's Column for Turbo Pascal for Windows
- By Bill Lenson
-
- Welcome one, welcome all to the first of, hopefully, many beginner's Pascal
- columns. If you've just purchased Turbo Pascal for Windows (TPW) or had it
- for a while I think this column will be of interest to you. I'll try not
- to go too fast so everyone gets lost but not too slow that nothing gets
- said either. Hey, I'm a programmer but I haven't forgotten what it's like
- learning a new language. Pascal is different from most languages and I
- think it will be a lot of fun.
-
- How much computer experience do you need to understand this stuff? Not
- much. You should have a basic grasp of USING windows and know enough DOS
- (or Windows File Manager if you prefer) to make directories and copy files.
- That's it. Everything else will be covered in the articles.
-
- All too often I've seen people try to learn a language like Pascal and
- ultimately get frustrated after a month or two. Their problem is simple:
- they may have picked up some really neat tricks to develop simple programs
- but they lack the fundamentals needed to soundly write large programs. To
- be a really good Pascal programmer you will need to learn lots of really
- scary things. First you will need to learn the fundamentals of the
- language. This isn't TOO bad because Pascal programs are fairly easy to
- read. Next, you'll need to learn algorithms and data structures. These
- are the building blocks of any program. Thirdly, given a problem, you'll
- need to know how to analyze it and produce a program to turn concept into
- reality.
-
- Finally, you must learn all the extensions your particular environment
- offers to Pascal. For this column we're using Windows so you'll need to
- become aware of the thousand or so functions available to you in Windows.
- To complicate matters, you can't effectively learn these things one at a
- time. To be a successful learner, you need to be exposed to everything at
- once but not so much of each that you'll run screaming into the night.
-
- Have I scared anyone? I hope not. Pascal isn't a difficult language to
- learn if you take it in small steps. I was fortunate enough to start
- learning "3rd generation" languages out of a BASIC book in 1981 which
- introduced the language in 7 steps. Two years later I started learning
- Pascal in University. By applying small, logical steps (or at least I
- should have - hindsight is 20-20) I could have dramatically reduced the
- learning in my first four month course into a couple of weeks. Pascal is
- a much more robust language than BASIC and will require probably three
- times that many steps to learn. Hey, I was looking for a name for this
- column. "Pascal in 21 Steps". I like it. Anyway, the emphasis in each
- step (column) will be to study problem solving as you learn the language
- and introduce Windows extensions as you go.
-
- That's it for the first Turbo Pascal for Windows column. Next month we'll
- start in on the writing your first Pascal program. Things will really
- start to move then. See you next month.
-
-
- - 30 -
-
-
-
-
-
-
- Bill Lenson holds a Bachelor of Computer Science from the University of
- Windsor. He is currently employed at Price Waterhouse Canada as a
- consultant in their National Technology Services department. Bill is a
- team leader in the development of a major Windows software package written
- in C++ and Pascal.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 31 -
-
-
-
-
-
-
- Hacker's Gash
-
-
- This month's column is by Wim Harrison (hope I have the last name
- right; I forgot to write it down after downloading his note).
-
- 4 States of a button
- --------------------
- I read with great interest, and mounting despair, the article about
- bitmapped buttons in WPJ 1-3. Yet again we have someone (just the latest in
- a long list) repeating the MS line that only 3 button states are needed.
-
- NOT! A button has 4 states - Normal, Focussed-not pressed, Focussed-
- pressed, and disabled (count 'em - 4). Everyone seems to omit the last
- state - disabled.
-
- What I do is to have a normal button (not focussed, not pressed) but
- with the international 'no entry' red diagonal bar across it. Then if you
- do a call to 'EnableWindow( hButton, FALSE)' it immediately acquires a red
- bar to show it is not available. Even Borland don't catch this, and I think
- it adds greatly to the user friendliness of the system.
-
- I have included the source (the Pascal version, I have C code as well)
- for the code I use. I use the following:
-
- ID + 100 = Normal
- ID + 200 = Focussed
- ID + 300 = Pressed
- ID + 400 = Disabled - the special one.
-
- Note it takes only one extra line to handle this
-
- ------------------------ Cut here --------------------------
-
- PROCEDURE DrawControl( hWind : HWND; lpInfo : PDRAWITEMSTRUCT );
- BEGIN
- IF ( lpInfo^.CtlType <> ODT_BUTTON ) THEN
- Exit;
- ResID := ( lpInfo^.CtlID MOD 100 );
- Inc( ResID, 100 );
- { }
- IF ( lpInfo^.itemState AND ODS_DISABLED ) <> 0 THEN
- Inc( ResID, 300 )
- ELSE
- IF ( lpInfo^.itemState AND ODS_SELECTED ) <> 0 THEN
- Inc( ResID, 200 )
- ELSE
- IF ( lpInfo^.itemState AND ODS_FOCUS ) <> 0 THEN
- Inc( ResID, 100 );
-
- hBM := LoadBitmap( System.hInstance, MAKEINTRESOURCE( ResID ) );
- IF ( hBM = 0 ) THEN
-
- - 32 -
-
-
-
-
-
-
- Exit;
- IF ( ( lpInfo^.itemAction AND ODA_DRAWENTIRE ) <> 0 ) OR
- ( ( lpInfo^.itemAction AND ODA_FOCUS ) <> 0 ) OR
- ( ( lpInfo^.itemAction AND ODA_SELECT ) <> 0 ) THEN
- BEGIN
- hMemDC := CreateCompatibleDC( lpInfo^.hDC );
- hOldbm := SelectObject( hMemDC, hBM );
- IF ( hOldbm <> 0 ) THEN
- BEGIN
- StretchBlt(lpInfo^.hDC,
- lpInfo^.rcItem.left, lpInfo^.rcItem.top,
- lpInfo^.rcItem.right - lpInfo^.rcItem.left,
- lpInfo^.rcItem.bottom - lpInfo^.rcItem.top,
- hMemDC, 0, 0, 63, 39, SRCCOPY);
- SelectObject( hMemDC, hOldbm );
- END;
- DeleteDC( hMemDC );
- END;
- DeleteObject( hbm );
-
- END;
-
- ------------------------------ CUT HERE -------------------------------
- This is called from the main (dialog) proc to handle all custom button draw
- requests.
-
- BTW the 63, 39 values above are because I use 64x40 buttons.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 33 -
-
-
-
-
-
-
- Microsoft's Windows Strategy
- By Pete Davis
-
- Well, in March I got the honor of going to a Microsoft Windows
- Strategy seminar put on by our buddies over at Microsoft. It was actually
- pretty interesting (any seminar goer can tell you that most are real
- sleepers.) I have to admit that at any seminar, the temptation to cop some
- Zs is pretty high and this one was no different, but there was a lot of
- interesting stuff for me to relay. (Otherwise I wouldn't be writing this,
- right?)
-
- What are the big things in Microsoft's future? Well, OLE 2.0 is
- probably at the top of the list, according to Microsoft. This is both a
- good thing and a bad thing. They showed a very impressive demo of OLE 2.0
- in action and I think everyone there was ooing and ahing. But, as I said,
- there is also a bad side, that being that OLE isn't the easiest thing in
- the world to program. Seeing as that's the case, we're obviously going to
- have to cover it here at some point and I'll start looking into that
- myself.
-
- My personal opinion, especially after talking to a few experts, is
- that OLE 2.0 won't really pan out the way Microsoft wants. In all honesty,
- it's just too much of a pain to program and it's very document oriented.
- Microsoft might try to argue otherwise, but I don't think EVERY program can
- be considered document-based. Microsoft, for some reason, thinks they are.
- Maybe I'm wrong, but we'll see in the near future, won't we.
-
- What can OLE 2.0 do for you? OLE 2.0 is VASTLY improved over 1.0. If
- you're familiar with 1.0, picture this. Let's say you were in Microsoft
- Word and you have an OLE link to an Excel spreadsheet. Let's say that link
- shows maybe 5 columns and 3 rows. Well, in 1.0, when you double clicked on
- the Word version, boom, Microsoft Excel pops up a big old window with your
- spreadsheet. Not too bad, but try to picture the 2.0 version. You double
- click on your link and boom, nothing happens. Well, not exactly nothing,
- but it's real hard to notice. First of all, the title line that used to say
- 'Microsoft Word ....' whatever, has now changed to 'Microsoft Excel ....'.
- The menu bar has changed to the Excel menu bar. Any tool bars are changed
- over to Excel tool bars. The column headers A-F and row headers 1-3 show up
- right around your existing copy of the spreadsheet. (Not the entire Excel
- window.) The weird thing is, the rest of your document is right there,
- unchanged. It looks like you're still in Word. The most noticable thing is
- the column and row headers which suddenly surround your spreadsheet. If you
- have bitmaps and graphs and stuff in your document, and they were on the
- screen before you double-clicked, they're still there after you double
- click. Pretty neat, eh?
-
- On top of all that, let's say you have, not only a few rows and
- columns, but also, say a link to a graph based on the numbers in your
- spreadsheet, in the document. Well, again, you can double click on the
- graph, and almost magically, you're in Excel and you hardly noticed the
- change. Let's say you modify the values in the spreadsheet. Well, the graph
- changes immediately. Let's say you move the bar graphs bars? The numbers
-
- - 34 -
-
-
-
-
-
-
- change to coincide with the graphs changes. It's really pretty cool.
-
- Well, can't just rave about the great parts, writing code to do it
- can't be easy. Haven't seen the API for OLE 2.0 yet, but I've seen it for
- 1.0 and it isn't exactly a piece of cake. You can be sure 2.0 isn't going
- to be easier.
-
- What were some other things.... 'Cairo', that's what. If you're around
- Microsoft types, you've heard of Cairo for some time now. Cairo is the
- secret (and I use that in terms of how secret anything in this country
- usually gets) codename for Microsoft's 'Advanced' operating system. That
- was about all I've known for a while. Got a little more news about it,
- though. Cairo is going to be the next version of Windows NT, essentially.
- It's going to be very object oriented, more so than the existing operating
- system. What's more is Cairo is going to be based heavily on the use of OLE
- 2.0, so it's time to start brushing up on those OLE 2.0 skills.
-
- Microsoft is going to be supporting 5 versions of Windows, over the
- next few years. They are, from bottom to top, Modular Windows, Windows 3.1,
- Windows 3.1 for Workgroups, Windows NT, and Windows NT Advanced Server.
- Obviously, this list could be kinda grouped into a set of 3 operating
- systems, but I'm giving it to you the way they fed it to me. Anyway, we all
- know what Windows 3.1 is, I hope, and just think of 3.1 for Workgroups as
- the network version with some nifty mail packages and stuff. There, two
- down and three to go.
-
- Modular Windows is going to be the kinda odd one. It's going to be for
- several different types of hardware, including some sort of Nintendo-like
- box, though it's purpose won't be to be a game machine, but in the sense
- that it plugs into the TV and has a little controller and no keyboard. It's
- also going into the Pen computers and such. They had a long list of things,
- but no, I couldn't find Windows for Toasters in there, though they did make
- a passing reference about Fax machines, and I don't know about you, but I
- can dial a phone and press start without Windows, myself. Maybe it's for
- the thinking impaired. Modular Windows is essentially a cut down version of
- Windows 3.1. It has a subset of the API and a bunch of DLLs and unnecessary
- stuff are removed. The idea is to get it down to 1 meg. They said they'd be
- specializing it for each machine it was used on to keep the size at a
- minimum. You could tell that they were really counting on getting computers
- into every household, one way or another.
-
- Actually, some of the ideas sounded pretty cool and they're actually
- working with different vendors to try to make some of it a reality. For
- example, one demo they showed was a program for working with Cable TV. You
- could watch Cable, but let's say you were watching MTV, and a band you
- liked was on. Well, with a little extra bandwidth that's not used by the
- TV, but is used by your little Windows Cable Box, you have access to all
- kinds of information, like what the name of the band is, a list of albums
- and songs, when they'll be playing in your area, and if you want, you can
- click on a button to order your tickets. Want the CD? Click on another
- button and they'll send it to you and bill you through the cable company.
- Now, I don't want to sound like one of those idiots from the 50s who
-
- - 35 -
-
-
-
-
-
-
- thought everyone in the 70s would have a helicopter in there back yard, but
- I really think this kinda thing is going to happen. (By the way, later I'll
- be coming back to that helicopter thing, 'cause I got a bit to say about
- it.) They're actually working with cable box manufacturers and cable
- companies to make this stuff a reality. It's some pretty neat stuff and
- it's about time! They're saying they think this kind of stuff will be
- available, large-scale, by '95. Well, I've never been too fond of
- Microsoft's predictions, as far as timing, so I'm going to take a safe bet
- with '97, but I definately think it'll be there.
-
- Then there's NT. See my column on NT programming yet? Check it out.
- I'm clueless when it comes to NT programming, therefore, over-qualified to
- be teaching it. Anyway, their NT stuff was pretty impressive. Looks like
- they're already heavy into building add-on stuff, like SNA servers (by the
- way, that's the only thing I really thought OS/2 had on NT, not anymore, I
- guess.) They're really pushing the idea of programming with the Win32 and
- Win32s APIs and making everything portable between all the Windows systems.
- Good luck, I say. I'd like to see it, but people are always going to try to
- exploit the specific nooks and crannys that each different version has to
- offer, and that's just life.
-
- NT, staying or going? It's here to stay. It's not going to be on every
- desktop and Microsoft knows it, hence the Win32s API, but it will be fairly
- popular. It's going to be best for workstation stuff, software development,
- servers, and the like. Personally, I love NT as a development environment.
- Compile your 3.1 programs in the DOS box and test them under NT. If they
- crash, who cares, you don't have to re-boot, ever. Great time saver.
-
- Microsoft's going crazy. API-crazy, that is. They must have mentioned
- 6 or 7 of them while I was awake. They've got the Sockets API, Open
- Database Connectivity (ODBC) API, SNA API, Win32 and Win32s API, Mail API
- (MAPI), and, of course, PAPI, the Pizza API. Actually, the last was a joke
- about an API to order Pizza for you, but I wouldn't be suprised to see it.
- They've got APIs left and right and what I want to know is, who's going to
- have time to learn half of them? When we start sending out resumes, we're
- not going to be writing that we know how to program for Windows, we're
- going to be listing the APIs we know how to program for Windows. The ones I
- listed above are just the tip of the iceberg. There are a ton of them out
- there. In an effort to help consolidate on some of this, Microsoft has come
- up with the SPI, or Service Provider Interface. This is sort of an API for
- the APIs. The ODBC API is a good example of how this works. What happens is
- you program for the ODBC API. Then, the guys that write the database
- software, like Oracle, Sybase, DBase, and all those guys, write the SPI.
- That way, no matter which database program you're using the you just have
- to write for the ODBC API. Sounds good, right? Well, yeah, that's fine, but
- I've been programming for a long time, and I know programmer's. The first
- thing they're going to do is get a hold of a bunch of SPIs, find neat
- little tricks they can use that require them to bypass ODBC, because it
- won't support them or something, and then have these 'hard-wired' tricks
- for specific databases. Maybe I'm wrong but people have been talking
- standards for years and what do we have? Undocumented DOS and Undocmented
- Windows. People are always going to be bypassing these standard things so
-
- - 36 -
-
-
-
-
-
-
- they can make their programs jump through hoops.
-
- The worst case of this was someone who was talking to me about writing
- a standard set of APIs for programming in a GUI environment that would then
- have the equivelent of SPIs (remember those) for each GUI, like Windows or
- X-Windows. Then you'd just have to program for one API and it would re-
- compile for each different GUI interface. Yeah, right. Sorry, it'll never
- happen. What happens when you want to use NetBIOS? Sorry, X-Windows doesn't
- have NetBIOS, so your universal API won't either, so you're S.O.L. Anyway,
- just wanted to make that clear that that will not happen.
-
- Ok, so back to Microsoft going API crazy. Well, I have to give them an
- 'A' for effort. They're really busting their collective hump to get tools
- out there for us developpers. Over the next year or two, you can expect to
- see a rich collection of APIs to do everything from getting data off of a
- Nintendo machine via smoke signals to APIs for ordering Pizza. Microsoft's
- really trying to standardize and I applaud their effort, but I've seen a
- lot of people try to do that in this industry, so I remain skeptical.
-
- Another new catch-phrase (or catch-acronym, as the case may be) is
- WOSA which stands for Windows Open Services Architecture. This includes a
- lot of the API and SPI stuff. WOSA is the collection of all these front-
- ends (APIs) with changeable back-ends (SPIs) for different engines. I just
- felt a need to throw the catch-acronym at you. I didn't want you to hear it
- a few weeks later and then say, 'That's what Pete was writing about, but he
- didn't call it that. What an idiot!' Well, I'm not an idiot, I'm just
- stupid.
-
- Well, that about wraps it up. What do I think about all of this? Do
- you care? Do I care? Cool. You Better. Of Course. In that order. I like the
- idea of having a ton of APIs to play with. I've always been a bit of an API
- nut, so I'll be messing with everything I can get my hands on. I think
- Microsoft's going in the right direction and I think Bill's going to keep
- raking in the bucks. I hope the cable-tv stuff happens and I hope I can run
- Windows on my coffee maker in the near future. I can't make good coffee,
- maybe Windows can. Hey, and maybe Windows to flush my toilet, wash my
- clothes and mow my lawn. That's not too much to ask for, is it? Well, you
- may be laughing but Bill's probably working these problems out in his head
- as you read this. We'll see if he can do it.
-
- P.S. Bet you thought I forgot about that helicopter nonsense. Well, I did,
- and after re-reading, I'm adding this. I'm convinced Man has evolved
- tremendously since the 50's. Let's face it, we all know, now, that everyone
- having a helicopter in their driveway is a ridiculous idea. Most drivers
- can't drive. Let's just say that if helicopters were that popular, I'd live
- underground. 'nuff said.
-
-
-
-
-
-
-
- - 37 -
-
-
-
-
-
-
- Accessing Global Variables Across DLL
- by Rod Haxton
-
- In the February issue of WPJ I wrote an introductory DLL article. This
- month I wish to share with the many readers of the WPJ of a way that I
- discovered by necessity of handling global variables across DLLs. I
- describe my approach as a 'kludge' but, to me it is a fairly good 'kludge'.
- Like anything done against the norm there are some risks; like receiving
- flammable E-mail about going against Windows standards, and possibilities
- that Microsoft will change some things and therefore in later versions my
- approach will not work. All of these are possibilities but, I can live with
- those for now. Why? Because I think that it is a feasible kludge and what I
- will show you is nothing that Windows has not been doing since version 2.0
- and it has not changed yet. That is not to say that they will not change,
- but that for now it seems safe to say that they will not.
-
- Here's some background information on why I chose to use the method I
- came up with. Windows already supplies ways of handling global variables
- across DLLs, for instance, shared memory, passing far pointers and
- redeclaring the variables in the DLL. These methods are workable and I
- strongly suggest that they be used. Well, here's the background. I was
- given the task of converting two DOS applications over to Windows and
- making them into one package. My mission was to get it up and running as
- quickly as possible. The original DOS application made use of numerous
- global variables. So, I decided to do a straight port, and after demoing
- the port and management making their decision, I would convert the App over
- to DLLs. Well, the first two steps (ported and mgmt. decision) were
- completed 7 months later. So, now the big job was to fix up everything over
- to DLLs. This was no problem except for the numerous global variables. Hind
- sight told me I was stupid for not dealing with them initially. Handling
- the global variables the way Microsoft suggests would mean that a great
- portion of the code would have to be rewritten, and you know that there
- just is never any time to do that. So, I began to think to myself, and I
- remembered reading about Micheal Geary's FIXDS. The same logic he applied
- to not having to call 'MakeProcInstance' also applied to what I was
- thinking.
-
- The stack segment (SS) for DLLs is that of the calling application.
- And, the calling apps. DS == SS. Therefore, any global variables (CONST and
- BSS) defined in the application is shared with the DLL via SS. The only
- problem is that you have no clear way of accessing those variables. In
- Windows global variables in segments do not change their offsets, only the
- segments can be changed due to memory management. Thus, the offset values
- of the global variables will always be at the same location inside the
- segment. Knowing this, how do we determine those offsets? The answer is the
- MAP file that the compiler will supply for you. The MAP file lists all
- global symbols defined in the object file(s), sorted by name and a list
- sorted by address. With this information in hand we can make a file of all
- the global variables used in the program. The global list should use the
- same case as the actual definitions. Also, since the MAP file sorts the
- variables by name and thats what we are looking for, the matching variable
- names and their offsets, our list file should be sorted, this will speed
-
- - 38 -
-
-
-
-
-
-
- the search. I wrote a utility program that I call "getoff.exe", that
- searches the MAP file and creates an output constants file of the
- variables, i.e.,
-
- GLOBAL HEADER FILE INPUT FILE FORMAT OUTPUT FILE FORMAT
- ------------------ ----------------- -------------------
- int variableA; variableA #define VARIABLEA 0x0001
- int variableB; variableB #define VARIABLEB 0x0002
- int variableC; variableC #define VARIABLEC 0x0003
-
- The outputted constant file is to be included in the DLL modules. I forgot
- to mention one thing. The global variables must be declared inside the DLLs
- also. The cleanest way would be to include them in a global header file.
- Now with the use of some in-line assembly code the global variables can be
- accessed and updated inside the DLL.
-
- #include "consts.h"
- #include "global.h"
- .
- .
- .
- /* this code sets up the variables inside the DLL */
- _asm mov ax, ss:[VARIABLEA]
- _asm mov [variableA], ax
-
- _asm mov ax, ss:[VARIABLEB]
- _asm mov [variableB], ax
-
- _asm mov ax, ss:[VARIABLEC]
- _asm mov [variableC], ax
-
- /* now use the variables like normal */
- variableC= variableB;
- variableB= variableA;
- variableA= variableC;
-
- /* when finish reasign the values to the global */
- /* variables defined in the application */
- _asm mov ax, [variableA]
- _asm mov ss:[VARIABLEA], ax
-
- _asm mov ax, [variableB]
- _asm mov ss:[VARIABLEB], ax
-
- _asm mov ax, [variableC]
- _asm mov ss:[VARIABLEC], ax
-
-
- This is all it takes to accomplish the task of using global variables
- across DLLs. I created (for my company's purposes) entry/exit routines that
- handle the assigning and re-assigning of the variables, only because our
- application has over 100 global variables.
-
- - 39 -
-
-
-
-
-
-
- Included with this document is the "getoff.exe" utility and its
- source, and source and executable example of a DLL accessing a global
- variable. To run "getoff" type 'getoff <mapfile name> <input file>'. As I
- stated, this is only a kludge, and so this method should only be used if
- you do not have time to rewrite code and you have too many global
- variables. If you have the fortunate pleasure of creating your own
- application try to stay away from global variables, but if you must, handle
- them the way Microsoft suggests.
-
- Rod Haxton can be reached at (202) 269-3780.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 40 -
-
-
-
-
-
-
- Getting A Piece Of The Future
- By Peter Kropf
-
- A few months ago, a computer trade publication ran an article in a
- regular column stating that anyone can obtain a beta copy of Windows NT.
- It would cost $69 without hard copy documentation, or $399 with a document
- set. There have been other short blurbs that I had read which gave a very
- brief view of Windows NT. Here was a chance to get the real thing.
-
- While waiting for the package to arrive from Microsoft, a trip to the
- local book store turned up a book called "Inside Windows NT" by Helen
- Custer. The book was written during the development process. At times it
- seems to read like a marketing brochure, but on the whole, I enjoyed
- reading it. The first two chapters were outstanding. They gave a
- wonderful overview to the various features and concepts of Windows NT. The
- remaining chapters discuss the features and concepts in much more detail,
- but the detail still remained at the surface level. Most of the features
- described read like VMS, The Next Generation. For those of you that don't
- know, Windows NT's chief driver is David Cutler, the same man who drove the
- initial development of Digital's VMS operating system. After reading
- through the book, I was very anxious to try Windows NT.
-
- There were a few hurdles to overcome before getting the system up and
- running. The distribution media is CD-ROM only. What that means is you
- must actually have a CD-ROM drive. Some of us (namely me) are a little
- slow. Until the media, computer and user were all physically in the same
- place, it just didn't click.
-
- The first drive purchased is a bundled package, one of those
- multimedia upgrade kits. Sound card/SCSI port/CD-ROM all in one. Great.
- Well, not so great. The SCSI port is not on the list of those currently
- supported by Windows NT. That means Windows NT can not be installed
- directly from the CD-ROM. Instead, all the required pieces are copied to a
- temporary working directory and a bootable starter floppy is created while
- running under MS-DOS. The system is then booted from the floppy and the
- installation of Windows NT actually begins. Once the installation is
- complete, Windows NT is booted directly from the hard disk. But, the SCSI
- port on the sound card is not currently recognized by Windows NT, therefore
- the CD-ROM drive cannot be accessed. That isn't really too bad until an
- attempt is made to change the configuration. It tries to read from the
- temporary load directory. But that directory was deleted after the
- installation completed! (The solution here was to boot under MS-DOS and
- copy the needed files into a directory that NT can then read.)
-
- What's that you say? Most hardware vendors have a 30 day money back
- guarantee/exchange policy? Gee you're right. Back the upgrade kit goes.
- A faster drive which is accessible from NT is required. Why? Well I don't
- know. Just because, that's why. An Adaptec 1542B with a Texel CD-ROM
- drive does the trick. Now my multimedia windows applications can access
- the CD-ROM directly while running under NT. Of course a sound card is now
- needed to allow complete multimedia.
-
-
- - 41 -
-
-
-
-
-
-
- After the installation completed, poking around the directories
- reveals some interesting things. There are a few new files in C:\ which
- are required by NT.
-
- WINNT Directory structure for NT.
- NTDETECT.COM Machine boot process
- NTLDR Machine boot process
- USERS Directory structure for NT users.
- BOOT.INI NT initialization information
- CONFIG.NT NT's version of CONFIG.SYS
- AUTOEXEC.NT NT's version of AUTOEXEC.BAT
- PAGEFILE.SYS NT's primary page file.
- BOOTSECT.DOS Purpose unknown. Hidden file.
-
- When the machines boots, it goes through the standard hardware testing
- and then loads NTDETECT/NTLDR/BOOTSECT.DOS. (At this time, I'm not certain
- of the relevance of these three files, their order and use at boot time are
- still unclear to me.) A menu is displayed with the entries in BOOT.INI:
- Windows NT from C:\winnt and the previous operating system from C:\. This
- allows either one to be easily booted. A timer is set for 30 seconds by
- default to wait for a selection. After either the timer has reached zero
- or the user has selected an OS, the highlighted entry is booted.
-
- MS-DOS boots without any problems. It's nice to be able to easily
- select which system to use.
-
- Selecting NT to boot begins a much different process. First the
- kernel and device drivers are loaded. Then all the known file systems are
- checked. (NT supports FAT, HPFS and NTFS.) If the file systems need to be
- rebuilt or fixed, this is where it would happen. All the partitions here
- are setup as FAT. So far, the checking process has never complained and no
- repair work has ever been done. After everything is checked, NT begins
- working. A bitmap screen is displayed stating that this is Windows NT
- BetaOctober '92 Release.
-
- Once NT has started all the required processes, a message is displayed
- indicating that CTRL-ALT-DEL are to be pressed to login. The standard
- CTRL-ALT-DEL to reboot the system whenever a problem occurs is gone. NT is
- a true pre-emptive multitasking operating system. One of the things this
- being along with it is the fact that disk I/O is now buffered in memory.
- Powering down the system without first requesting buffers to be flushed
- will most certainly cause file corruption. Anyone whohas ever crashed a
- Unix system will understand. The CTRL-ALT-DEL sequence will also ensure
- that the real logon screen is being displayed, not an attempt at capturing
- passwords.
-
- Once signed on, most things look the same. There are several new
- features and programs available such as user maintenance, disk maintenance
- and event log review, but their explanations are for a later time. Pressing
- CTRL-ALT-DEL after signing on brings up a window which allows almost
- complete control over the work currently being done. A task can be
- stopped, the user can be logged off, the system can be shutdown, along with
-
- - 42 -
-
-
-
-
-
-
- a few others. Shutting down the system has two options, one for a complete
- poweroff, and the second to shutdown NT and then reboot. The second option
- behaves much like CTRL-ALT-DEL while running under MS- DOS, allowing the
- system to be shutdown and rebooted in the event of a major problem.
-
- This brings to a close a first look at getting NT running on a Intel
- 486-based machine. Since NT will run on many other hardware platforms
- including the Mips R4000 and Digital's Alpha, getting a system up and
- running on those machines might be a little different. The next article
- will take a look at the additional features and programs available from the
- Program Manager.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 43 -
-
-
-
-
-
-
- The "ClickBar" Application
-
- ClickBar consists of a Dynamic Dialog pair that allows C developers for
- Windows 3.0/3.1 to insert a "toolbar" into their application. Microsoft,
- Borland, etc. developers may display a toolbar or tool palette inside their
- application, according to a DLG script in their .RC or .DLG file.
-
- Borland developers may install ClickBar as a custom control, providing
- three custom widgets added to the Resource Workshop palette. These are
- three different button profiles defining 69 custom button images total.
- The buttons may be placed and assigned attributes identically to the
- intrinsic Resource Workshop widgets.
-
- Source is provided for a complete example of using the tools, including the
- use of custom (owner-drawn) bitmaps for buttons.
-
- Version 1.5 uses single-image bitmaps to reduce the DLL size, and includes
- source for a subclass example for inserting a toolbar.
-
- Registration is $35 and includes a registration number and printed manual.
-
- WynApse
- PO Box 86247 (602) 863-0411
- Phoenix, AZ 85050-6247 CIS: 72251,445
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 44 -
-
-
-
-
-
-
- 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.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - 45 -
-
-
-
-
-
-
- The Last Page
- by Mike Wallace
-
- Got this in the mail today. WPJ has the coolest readers. Hope you
- like it.
-
- Date: 01-Apr-93 12:41 EST
- From: Mike Strock >INTERNET:MikeS@asymetrix.com
- Subj: Humor: Health Tips for the 90s
-
- BURNOUT PREVENTION AND RECOVERY
-
- 1. STOP DENYING. Listen to the wisdom of your body. Begin to freely admit
- the stresses and pressures which have manifested physically, mentally or
- emotionally.
-
- MICROSOFT VIEW: Work until the physical pain forces you into
- unconsciousness.
-
- 2. AVOID ISOLATION. Don't do everything alone! Develop or renew
- intimacies with friends and loved ones. Closeness not only brings new
- insights, but also is anathema to agitation and depression.
-
- MICROSOFT VIEW: Shut your office door and lock it from the inside if you
- can so no one will distract you. They're just trying to hurt your
- productivity.
-
- 3. CHANGE YOUR CIRCUMSTANCES. If your job, your relationships, a situation
- or a person is dragging you under, try to alter your circumstances, or if
- necessary, leave.
-
- MICROSOFT VIEW: If you feel something is dragging you down, suppress those
- thoughts. This is a weakness. Drink more coffee (it's free).
-
- 4. DIMINISH INTENSITY IN YOUR LIFE. Pinpoint those areas or aspects which
- summon up the most concentrated intensity and work toward alleviating that
- pressure.
-
- MICROSOFT VIEW: Increase intensity. Maximum intensity = maximum
- productivity. If you find yourself relaxed and with your mind wandering,
- you are probably having a detrimental effect on the stock price.
-
- 5. STOP OVERNURTURING. If you routinely take on other people's problems
- and responsibilities, learn to gracefully disengage. Try to get some
- nurturing for yourself.
-
- MICROSOFT VIEW: Always attempt to do everything. You ARE responsible for it
- all. Perhaps you haven't thoroughly read your job description.
-
- 6. LEARN TO SAY "NO". You'll help diminish intensity by speaking up for
- yourself. This means refusing additional requests or demands on your time
- or emotions.
-
- - 46 -
-
-
-
-
-
-
- MICROSOFT VIEW: Never say no to anything. It shows weakness, and lowers
- the stock price. Never put off until tomorrow what you can do at midnight.
-
- 7. BEGIN TO BACK OFF AND DETACH. Learn to delegate, not only at work, but
- also at home and with friends. In this case, detachment means rescuing
- yourself for yourself.
-
- MICROSOFT VIEW: Delegating is a sign of weakness. Don't let someone else do
- it (See # 5).
-
- 8. REASSESS YOUR VALUES. Try to sort out the meaningful values from the
- temporary and fleeting, the essential from the nonessential. You'll
- conserve energy and time, and begin to feel more centered.
-
- MICROSOFT VIEW: Stop thinking about your own problems. This is selfish. If
- your values change, we will make an announcement at the company meeting.
- Until then, if someone calls you and questions your priorities, tell them
- that you are unable to comment on this and give them the number for
- Microsoft Marketing. It will be taken care of.
-
- 9. LEARN TO PACE YOURSELF. Try to take life in moderation. You only have
- so much energy available. Ascertain what is wanted and needed in your
- life, then begin to balance work with love, pleasure and relaxation.
-
- MICROSOFT VIEW: A balanced life is a myth perpetuated by the Borland
- Marketing Team. Don't be a fool: the only thing that matters is work and
- productivity.
-
- 10. TAKE CARE OF YOUR BODY. Don't skip meals, abuse yourself with rigid
- diets, disregard your need for sleep or break the doctor appointments. Take
- care of yourself nutritionally.
-
- MICROSOFT VIEW: Your body serves your mind, your mind serves the company.
- Push the mind and the body will follow. Drink Mountain Dew (it's free).
-
- 11. DIMINISH WORRY AND ANXIETY. Try to keep superstitious worrying to a
- minimum - it changes nothing. You'll have a better grip on your situation
- if you spend less time worrying and more time taking care of your real
- needs.
-
- MICROSOFT VIEW: If you're not worrying about work, you must not be very
- committed to it. We'll find someone who is.
-
- 12. KEEP YOUR SENSE OF HUMOR. Begin to bring joy and happy moments into
- your life. Very few people suffer burnout when they're having fun.
-
- MICROSOFT VIEW: So, you think your work is funny? We'll discuss this with
- your manager on Friday. At 7:00 pm.
-
-
-
-
-
- - 47 -
-
-
-
-