Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

.NET

A Multitool Approach to Windows Development


SP93: A Multitool Approach to Windows Development

Al is a contributing editor to DDJ and can be contracted at 411 Borel Ave., San Mateo, CA 94402.


It's no secret that programming for GUIs like Windows is difficult. It takes a long time to become expert in each GUI. And because no two are alike, even if you are proficient in one GUI, you can't transfer much of that experience to another.

Consider the learning curve for a new Windows programmer. The first hump is the event-driven programming model. It's not quite object oriented, and it's not quite traditional procedural programming. Once you understand the model, you must learn all of the messages, functions, and nuances of each. The API has almost 1000 functions. Few programmers can remember them all, and you must develop an associative memory about them so that a given need reminds you of the message or function that will solve the problem at hand. Then there's the folklore. Windows programmers learn tricks, workarounds, and undocumented features to get over the hurdles and toward a working application. Debugging a Windows application is another issue. Windows debugging can be art in itself, sometimes involving multiple monitors, perhaps even two computers connected on a network or by a serial cable. Only recently have Windows-hosted debuggers become available.

The approach I'll discuss here is based on Borland C++, tested with Turbo Debugger under DOS. The version of the program I present is for testing only, designed to verify the application-specific algorithms without regard to the user interface, which is a stubbed iostream module. Once I've debugged the application, I convert it to a Windows DLL and integrate a Visual Basic UI front end. The result is a complete Windows application, developed without a lot of Windows programming knowledge and retaining the strength of a platform-independent C++ design.

Visual Development Environments

Visual development environments (VDEs) and class libraries are emerging to address the difficulties in programming Windows. They encapsulate much of the API and provide visual UI composition tools that take much of the burden off the programmer. Though not the first of its kind, Visual Basic changed the nature of software development for GUI platforms when it combined the traditional Interactive Development Environment (IDE) with visual resource-design tools and defined what visual programming should be.

In a visual development environment, a programmer uses interactive tools to build windows and dialog boxes, constructing the visual parts of the application on the screen as they will appear in the running program. Then the programmer attaches fragments of code to user events: menu selections, button presses, mouse movements, and so on. Visual Basic programmers use a structured superset of Basic for this code. Visual Basic caught on because it is easy to learn, easy to use, and lets non-Windows programmers write Windows applications.

The success of Visual Basic was followed by cries from programmers for visual versions of other languages. Loudest of these calls came from C and C++ programmers. Now there are tools that support visual programming environments with C++ as the host language. Visual C++ is Microsoft's answer to that cry. Application::ctor (pronounced "constructor"), from Compass Point Software, is a similar product that aims a smaller dart at the same big target. (See the accompanying textboxes entitled, "Visual C++" and "Application::ctor," respectively.)

If you are looking for Visual Basic with a C or C++ dialect, forget it. Neither of these products is to C and Windows what Visual Basic is to Basic and Windows. Visual Basic is an interpreted language that seamlessly integrates user- interface design and application development. Visual C++ and Application::ctor are applications generators. They generate C++ source code from your visual design and compile it for you. The advantages of an applications generator over an interpreter are that the compiled applications run faster and do not need the interpreter's dynamic link library, which means that you don't have to distribute and install a third-party DLL with your application. Furthermore, the application's source programs are complete, stand-alone modules that you can modify and recompile outside of the visual programming environment. As such, they have access to all of the features available to a traditional Windows program. There is no new wall to hit.

However, certain disadvantages become apparent during development. An interpreted program runs slower than a compiled one, but the interpreter builds a testing application faster. A C/C++ interpreter is possible, but neither Visual C++ nor Application::ctor uses one. The development model is different, too. With Visual Basic you click a control on your design, and instantly you are editing the code that processes the control's command. Make a small change, tell the interpreter to run the program, and the program runs without delay. Stop in the middle, change something else, and resume running. Everything is integrated and fast. A programmer hammers out an application in the shortest possible time. A C/C++ applications generator could work that way, but these two do not.

Both Visual C++ and Application::ctor loosely associate, rather than tightly integrate, design and development. You design the windows; the generators then build a skeletal source program. Next, you modify and add source code. However, instead of clicking a button on your design to go directly to the button's event code in an editor, you navigate to the code through lists. First you view the class that represents the window that gets the event. Then you select the event member function from a list. It's a bit of a trek from the window with the button on it to the C++ code that executes when the user clicks that button. Once you get there and add or change some code, you have to compile and link the program. Both systems automate that process, but they take longer than Visual Basic to rebuild an application after you've made even the smallest change. That's the price you pay for compiled code.

