Creating and Using Anchor Windows with Visio 2000

This content is no longer actively maintained. It is provided as is, for anyone who may still be using these technologies, with no warranties or claims of accuracy with regard to the most recent product version or service release.


David Gates

December 1999

Summary: This article discusses how to create and populate anchored windows using Visio 2000 and Visual Basic for Applications (VBA). (7 printed pages)

What Are These Anchored Windows, Anyway?

So you think the Microsoft® Visio® 2000 anchored windows are cool? I agree—they're pretty slick! Anything that helps recapture screen space in programs that make use of a document view is as good as gold.

In case you didn't know they had a name, anchored windows are the new windows in Microsoft Visio 2000 products that dock around the edges of the drawing area. You can choose to auto hide them, so that they collapse and expand when you move the mouse pointer over them. The technology is similar to the Windows Taskbar Auto Hide setting.

Visio windows, such as the Drawing Explorer, Size & Position, Custom Properties, and Pan & Zoom take advantage of auto-hide technology. You display these windows by choosing View > Windows, and then selecting the window you want.

You can dock anchored windows to an edge of the drawing space, or you can float them, after which you can move them anywhere within the drawing space. In addition, you can click the Pushpin to fix the window in its expanded state, the way you can with property pages.

Creating Your Own Anchored Windows

Creating an anchored window is easy. The method changes a little depending on the programming environment you use—Microsoft® Visual Basic®, Microsoft Visual Basic for Applications (VBA), or Microsoft® Visual C++®. For the example macro we create in this article, we'll use VBA code. It is pretty straightforward and available for all Visio users to try.

Before you start, download AnchoredWindows.exe to your local drive and open the Visio (.VSD) file. The file includes these macros:

  • Stock: The steps described in this article created this macro.
  • Home: Changes browser navigation when a shape is dropped on the page.
  • ShapeLib: Opens another Visio drawing file in the browser, from which you can drag shapes to the current drawing.

The following code makes a new macro named Stock, which creates the window.

Public Sub Stock() 
   Dim wAddon As Visio.Window 
   Set wAddon = ActiveWindow.Windows.Add("Stock", visWSVisible, _
   visAnchorBarAddon, , , 300, 210) 
End Sub 

In VBA, you use the Add method of the Visio Windows collection class to create an anchored window. The first parameter is the name (in this case, I named it Stock). The constant visAnchorBarAddon specifies that you want to create an anchored window, and the ending two numbers indicate the starting width and height of the window.

Populating the Anchored Window

Now we have a window, but there is nothing in it. The beauty here is that you can put almost any dialog box, form, or window that you create inside the new window. You must make sure that the window is modeless. To create modeless dialog boxes, you need Visual Basic for Applications 6.0, which is the version that comes with Visio 2000.

Before we populate the window, we'll create a new form in VBA and drop a WebBrowser control on it.

To create a form with a WebBrowser control

  1. In the Visio program, open the Visual Basic Editor by pressing Alt+F11.
  2. Choose Insert > UserForm.
  3. Right-click in the Controls toolbox and choose Additional Controls.
  4. In the Additional Controls dialog box, check Microsoft Web Browser and click OK. The WebBrowser control appears in the toolbox.
  5. Drag the WebBrowser control from the toolbox to the form.

To place the form inside your new window, set the window as the form's parent. This sounds easy, and it is. However, because VBA doesn't include a built-in function for this, we need to use the Win32 API SetParent function. To use it, add the following code to the Declarations section of the VBA project:

