The Visual Programmer

Jashua Turpin

Joshua Trupin is a software developer specializing in C/C++ and Visual Basic apps for Windows. He can be reached at 75120.0657@compuserve.com or geeknet@ix.netcom.com.

This month, I'm going to dive into the Visual Programmer mailbag, although it's actually not a bag at all—it's a WinSock-based mail reader—and it seems to contain a few letters I haven't been able to get to yet. If you've sent me a note and haven't received a reply, it's not something you said. I've been inundated by Visual Programmer email lately.

There were a few letters from people indicating that they couldn't load the example code from the February 1996 column about tray icons. As a developer, I usually find that most errors in my code are the user's fault, but I thought I'd look into this one because more than one person hit on the same problem.

The problems seem to revolve around the CBACK.OCX file, and its failure to load along with the project. Thinking the problem was just a matter of an unregistered control, I removed all traces of it from my registry. I loaded the VBTRAY project (my Visual Basic-based app that adds an icon to the taskbar), and it worked fine—Visual Basicâ 4.0 registers a control within a project automatically if the OLE class ID listed within the Visual Basic Project (VBP) file isn't already there. Then I realized something—the Object= line in a Visual Basic makefile contains only the class ID, some version information, and the relative filename of the control. My project was loading because CBACK.OCX was in the same directory. When I moved the control to a different directory, it wouldn't load automatically. Since an OLE control is really just a DLL that went to college, Windows searches for it in the same places it looks for DLLs: the Windows and Windows System directories, the current directory, and the path. If you put CBACK.OCX in any of these places, it should load automatically when you load VBTRAY.VBP.

You can also register it by hand. Just run REGSVR32.EXE or REGOCX32.EXE, both of which ship with Visual Basic 4.0. You pass the full path of the control on the command line and it will be added to the registry. REGSVR32.EXE is better because it tells you whether or not it worked.

If VBTRAY still doesn't work, you might not have all the redistributable DLLs on your system. CBACK.OCX needs MFCANS32.DLL, OC30D.DLL, and MSVCRT20.DLL, which are supplied with Visual C++Ô 4.0 and 2.x. If you don't have the DLLs, check the usual MSJ download sources.

Another issue was brought up by an eagle-eyed reader who gently reminded me that not everyone has purchased the Visual Basic 4.0 Enterprise Edition. VBTRAY.VBP includes a reference to the Remote Data Object DLL (MSRDC32.0CX), which isn't available with the Standard and Professional packages. There are two lines in VBTRAY.VBP that refer to Remote Data. With a text editor, bring up VBTRAY.VBP and remove the lines


 Object={F6125AB1-8AB1-11CE-A77F-08002B2F4E98}#1.0#0; MSRDC32.OCX
Reference= . . . Microsoft Remote Data Object 1.0

MSRDC32.OCX is not in the makefile because it's part of the project—it's just one of the standard objects loaded in a default Visual Basic 4.0 Enterprise Edition project. In future projects I'll make sure to note whether they need a particular version of Visual Basic. Since I've only been at this column business for a couple of months you'll have to excuse the occasional blunder. Please, cut me some slack!

Another question that came up was what to do with old sample code. In case you haven't noticed yet, Visual Basic 4.0 doesn't load Visual Basic 1.0 forms that aren't saved as text. There are still a lot of sample programs from 1992 and 1993 floating around in Visual Basic 1.0 format. Sadly, I haven't seen a converter for these files yet. What I did was load them in Visual Basic 3.0, save them as text, and load them in Visual Basic 4.0. This was a conscious design decision by Microsoft to save program size, but it limits source file compatibility (not code compatibility, though).

A couple of users asked how to create forms on-the-fly within Visual Basic. The simple answer is: you can't. At run time, Visual Basic manages all its own forms, and unlike an SDK program (where you can call CreateDialogIndirect based on data structures in memory), you can't read a form definition file, build a form in memory, and pop up a brand-new form that's hooked into the Visual Basic engine. For one thing, it wouldn't be hooked up to the event loop or code interpreter, so you couldn't write any code behind it. Without code, there's little point in adding a form.