If you are looking for a visual programming environment that frees you from the drudgery of the Windows API, forget that, too. An application developed with either Visual C++ or Application::ctor needs code fragments associated with user events. You must write the appropriate C++ code within the member functions of the window classes. With either package, this process requires a thorough understanding of Windows programming. The class libraries do not encapsulate everything. There are things you will want to do for which no member functions exist.

And if you are a C programmer who does not want to learn C++, neither of these products is for you. Both are bound to class libraries that encapsulate some of the Windows API. You must know how to read and use C++ classes, and you must become an expert on the particular class library that each product uses. To add functionality to an application, you modify the derived classes that the generators build, adding data members and member functions. To communicate between windows you must know how to send C++ messages to instantiated objects of classes. To know what messages are available to a derived class, you must understand inheritance, function overriding, and virtual member functions. All of that requires C++ skills.

Rather than reducing the knowledge required from a would-be Windows programmer, these packages add to it. You need to know the API; you need to know C++; you need to know the class libraries. That's not necessarily bad, however. If you want to be a power Windows programmer, you need those skills anyway. You have to immerse yourself in the hundreds of API functions and messages and all the underground folklore about undocumented features and such. You must know C++ intimately and have a decent class library that encapsulates as much of the Windows API as possible. However, if all you want is to knock out an occasional custom Windows application without joining the priesthood, there is no C or C++ solution for you, so you'd better stick with Visual Basic.

The main difference between Visual Basic and these new programs is, therefore, the length and pitch of the learning ramp: short and flat vs. long and vertical. Other differences are aesthetic and relative to what you were doing before. A C++ Windows programmer coming to Visual C++ or Application::ctor from the SDK/API environment will be impressed. A C programmer who has been using Visual Basic while waiting for a visual C environment will be disappointed.

But VDEs tend to bind the application to the platform. A Windows program developed with a VDE--or any other tool, for that matter--is anything but portable.

The result is that applications written for today's GUI platforms--Windows in particular--tend to be nonportable. The algorithms that support most applications should be virtually platform independent, yet porting applications between GUIs usually involves a complete rewrite.

How important is portability to an application? In an interview in the C++ Special Supplement to Dr. Dobb's Journal (December 1992), Bjarne Stroustrup said, "Portability is an economic issue. You're portable if it's cheaper to modify the program [than to] build a new program from scratch."

The issue is cost. The secret is to foresee, project, and manage that cost during the design and development of a program's first version. If you're hammering out a custom application for a user, portability is not an immediate concern. But if the user changes systems and wants to take the application along, portability becomes an instant and important issue. If you planned for it, you're one step ahead; if not, you must start over.

Designing Windows Apps

The approach to Windows development presented here involves five stages of design and development:

  • 1. Develop the application for DOS in generic C or C++. Don't worry about the UI.
  • 2. Build a functional API into the application. Use a DOS/Windows porting layer with compile-time conditionals that translate the API into either C++ functions or Windows-exportable DLL functions.
  • 3. Test as a DOS application with a command-line UI stub and a DOS source-level debugger. Get the application-specific algorithms working in the least intrusive environment. The UI stub calls the API as C++ functions.
  • 4. Convert the application to a Windows DLL. Properly planned, this is a simple matter of recompiling the application and allowing the porting layer to establish the API as exportable DLL functions.
  • 5. Develop the UI in Visual Basic. The Visual Basic program interfaces with the now-debugged application DLL by calling the exportable API functions.
The advantages of this approach are as follows:

  • You don't need to be a Windows-programming expert to develop a Windows application. A strength of Visual Basic is that it encapsulates the Windows API in ways that hide it from the programmer.
  • The substance of the application is not bound to the performance limitations of interpreted Visual Basic. Interpreted code does not execute as efficiently as compiled native code. By offloading the application-specific, processor-intensive processes to the C++ DLL, you put the power of the compiled language where it is needed. Interpreted Visual Basic is used only for the interactive parts.
  • Having been written in C/C++, the application, is essentially platform independent. A project can leverage its investment in the C/C++ application code from an earlier version on a different platform.
  • You can take your time rewriting the UI with a more-efficient C/C++ class library such as MFC or OWL with few or no changes to the application code.
  • This approach encourages a team effort, in which the UI team develops the Visual Basic stuff, perhaps working with a dummy applications DLL. The applications team develops the application, using DOS to simulate the user interface. The interface between the two efforts is clearly defined: exportable C/C++ functions that exchange strings and numbers between the two parts of the application.
  • If the stubbed DOS user interface is usable, a by-product is a DOS application. If not, a third team can integrate the DLL with a DOS user-interface tool.
  • The rapid prototype nature of this approach allows you to field a working system in the shortest possible time.

