home *** CD-ROM | disk | FTP | other *** search
-
-
-
- Using Borland C++ IDE with
- the Microsoft Visual BASIC Control Development Kit (CDK)
-
-
-
- I wrote this description to help anyone using Borland's C++
- compiler and Integrated Development Environment (IDE) to create
- custom controls for use with Microsoft's Visual BASIC. The MS
- CDK (Control Development Kit) has a series of example programs
- that were written to work with Microsoft C version 6 or later.
- This document should help you get them to work using Borland's
- development products.
-
- This document assumes that you have purchased the MS CDK product.
- I make reference to specific line numbers within the files that
- were shipped to me with version 1.0 of that product. When
- working with Borland's IDE, you can tell what line that you are
- currently editing by referencing the numbers in the bottom left-
- hand corner of the active edit window. The numbers shown there
- appear in the format:
-
- <line number> : <column position>
-
- for example:
- 25:32
-
- which says that your cursor is on the 32nd character of line 25.
-
- In this document, I also assume that you have installed your
- Borland C++ product in the drive\subdirectory C:\BORLANDC. Also
- that after installing the CDK, you have copied the file VBAPI.LIB
- to C:\BORLANDC\LIB and the file VBAPI.H to C:\BORLANDC\INCLUDE.
-
- While experimenting with this code, I created a subdirectory
- called TEMP under the directory for each control, copied all
- files for that control there, and edited the copies. It is NEVER
- advisable to edit your original copies of anything. Also
- remember that whenever you are coding at a systems-level, you
- should save your code frequently.
-
- If you have any comments, suggestions, or neat VBX files, please
- feel free to drop me a line in my Compuserve mailbox, or at my
- humble homestead at 1188 Morgan Ave, Williamsport, PA 17701.
-
- Throughout this document, I mention products and programs that
- are protected by some sort of legal nonsense or another, and I
- hope I can appease all legal-eagles by saying that any Borland
- product mentioned is trademarked and legally protected by Borland
- International Inc. of Scotts Valley, CA. Any Microsoft product
- is trademarked and legally protected by Microsoft Corporation of
- Redmond, WA. Anything done by you using the descriptions here
- should make neither them (nor me) liable for any silliness that
- might prevail.
-
-
-
-
-
-
-
-
- Brent K. Langley Compuserve Userid 70312,2142 Page 1
-
-
- Using Borland C++ IDE with
- the Microsoft Visual BASIC Control Development Kit (CDK)
-
-
-
- GETTING THE CDK TO WORK:
-
- I have found that in getting the CDK code to work with the IDE
- there are 8 steps that I had to follow:
-
- 1) Change WINDOWS.H
- 2) Copy and Rename LibInit.Obj to C:\BORLANDC\LIB\C0VBINIT.OBJ
- 3) Create a Project file (.PRJ) to create the VBX/DLL file
- 4) Change CCINIT.C to take advantage of changes in WINDOWS.H
- 5) Handle any syntax errors in demo code
- 6) Handle any language incompatibilities in code
- 7) "Make" Project from IDE
- 8) Rename (or Copy) xxxxxxxx.DLL to xxxxxxxx.VBX
-
- Steps 1 and 2 from above only need to be done once. Steps 3 and
- 4 need to be done for every project, but follow the same steps.
- Steps 5 and 6 will be addressed separatly for each of the three
- example programs that need fixing. Steps 7 and 8 let you put all
- of the pieces together.
-
- STEP ONE: CHANGE WINDOWS.H
-
- The normal startup code for a DLL does a little processing and
- then calls your function called LibMain. In a .VBX file, we have
- to replace the normal startup code with a modified routine that
- passes some extra information to our control's LibMain. This
- means that the format for calling a VBX's LibMain is different
- from a normal DLL's LibMain. This causes no real hassle to
- MSC/SDK developers because Microsoft doesn't include a function
- prototype in their version of WINDOWS.H for LibMain, however,
- Borland does. And when Borland's compiler sees the CDK version
- of the LibMain function, it stops compiling with an error.
-
- We could just remove the function prototype for LibMain from
- Borland's WINDOWS.H, but it will help us with our syntax checking
- if we leave it there. My solution is to define a constant called
- _CDK before the #include of WINDOWS.H. Then have WINDOWS.H
- determine the existance of this defined constant to decide
- whether to use the CDK or normal version of LibMain.
-
- To do this, load C:\BORLANDC\INCLUDE\WINDOWS.H and then press
- Ctrl-PgDn to go to the bottom of the file. Move your cursor up
- to about line 3473, and you should see Borland's function
- prototype for LibMain. I changed this part of the code to be:
-
- #ifndef _CDK
- int FAR PASCAL LibMain ( HANDLE, WORD, WORD, LPSTR );
- #else
- BOOL FAR PASCAL LibMain( HANDLE, HANDLE, unsigned short );
- #endif
-
- I used "unsigned short" instead of USHORT for the third parameter
- of the CDK version of LibMain because USHORT isn't seen in a
- typedef statement until the file VBAPI.H is #include'd later.
-
-
- Brent K. Langley Compuserve Userid 70312,2142 Page 2
-
-
- Using Borland C++ IDE with
- the Microsoft Visual BASIC Control Development Kit (CDK)
-
-
-
- STEP TWO: RENAME LIBINIT.OBJ TO C0VBINIT.OBJ
-
- Page 20 of the CDK Guide explains that LIBINIT.OBJ contains
- initialization code to replace the code from the file
- LIBENTRY.OBJ that is normally linked into DLL projects first. So
- we must ensure that the code from LIBINIT.OBJ is linked before
- any other code in our projects.
-
- On page 141 of Borland's C++ User Guide, we find the section of
- the project manager chapter titled "Overriding Libraries" states
- that we can have our own startup file linked first, if:
-
- 1) its name starts with C0 (the letter C followed by zero)
- 2) it is placed as the first file in the project.
-
- We'll worry about making a project file in a minute, but for now,
- lets give LibInit.OBJ a new name to conform with step one from
- above. While we're at it, lets also move it to a standard
- location (since the CDK manual says that this code would seldom
- need to change.) If LibInit.OBJ is in your current directory,
- type:
-
- COPY LIBINIT.OBJ C:\BORLANDC\LIB\C0VBINIT.OBJ
-
- You could call it anything you want (so long as it starts with
- "C0") but since it contains the Visual Basic INITialization code,
- I thought that this name was appropriate.
-
- STEP THREE: CREATE A PROJECT FILE
-
- For each control, you will make a project file that looks similar
- to the following:
-
- C:\BORLANDC\LIB\C0VBINIT.OBJ
- C:\BORLANDC\LIB\C0DC.OBJ
- C:\BORLANDC\LIB\VBAPI.LIB
- CCINIT.C
- program.DEF
- program.RC
- program.C
- .
- . (any other program files or libraries)
- .
-
- For example, the project for the CNTR control would look like:
-
- C:\BORLANDC\LIB\C0VBINIT.OBJ
- C:\BORLANDC\LIB\C0DC.OBJ
- C:\BORLANDC\LIB\VBAPI.LIB
- CCINIT.C
- CNTR.DEF
- CNTR.RC
- CNTR.C
-
-
-
- Brent K. Langley Compuserve Userid 70312,2142 Page 3
-
-
- Using Borland C++ IDE with
- the Microsoft Visual BASIC Control Development Kit (CDK)
-
-
-
- STEP THREE: CREATE A PROJECT FILE (continued)
-
- The file C:\BORLANDC\LIB\C0DC.OBJ listed in the above projects is
- the normal startup code file for Borland C (that has been
- superseded by C0VBINIT.OBJ) and should appear immediately after
- C0VBINIT.OBJ in your project file. This file should actually be
- C0Dx.OBJ where "x" indicates your memory model that you are
- compiling with. Since I used the "Compact" memory model for
- compiling my projects, this is C0Dc.OBJ in my code examples.
-
- Since a VBX file is a type of DLL, you should let the project
- manager know that you will be creating a DLL. You can do this by
- typing Alt-O to activate the Options menu. Type A to select your
- Application type, and then type D to select DLL. Now when you
- save your project, this information will be stored with it.
-
- Besides the interactive way of building a project, you could make
- a batch file to create your project files, or you could copy this
- text to a .PRJ file, but then remember to run PRJCNVT to change
- the old-style text project file to Borland's new project file
- format.
-
- An example .BAT file called MAKEPRJ.BAT might contain:
-
- @ECHO OFF
- IF "%1"=="" GOTO ERROR
- ECHO C:\BORLANDC\LIB\C0VBINIT.OBJ > %1.PRJ
- ECHO C:\BORLANDC\LIB\C0DC.OBJ >> %1.PRJ
- ECHO C:\BORLANDC\LIB\VBAPI.LIB >> %1.PRJ
- ECHO CCINIT.C >> %1.PRJ
- ECHO %1.DEF >> %1.PRJ
- ECHO %1.RC >> %1.PRJ
- ECHO %1.C >> %1.PRJ
- PRJCNVT %1.PRJ
- GOTO END
- :ERROR
- ECHO You must specify a project name
- :END
-
- This uses the program PRJCNVT.EXE in your C:\BORLANDC\BIN
- subdirectory (probably in you PATH) to convert from a text .PRJ
- file to Borland's new project file format. The first ECHO
- statement creates a new .PRJ file, and the rest of the ECHO
- statements append their line of text to this file. The file is
- named using whatever you specify on the command line after the
- word MAKEPRJ. For Example:
-
- MAKEPRJ CNTR
-
- Would make the project example shown on the previous page and
- name it CNTR.PRJ. Remember then to set the Alt-O-A-D options
- when you load this into the IDE.
-
-
-
-
- Brent K. Langley Compuserve Userid 70312,2142 Page 4
-
-
- Using Borland C++ IDE with
- the Microsoft Visual BASIC Control Development Kit (CDK)
-
-
-
- STEP FOUR: CHANGE CCINIT.C
-
- In step one, we modified WINDOWS.H to allow correct function
- prototyping of the LibMain function. In the file CCINIT.C we
- will take advantage of this change. This is the file where our
- version of LibMain is declared, so we want WINDOWS.H to use the
- CDK version of the prototype.
-
- This is pretty simple, all you need to do is to include the line:
-
- #define _CDK
-
- before the #include <windows.h> statement in the file CCINIT.C.
-
- I suggest that you type over line 6 in this file which is
- currently blank. This will preserve the line numbers for the
- rest of the code. CCINIT.C is very similar for each of the
- example programs in the CDK, but each does vary slightly. Please
- make this change for every sample control project in the CDK.
-
- STEP FIVE: HANDLE SYNTAX ERRORS
- STEP SIX: HANDLE ANY LANGUAGE INCOMPATIBILITIES
-
- CIRCLE1, CIRCLE2, and PUSH have no further problems so you can
- continue with steps seven and eight for them.
-
- However, there is still some work that needs to be done with the
- files for CIRCLE3, CNTR, and PIX. I prefer to address the
- problems for each of these programs separately, so please see
- their individual descriptions on the following pages.
-
-
- STEP SEVEN: MAKE PROJECT
-
- You're just about done! Press F9 and the IDE will create your
- DLL file. If you prefer to use Borland's MAKE utility, you can
- convert your .PRJ file from step three (above) to a .MAK file
- with the Borland utility PRJ2MAK and then edit this make file to
- tailor it to your own specifications.
-
- STEP EIGHT: RENAME .DLL FILE TO .VBX
-
- The IDE's project manager will create a file with the same
- filename as that of your .PRJ file. The resulting file's
- extension will be .DLL but the Visual BASIC system will be
- expecting a Visual Basic eXtension file. To accomodate Visual
- BASIC, just RENAME (I prefer to COPY) name.DLL to name.VBX
-
- That's all there is (as if it isn't enough!) Now you can load
- Visual BASIC and select Alt F D for File Add-file and specify
- your .VBX file.
-
-
-
-
-
- Brent K. Langley Compuserve Userid 70312,2142 Page 5
-
-
- Using Borland C++ IDE with
- the Microsoft Visual BASIC Control Development Kit (CDK)
-
-
-
- CIRCLE3
-
- In addition to following the steps described above (such as
- putting the #define _CDK in CCINIT.C) CIRCLE3 has some
- compatibility problems:
-
- CIRCLE3 PROBLEM 1:
-
- On line 114 of CIRCLE.C there is a call to VBCreateHsz that uses
- the new MS C v6 type keyword "_segment". My info on this keyword
- comes from an article in the March 1990 issue of Microsoft
- Systems Journal by Noel J. Bergman. While describing the new (at
- that time) version 6 of MS C, he describes briefly, on page 58,
- the concept of "based pointers" and the function of _segement.
-
- He says: "When _segment is used to cast a near address, the
- result is the current value in DS" which can be obtained in BC++
- by specifying _DS or FP_SEG( (void far *) addr ). He continues:
- "If the address is a far address, the result is the segment for
- that far address." You can use the FP_SEG( addr ) macro in dos.h
- to get this value.
-
- A consistent way to handle both cases would be to use the FP_SEG
- macro and cast (void far *) on the pointer. For example:
-
- FP_SEG( (void far *) addr )
-
- Or, since the macro does this casting for you internally, you can
- abbreviate this as just:
- FP_SEG( addr )
-
- A side note: when looking in the include file dos.h I found that
- FP_SEG is using a cast operation with the word _seg !?! What is
- that?? Is it the same as _segment ?? It doesn't seem so. Since
- I couldn't find it in the documentation, lets play it safe and
- stick with FP_SEG. Although, if you are converting a MAJOR
- project, you could speed up the conversion by doing a global
- search and replace: changing all
-
- (_segment)
- to
- (void _seg *)(void far *)
-
-
- Using FP_SEG is easier to read (I think), and a little more
- portable. The choice is up to you, but for this example, lets
- change line 114 of CIRCLE.C to read:
-
- hsz = VBCreateHsz( FP_SEG(hctl), (LPSTR)lp);
-
- and then put the #include <dos.h> on the blank line between the
- includes for <windows.h> and <vbapi.h> (this will preserve line
- numbers for the further editing that we have to do...)
-
-
-
- Brent K. Langley Compuserve Userid 70312,2142 Page 6
-
-
- Using Borland C++ IDE with
- the Microsoft Visual BASIC Control Development Kit (CDK)
-
-
-
- CIRCLE3 PROBLEM 2:
-
- In line 406 of CIRCLE.C, the reference to FlashDlgProc is meant
- to pass the address of a certain type of function to the function
- VBDialogBoxParam. It's function prototype on line 423 is:
-
- BOOL FAR PASCAL _export FlashDlgProc(HWND, USHORT, USHORT, LONG)
-
- but what is required for VBDialogBoxParam (on line 309 of
- VBAPI.H) is the type FARPROC that is defined on line 151 of
- WINDOWS.H as:
-
- typedef int (FAR PASCAL * FARPROC)();
-
- OK, so all we need to do is cast this FARPROC type on the
- function FlashDlgProc. Change line 406 of CIRCLE.C to read:
-
- VBDialogBoxParam(hmodDLL, "FlashDlg", (FARPROC)FlashDlgProc, 0L);
-
- Now your CIRCLE3.PRJ should compile cleanly. Remember to rename
- (or copy) CIRCLE3.DLL to CIRCLE3.VBX then fire up Visual BASIC
- and try it out!
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Brent K. Langley Compuserve Userid 70312,2142 Page 7
-
-
- Using Borland C++ IDE with
- the Microsoft Visual BASIC Control Development Kit (CDK)
-
-
-
- CNTR
-
- CNTR, the counter control uses "based pointers" in a couple of
- its modules so there is some conversion that needs to be done,
- but there is an error (BUG??) in CCINIT.C that we must fix first.
-
- In CCINIT.C on line 45, the function modifier "PASCAL" is
- missing from the definition of the function LibMain, so change
- this line from:
- BOOL FAR LibMain
- To:
- BOOL FAR PASCAL LibMain
-
- Also, at the top of CCINIT.C (line 6, for example) remember to
- place the statement:
- #define _CDK
-
-
- In CNTR.H and CNTR.C we need to remove the based pointer
- references and replace them with their equivalents in terms of
- far pointers. I'm not sure why Microsoft added this based
- pointer complexity to this program, unless its that they felt
- that it would make the code run faster (using 16 bit pointers
- rather than 32 bit.) But I don't think that this is the type of
- application that would benefit from the added complication.
-
- In CNTR.H we have some stuff to clean up. Lines 26 through 34
- and also line 54 should be commented out as shown below:
-
- // _segment segCntr;
- // #define BP _based(segCntr) * // based pointer
- // #define BH BP BP // based handle
- // typedef VOID BH BHVOID; // void handle
- // typedef CHAR BH BHSTR; // handle to a string
-
- // #define CNTRDEREF(hctl) ((PCNTR)(VOID *) ...
-
- and then change line 52 from:
- typedef CNTR BP PCNTR;
- to:
- typedef CNTR far * PCNTR;
-
-
- In CNTR.C comment-out line 53 as shown below:
-
- // segCntr = (_segment) hctl;
-
- and change line 54 from:
- pcntr = CNTRDEREF(hctl);
- to:
- pcntr = VBDerefControl(hctl);
-
- Now CNTR should compile ok. Rename CNTR.DLL to CNTR.VBX an go!
-
-
-
- Brent K. Langley Compuserve Userid 70312,2142 Page 8
-
-
- Using Borland C++ IDE with
- the Microsoft Visual BASIC Control Development Kit (CDK)
-
-
-
- PIX
-
- Remember to put the line:
-
- #define _CDK
-
- on line 6 (the blank line above #include <windows.h>) in the file
- CCINIT.C as described in step 4 (above).
-
- Lines 81, 85, and 109 of PIX.C use the non-Borland _segment type
- for casting as described for CIRCLE3 (above). On each of these
- lines modify reference in the code for
-
- (_segment) hctl
-
- to appear like:
-
- FP_SEG( hctl )
-
- and place the line
-
- #include <dos.h>
-
- at the top of the file PIX.C.
-
- Now this control should compile and link cleanly. Remember to
- rename the resultant .DLL file to a .VBX file before you load
- Visual BASIC and try it out.
-
- --------------------------------------------------------------
-
- Well, I hope this made enough sense to get you going. I tried to
- not only tell you what to do, but to also tell you where in the
- various references that I found my information. I hope it helps.
-
- Also, I can't emphasize enough, for you to save your programs
- often. A small mistake in your code can cause a Windows
- Unexpected Application Error (UAE) and either kick you completely
- out of Visual BASIC, kick you out of Windows, reboot your
- machine, or freeze your machine. I have encountered all of these
- battle scars, but I survived and you will too! Have fun....Brent
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Brent K. Langley Compuserve Userid 70312,2142 Page 9
-