Public Declare Function SetParent Lib "user32" _
   (ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long 

SetParent takes two parameters: the window handle of the child and the window handle of the parent. We have the window handle of the parent (the anchored window) because it is a Visio.Window object, and the Visio program exposes a property called WindowHandle32. Getting the handle for our VBA form is a little trickier. A Visual Basic Form object has an hWnd property we can use, but a VBA UserForm object does not include a property or method for getting at its window handle. So, once again, we need to go back to a Win32 API call. To get the window handle of our form, we will declare the FindWindow function with the following code:

Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long 

To use this function we will have FindWindow search for the title (caption) of the window. This is whatever you named your form (UserForm1 if you just used the default name). In this case, I named the form "Stock" (the same name as my window). To tell FindWindow to base its search on the window title and not the class name, we pass the Visual Basic constant vbNullString as the first parameter.

Dim FormHandle As Long 
FormHandle = FindWindow(vbNullString, "Stock") 

Now that we have handles for both the form and the window, we can use the SetParent API function. Before we do that, however, we need to take care of one more thing. For the parent/child relationship to work correctly, we must make the form's window style a child. Once again, VBA does not have a call for this, so we refer back again to the Win32 API.

To make the form a child, we need to use the SetWindowLong API function. But, of course, to use it, we need to declare it first. While we're at it, we will also declare a few constants.

Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
   (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long 
Public Const GWL_STYLE = (-16) 
Public Const WS_CHILD = &H40000000 
Public Const WS_VISIBLE = &H10000000 

The constant GWL_STYLE is used to tell SetWindowLong that we will be changing the window style. We use the Or operator between the constants WS_CHILD and WS_VISIBLE, so that both these "styles" are set for the form's window:

SetWindowLong FormHandle, GWL_STYLE, WS_CHILD Or WS_VISIBLE 

Now that we have set the form as a child and obtained both window handles, we are ready to make the SetParent API call.

SetParent FormHandle, wAddon.WindowHandle32 

Making Them Work Together

If you run your macro now, you see your form in the anchored window, but it still shows its title bar and borders. An easy way to make the title bar and borders disappear is to change the form's size slightly. This leaves you with just the form embedded in the anchored window.

Dim pnLeft As Long, pnTop As Long, pnWidth As Long, pnHeight As Long 
wAddon.GetWindowRect pnLeft, pnTop, pnWidth, pnHeight 
wAddon.SetWindowRect pnLeft, pnTop, pnWidth + 1, pnHeight 

Now we'll tell our WebBrowser control where to navigate. In this case I'll tell it to browse to and get a current intraday stock quote for Visio, along with the Nasdaq and S&P indexes and a moving average.


Figure 1.

It's starting to look pretty good, and by now you may be inventing numerous uses for something like this. But before you go too far, we need to do one more thing.

When you resize the anchored window, the VBA form that is its child automatically resizes to match. In some cases this may be all that is needed, but in our example it makes sense for the WebBrowser control that is part of the form to also resize to match. If we gave the WebBrowser a home page URL instead of this small stock quote image, resizing would be very nice to have. To do this, we simply add a little code to the Resize event for the form.

Private Sub UserForm_Resize() 

WebBrowser1.Width = Me.Width - 5 
WebBrowser1.Height = Me.Height - 5 

End Sub 

Figure 2.

We have taken a detailed look at creating an anchored window, but we used only about 12 lines of code to accomplish it. This is thanks to the richness of the Visio object model. The potential uses seem almost limitless.

Here is the complete code for the home page example I mentioned above:

Public Sub Home() 

Dim wAnchor As Visio.Window 
Set wAnchor = ActiveWindow.Windows.Add("Home", visWSVisible, visAnchorBarAddon, , , 300, 210) 

Set m_HomeFrm = New Browser 
m_HomeFrm.Caption = "Home" 

Dim FormHandle As Long 
FormHandle = FindWindow(vbNullString, "Home") 

SetWindowLong FormHandle, GWL_STYLE, WS_CHILD Or WS_VISIBLE 

SetParent FormHandle, wAnchor.WindowHandle32 

Dim pnLeft As Long, pnTop As Long, pnWidth As Long, pnHeight As Long 
wAnchor.GetWindowRect pnLeft, pnTop, pnWidth, pnHeight 
wAnchor.SetWindowRect pnLeft, pnTop, pnWidth + 100, pnHeight + 100 

m_HomeFrm.WebBrowser1.Navigate "" 

End Sub 

Other Tips for Using Anchored Windows with the WebBrowser Control

Did you know you can drag images from Web pages to your Visio page? Try it with the stock quote. If you were putting together a business diagram and wanted to spice it up a little, you could browse the Web for an image you liked and then simply drag it into your diagram.

Visio shapes can contain hyperlinks. When you drag a shape from a stencil to the drawing, a macro can retrieve the shape's hyperlink and display the Web page in an anchored window. For example, suppose you are a sales rep designing a network configuration for a client. As you drag components onto the drawing, the anchored window can browse to your company's intranet site and display detailed information about the most recent component you added.

You can also have the browser navigate to a .VSD file, which displays as a Document object in the browser. This enables you to zoom and pan the .VSD inside the browser, select multiple shapes, and even drag shapes from the browser to your current page.

The concepts I've described here use only a WebBrowser control on the form. Remember, almost any window can be attached to anchored windows you create. Just make the VBA form a modeless child window and set the anchored window as its parent.