Memoir: A Case Study

To illustrate this approach, I'll use a small Windows application called "Memoir" that resembles the Windows Cardfile application, but is more suitable for storing short notes. Each note has a subject and text, and the user can search the database for a key word or phrase match.

The Memoir application code is written in Borland C++, and its UI in Visual Basic. The source code is available electronically; see "Availability," page 3.

The first part of the program design considers which functions will be written in C++ and which are deferred for the UI. All file storage and retrieval is written in C++. The search algorithm is in C++, and everything related to screen displays and user input is in Visual Basic. This dividing line clearly separates the GUI-dependent code from code unique to the application--and that's the objective.

To develop the application, I use the Borland C++ 3.1 compiler, the Brief 3.1 programmer's editor, and Turbo Debugger. You can use any compiler/editor/debugger package, including an integrated development environment (IDE), as long as it supports Windows DLL development.

With the responsibilities of both parts of the system defined, it's now necessary to establish the interface between the two. In its final version, the Memoir application code will be in a DLL. Visual Basic programs can call DLL functions with some small restrictions. Therefore, the interface consists of API function calls that comply with the Visual Basic/DLL specification. Initially, however, the program will be tested from DOS, so the API must be compatible with DOS C++ programs, too. Listing One (page 13) is the API as taken from the memoir.h header file. Note the #define statement for APPLAPI. While programming in DOS, the global is an empty token. Later, that token helps to make the program a DLL.

The API consists of functions to open and close the database and add, find, change, and delete documents. The functions are representative of UI-independent, application-specific algorithms. The functions pass string parameters by reference, which is a Visual Basic convention. It's also a C/C++ convention, so the API should adapt well to porting to other GUIs or other Windows user-interface tools.

To test the application, use a simple DOS command-line UI. The source-code module that simulates the UI won't be a part of the DLL. It should, however, have enough functionality to exercise all of the features of the application. Listing Two (page 13) is an abstract of the Memoir UI stub. Along with a few supporting functions that read user input and display output, this stub is all that is needed to test the essence of the application. Listing Three (page 13) is the Memoir makefile that builds the DOS test version.

The application itself consists of three source files--applapi.cpp, database.cpp, and search.cpp--plus the memoir.h header file. The details of how they work aren't important to this discussion. It's enough to know that they implement the storage, search, and management of documents in the database. The uistub.cpp program is the DOS UI stub. Note the DOS_VERSION conditional that is defined by a command-line switch.

Because this is a DOS C++ program, you can use Turbo Debugger to test it. The program uses the fstream class to read and write the database. It uses the C++ new and delete operators to allocate memory from the heap. Other than for the unconventional APPLAPI usage, there's nothing in the code to indicate that it will be included in a DLL after it is debugged.

The DOS_VERSION compile-time conditional specifies that the code is being compiled as a DOS program. It's used in memoir.h as in Listing Four (page 13). When DOS_VERSION is defined, the APPLAPI token is an empty comment. When it is not defined, the program includes windows.h and defines the token to add the FAR _export PASCAL qualifiers to the API functions. These qualifiers are required for DLL functions that will be called from Visual Basic.

All of the API functions are compiled with the extern "C" linkage specification so that their names are not mangled by the C++ compiler and are accessible to the caller.

Windows Development

After the application program is fully tested as a DOS program with the UI stub, it can be built as a DLL. I use Turbo C++ for Windows (TCW) to do that. I could use the Borland C++ command-line compiler, but the Windows-hosted TCW IDE is more convenient for making small changes to the DLL during Windows testing.

The DLL substitutes a small source module for the user-interface stub. Listing Five (page 13) is the source module, dll.cpp. The LibMain and WEP functions are the standard entry and exit points for a DLL. RegisterAppl allows the Visual Basic program to determine if a prior instance of the application is running. The Memoir program does not want multiple instances of itself running because it uses a constant database filename. Subsequent instances of the program would run into sharing problems.