However, if you want to start thinking about the future, I urge you to take a peek at the Microsoft Internet Development Technologies Web page (http://198.105.232.4/INTDEV/TECH.HTM), especially the sections on Visual Basic Script. Visual Basic Script will take the form of an interpreter hooked into a form as an OLE control. Using the proposed INSERT tag, you can put OLE controls on an HTML page, with code behind it and everything. Since the language engine (a subscript of the full Visual Basic language) has been abstracted like this, it works on-the-fly.

If you want to write a program that generates new forms as it goes, this might be one approach to consider. All your program has to do is generate the appropriate HTML representation of the Visual Basic form and you'll be back in business. If you download the Active Internet Platform (formerly known as Sweeper) SDK, you'll find a limited version of this technology in alpha testing. Visual Basic Script is scheduled for widespread release in the first half of 1996.

Here's one more question that addresses a limitation of the Visual Basic Picture control.

QCurrently, I am developing a small Visual Basic app to let people view different kinds of scientific spectra. These originate from UNIX boxes somewhere in our group and are delivered in HPGL (Hewlett Packard Graphics Language) format. When I made my first attempt, I realized that within Microsoft® Excel the problem could be solved easily using Visual Basic for Applications.


 ·
·
·
ActiveSheet.Pictures.Insert("FILENAME.HGL",xlHGL)
·
·
·

Is there a way to use that import filter from within Visual Basic?

AWhen I first started thinking about this problem, a couple of things occurred to me. First, I realized that HPGL format was the only one I had left unchecked as a graphic filter when I installed Office 95. Second, I recalled that HPGL is a vector-based, not raster-based, graphical format—it describes pen paths for plotters. As you may know, a Visual Basic 4.0 Picture control can handle image formats like bitmap (BMP) files, icon (ICO) files, run-length encoded (RLE) files, and metafile (WMF) files.

Microsoft Excel lets you install a whole bunch of graphic filters; in theory, you should be able to import any supported file type, convert it to a bitmap or metafile, and slap it into a Picture control. After a bit of consideration, I realized that it's not very hard to do with a bit of OLE Automation.

Let's say you're trying to load an unsupported graphic format, (for instance, the sporty image I created with CorelDRAW in Figure 1). The first thing you have to do is load Microsoft Excel into memory. The following code creates an instance of a worksheet within Microsoft Excel. (Make sure you select Microsoft Excel 5.0 Object Library in the Tools/References dialog first.)

Figure 1 Sporty image in CorelDRAW


 Dim obj As Object
Set obj = CreateObject("Excel.Sheet")

The variable obj now refers to the Microsoft Excel worksheet. You won't actually see it on the screen because Microsoft Excel, unlike most products, stays hidden when it's created through OLE Automation. This is actually pretty cool, because you can use it without letting users know what you're doing. (A Worksheet object has a Visible property, so if you wanted to see the worksheet, just set obj.Visible = 1.)

The second step is loading the picture into Microsoft Excel. A Worksheet object has a number of collection properties that define various objects it contains. The Pictures property is the set of all graphics on a sheet, as well as all linked or embedded OLE objects. A superset of this collection is the DrawingObjects group, which contains all Pictures, plus all controls and ChartObjects on a sheet. If you want to add a picture of any Microsoft Excel-supported type to a worksheet, you can write:


 Call obj.Pictures.Insert("VISPROG.HGL", xlHGL)

Insert works like LoadPicture in Visual Basic. You pass it a filename and an optional picture type and Insert loads the picture from disk. If the graphic has an appropriate extension, you can forego the second parameter. The following command loads my CorelDRAW file.


 Call obj.Pictures.Insert("VISPROG.CDR")

This graphic file is now visible on the worksheet if Microsoft Excel itself is visible (see Figure 2). Depending on the input type, the image is either a bitmap or metafile. When you insert pictures on a form, they are named for you automatically. The first picture is "Picture 1". Instead of clicking to select it, you can write:


 obj.DrawingObjects("Picture 1").Select

Figure 2 Sporty image in Microsoft Excel.

Only one object can be selected in Microsoft Excel at any time, so the Selection property exists at application level. Microsoft Excel itself is encapsulated in an Application object, much like the Visual Basic App object. Sheets have an Application property that points back to the containing instance of Microsoft Excel, so you need to get that object, grab the Selection, and copy it to the clipboard.


 obj.Application.Selection.Copy

This is the same as single-clicking a graphic in Microsoft Excel and pressing Ctrl-C to copy it.

Now all that remains is to pull the data out of the clipboard and into the Picture control. Visual Basic has a Clipboard object that does the trick.


 picFromXL.Picture = Clipboard.GetData()

The picture should now be visible in your Picture control, as shown in Figure 3.

When you're done with the spreadsheet object, you should


 Set obj = Nothing

Figure 3 Sporty image in my Visual Basic form.

Setting an object to Nothing removes the previous contents from memory, so this kills the copy of Microsoft Excel that you loaded earlier. You can use the code in Figure 4 to load any graphic format Microsoft Excel for Windows 95 supports. Just how many formats is that? They're listed in Figure 5.

Figure 4 Loadpic.bas


 Private Sub btnLoadPic_Click()
Dim obj As Object

' Start a new (hidden) instance of Microsoft Excel
Set obj = CreateObject("Excel.Sheet")

' Insert a picture in a supported format
Call obj.Pictures.Insert("VISPROG.CDR")

' Select the newly inserted object
obj.DrawingObjects("Picture 1").Select

' Copy the selected object
obj.Application.Selection.Copy

' Paste the object's picture to the Picture box
picFromXL.Picture = Clipboard.GetData()

' Destroy the instance of Excel
Set obj = Nothing
End Sub

Figure 5 Microsoft Excel Import Formats

AutoCad Format 2-D (.DXF) file
CompuServe GIF (.GIF) file
Computer Graphics Metafile (.CGM)
CorelDRAW 3.0 (.CDR) file
Encapsulated PostScript (.EPS) file
HP Graphics Language (HPGL) file (.HGL)
JPEG Filter (.JPG)
Kodak Photo CD (.PCD)
Macintosh PICT (.PCT) file
Micrografx Designer/Draw (.DRW) file
PC Paintbrush (.PCX) file
Tagged Image File Format (.TIF) file
Targa (.TGA)
Windows Bitmap (.BMP)
Windows Metafile (.WMF) file
WordPerfect Graphics (.WPG) file

Have a question about programming in Visual Basics, Visual Fox Pro, Access, Office, or stuff like that? Mail it directly to The Visual Programmer, Microsoft Systems Journal, 825 Eighth Avenue, 18th Floor, New York, New York 10019, or send it to MSJ (re: Visual Programmer) via:


Internet:



Internet:

Joshua Trupin
75120.657@compuserve.com
geeknet@ix.netcom.com

Eric Maffei
ericm@microsoft.com


This article is reproduced from Microsoft Systems Journal. Copyright © 1995 by Miller Freeman, Inc. All rights are reserved. No part of this article may be reproduced in any fashion (except in brief quotations used in critical articles and reviews) without the prior consent of Miller Freeman.

To contact Miller Freeman regarding subscription information, call (800) 666-1084 in the U.S., or (303) 447-9330 in all other countries. For other inquiries, call (415) 358-9500.