The DLL project file includes the module-definition file, the same applapi.cpp, database.cpp, and search.cpp source files that the DOS makefile includes, and the dll.cpp file that contains the DLL-specific code.

The UI code is developed in Visual Basic. Memoir is a single-document interface application with a menu and some text boxes and buttons. Memoir communicates with the application DLL by declaring the API functions in Listing Six (page 13) in the MODULE1.BAS source file.

Listing Seven (page 13) is taken from the Visual Basic part of the application. This code executes when the application window is first loaded. It calls RegisterAppl to see if an earlier instance of the program is running. If so, this program calls a Windows API function to give the focus to the original instance. Otherwise the program calls the API to open the database, read the first document, and put its text into the application window.

I keep all the code under the main subdirectory named MEMOIR, which has two subdirectories named VB and DOS. The DOS subdirectory code contains the C++ source files, the DOS makefile, the DLL definition file, and the TCW project file. The VB subdirectory has the Visual Basic source files.

When TCW builds the DLL, it writes the .OBJ and .DLL files into the VB subdirectory, where they can be found by the Visual Basic runtime. When the bcc command-line compiler builds the DOS executable, those .OBJ files and the .EXE are written into the DLL subdirectory. With this setup, the two make processes do not confuse dependent object modules.

I set up a Program Manager group window for Memoir development. It contains icons to execute Visual Basic, BCW++, MS-DOS, and the Memoir executable file itself. By building a specialized Program Manager group, I can cause the different development environments to start up in the correct subdirectory and to execute with the relevant file on the command line. This procedure saves time. Each execution of Visual Basic, for example, does not need to first load the default empty application and all the VBX controls.

Conclusion

Using the tools and techniques presented here, you can develop a Windows application without possessing extensive knowledge about Windows programming. You'll be able to use existing C/C++ applications code, and the applications code itself will be relatively portable to other platforms.

Visual C++

Visual C++ 1.0 is Microsoft C/C++ 7.0 with the Foundation Class library (MFC 2.0). It's also surrounded by some visual development tools and the compiler is called "Version 8.0."

To build an application, you begin in the Visual Workbench, an IDE-like multiple document interface (MDI) program that manages an application as a project. You start with nothing, and must first define a project to manage your application.

The AppWizard tool builds skeleton source code for the application. First, you name the project and specify the subdirectory for all the source files. You then decide whether the application will use the single or multiple document interface, if it will have a tool bar, if there will be print commands, and so on. You look at the classes that AppWizard creates and change the source-code filenames if you want to. Make all of these decisions carefully. It's your only chance. When you are done, AppWizard builds a makefile for the project and the source files for the skeleton application. If you must make changes, you will need to learn the format of that makefile, change it yourself with an editor, maybe delete or rename some source files and change their contents, and rebuild everything, all outside of the visual environment, all definitely not visual.

Having described an application to AppWizard, you build it from the Visual Workbench. Without adding any code, you can compile an impressive, running Windows program with a menu, a tool bar, a status bar, and document windows. Certain dialog boxes will retrieve and store documents; others will print documents, preview printed output, and select printer options. You can move the application window around, change its size, and minimize, maximize, restore, and exit from it, all in the standard CUA way. Most commands have buttons on the tool bar, too. The application doesn't do anything yet, but a lot of the code that you wrote for yourself in the old days has been written by the AppWizard tool.

You modify the source code in the Workbench's editor windows. When you change something, the next Build command senses the change and, in typical, well-behaved makefile fashion, rebuilds the dependent targets. Some of the changes might require a Rebuild All command, which recompiles everything, but the Workbench doesn't do that automatically. The symptom might be a breakpoint at a source line other than the one you thought you selected, or it might be a cryptic error message saying that the project database is out of sync. When things don't look quite right, run the Rebuild All command yourself. That should straighten things out.

The Class Wizard tool provides a list of the classes in your application and the events that they process. At first, there are four classes: the application, the main frame window, the document, and the view of the document. As you add document types, views, dialog boxes, and so on, the number of classes increases. Each class has a list of object identifiers. For example, a dialog box will have an object for itself and one for each of its controls. Each object identifier has a list of Windows messages that it can receive. Each message may have an associated class-member function. You can add and modify member functions from the Class Wizard to define the behavior of the application.

The App Studio tool builds resources: menus, dialog boxes, strings, bitmaps, icons, and accelerators. The AppWizard has already built a menu and a bitmap for the tool bar, and there are already some default dialog boxes. You use App Studio to add to and modify these resources. When you add a menu selection, for example, you assign it properties, such as whether it is enabled, checked, and so on, and you give it an object-identifier code. The menu is associated with the identifier of an already-defined frame-window class. To add code to process the new menu selection, you exit from App Studio, go into Class Wizard, select the frame window class, find the new object- identifier code, select from the two messages that it can receive, select the Add Function command, and approve or change the function identifier that Class Wizard assigns. You are then in the editor, ready to add code. Compare that to Visual Basic, where you click the menu selection and edit the code.

Visual C++ supports the advanced VBX controls that Visual Basic Professional programmers have. These controls have the three-dimensional look with beveled boxes, buttons that stay down, gauges, grids, and other specialized controls.

--A.S.

Application::ctor

Application::ctor (pronounced "constructor") from Compass Point Software is an applications generator that generates C++ source code from your visual design, then compiles it for you. The advantages of an applications generator over interpreters (like Visual Basic) are that the compiled applications run faster and don't need the interpreter's DLL, which means that you don't have to distribute and install a third-party DLL with your application. Furthermore, the application's source programs are complete, stand-alone modules that you can modify and recompile outside of the visual programming environment. As such, they have access to all of the features available to a traditional Windows program.

Application::ctor is not self-contained. You need a C++ compiler. It supports the Borland, Microsoft, and Zortech C++ compilers. There is no integrated debugger. To debug Application::ctor programs, you modify the generated makefile and exit from the environment to debug with the debugger that comes with your compiler.

When you run Application::ctor, it opens an empty MDI frame window. When you start to build a new application, the main window gets four document windows, representing the four kinds of objects you can build. An application consists of window objects, menu objects, graphic objects, and string objects. You design your application windows and dialog boxes in the Window Objects document window. The menu bar, pull-down menus, and floating menus are in the Menu Objects document. Graphics are in the Graphics Objects document, and strings are in the Strings Objects document.

You can build a prototype of your application's user interface without writing any code. For example, the Window Objects document contains an icon for each of the windows that you define. Double click on an icon, and you're running the View Editor for that window. The View Editor is where you define the size and position of the window and where you add controls: buttons, text, edit boxes, list boxes, and so on. You drag control icons from a tool bar to the window. Then you modify the appearance and behavior of each window and control by changing the values of window and control properties and by assigning functions to events.

A window or control exhibits behavior in response to events. Each window and control is an object of a class. The Application::ctor View Editor associates events with class member functions, and the system includes enough prototype member functions to permit you to build most of the application as a visual mockup. You add custom behavior by deriving classes from Application::ctor classes and adding member event functions. These derived classes are called "window managers." The Application::ctor program adds your custom C++ manager functions to the list of functions that you can associate with events. You write these class definitions and implementations in a prescribed format, and then you run the C++ Source Browser to incorporate those source files into Application::ctor's list of programs to build.

When you design a window, you're looking at it on the screen. As you change the design, the representation changes. Certain aspects of that design are not so easy to use, however. For example, to change the window's size and position, you enter the coordinates and dimensions into a dialog box. You don't really see the menu bar on the mockup window. You see the name of a menu-bar object that you build in the Menu Objects window.

You can design dialog boxes and open them automatically using the prototype function that Application::ctor generates. But these default dialog boxes are modeless, which means that the user can select other windows and menus in the application while the dialog box is active. The user can even select the command that opened the dialog box and open another copy of the same one. To build a modal dialog box requires some tricks in a window manager.

There are procedures common to every application that you have to use to build and run the application. You have to tell Application::ctor to build the .DEF file and the makefile. If you have changed your custom source code, you have to run the Source Browser and rebrowse your source. Your only indication that source code has changed is that the system did not build the .EXE file and won't run your application.

--A.S.



[LISTING ONE]

#define APPLAPI /* */

void APPLAPI OpenDocuments(char *dbname);
void APPLAPI CloseDocuments(void);
void APPLAPI AddDocument(char *Subj, char *Text);

void APPLAPI DeleteDocument(void);
void APPLAPI ChangeDocument(char *Subj, char *Text);
int  APPLAPI FindDocument(char *key, char *Subj, char *Text);
void APPLAPI GetFirstDocument(char *Subj, char *Text);
void APPLAPI GetNextDocument(char *Subj, char *Text);
</PRE>
<P>
<h4><a name="03ce_000d"><a name="03ce_000e"><B>[LISTING TWO]</B><a name="03ce_000e"></h4><pre>

void main()
{
   OpenDocuments("test.dat");
   int done = 0;
   while (!done)   {
      cout << "\n ----------------------------------";
      cout << "\n Add Srch Fst Nxt Chg Del List Quit ";
      cout << "\n ----------------------------------\n";
      switch (getch())   {
         case 'a':
            AddDocument(Subject, Text);
            break;
         case 's':
            if (FindDocument(Keyword, Subject, Text))
               DisplayDocument();
            break;
         case 'f':
            GetFirstDocument(Subject, Text);
            DisplayDocument();
            break;
         case 'n':
            GetNextDocument(Subject, Text);
            DisplayDocument();
            break;
         case 'c':
            ChangeDocument(Subject, Text);
            break;
         case 'd':
            DeleteDocument();
            break;
         case 'l':
            GetFirstDocument(Subject, Text);
            while (*Subject)   {
               ShowSubject();
               GetNextDocument(Subject, Text);
            }
            break;
         case 'q':
            done = 1;
            break;
         default:
            break;
      }
   }
   CloseDocuments();
}
</PRE>
<P>
<h4><a name="03ce_000f"><a name="03ce_0010"><B>[LISTING THREE]</B><a name="03ce_0010"></h4>
<P>
<pre>

   bcc -ml -c -v -DDOS_VERSION {$*.cpp }

OBJS=uistub.obj applapi.obj database.obj search.obj

memoir.exe : $(OBJS)
   bcc -v -ml -ememoir.exe $(OBJS)
</PRE>
<P>
<h4><a name="03ce_0011"><a name="03ce_0012"><B>[LISTING FOUR]</B><a name="03ce_0012"></h4>
<P>
<pre>

#ifdef DOS_VERSION
#define APPLAPI /* */
#else
#include <windows.h>
#define APPLAPI FAR _export PASCAL
#endif
</PRE>
<P>
<h4><a name="03ce_0013"><a name="03ce_0014"><B>[LISTING FIVE]</B><a name="03ce_0014"></h4>
<P>
<pre>

#include "memoir.h"

static HINSTANCE hInst = NULL;


extern "C" {
int FAR PASCAL LibMain(HINSTANCE hInstance, WORD wDatSeg,
                  WORD cbHeapSize, LPSTR lpCmdLine)
{
   if (hInst == NULL)   {
      hInst = hInstance;
      if (cbHeapSize > 0)
         UnlockData(0);
   }
   return 1;
}
int FAR PASCAL WEP(int nParameter)
{
   return 1;
}
int FAR _export PASCAL RegisterAppl(HANDLE hWnd)
{

 static HANDLE semaphore = 0;
   HANDLE sem = semaphore;
   if (semaphore == 0)
      semaphore = hWnd;
   return sem;
}
}
</PRE>
<P>
<h4><a name="03ce_0015"><a name="03ce_0016"><B>[LISTING SIX]</B><a name="03ce_0016"></h4>
<pre>

Declare Sub OpenDocuments Lib "memoir.dll" (ByVal db As String)
Declare Sub CloseDocuments Lib "memoir.dll" ()
Declare Sub GetFirstDocument Lib "memoir.dll" (ByVal Subj As String,    ByVal Text As String)
Declare Sub GetNextDocument Lib "memoir.dll" (ByVal Subj As String,     ByVal Text As String)
Declare Sub AddDocument Lib "memoir.dll" (ByVal Subj As String, ByVal   Text As String)
Declare Sub DeleteDocument Lib "memoir.dll" ()
Declare Sub ChangeDocument Lib "memoir.dll" (ByVal Subj As String, ByVal    Text As String)
Declare Function FindDocument Lib "memoir.dll" (ByVal Key As String,    ByVal Subj As String, ByVal Text As String) As Integer
</PRE>
<P>
<h4><a name="03ce_0017"><a name="03ce_0018"><B>[LISTING SEVEN]</B><a name="03ce_0018"></h4>
<P>
<pre>

Sub Form_Load ()
    Dim handle As Integer
    handle = RegisterAppl(form1.hWnd)
    If handle <> 0 Then
        n = SetFocusAPI(handle)
        shutdown
    Else
        ' ------ initialization code
        OpenDocuments ("memoir.dat")
        GetFirstDocument SubjBuffer, TextBuffer
        DocumentSubject.Text = SubjBuffer
        DocumentText.Text = TextBuffer
    End If
End Sub
End Listings



Copyright © 1993, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.