User's Guide For
Multimedia Controls
Software Development Kit

1. About The MM Controls Project
2. Using The MM Controls SDK
3. SDK Part A: The Theatre Control Ensemble
4. SDK Part B: Writing Lightweight Controls & Containers
5. The ActiveX Control Architecture And MM Controls Extensions

To report bugs, mailto:MMCtl.
For more information, see http://consweb/tech/mmctl/.

Help file built: 10/22/96
About Autodoc
1. About The MM Controls Project

1.1. MM Controls: Introduction And Goals
1.2. MM Controls Requirements Beyond ActiveX
1.3. Lessons Learned (So Far)
1.4. Related Efforts
1.1. MM Controls: Introduction And Goals

The Multimedia Controls project is an effort within the Interactive Media Technologies group in the Interactive Media (formerly Consumer) Division. MM Controls begun in late 1995 with the following goals:
—	1. Represent IMD-specific requirements for the ActiveX control architecture to Sweeper and Forms3.  IMD products tend to be more media-rich and require more customized user interfaces than other ActiveX clients.  Also, since animation plays a large role in many IMD products, it's important to ensure that, in the long term, animation capabilities are integrated fully into MS ActiveX containers; black-box monolithic Shockwave-style animation isn't flexible enough.)
—	2. Promote the ActiveX control architecture throughout IMD. Initially, many IMD product groups viewed the OLE Controls architecture as too heavyweight to use as a way of dividing large conventional CD-ROM applications into smaller components.  But with OC96/ActiveX (with a push in the right direction) this is no longer necessarily the case.
—	3. As needed, provide the tools for building lightweight "multimeda-enabled" ActiveX controls.  MFC is insufficient for building lightweight controls, and other toolkits (MarcWan, ATL) aren't yet focussed on (a) helper DLLs to reduce average control size, and (b) palette negotiation and other MM-specific issues.  Until they are (and to help demonstrate requirements), the MM Controls project provides an SDK to meet these needs.
—	4. Become obsolete!  Once the above goals have been met by platform-provided tools and technologies, we can focus purely on building above the platform.  (Of course, we'll ensure that any clients of MM Controls have a smooth transition path toward future Sweeper/Forms3 solutions.)
It is important to emphasize that MM Controls does not attempt to create any new standards -- we simply want to make ActiveX work for IMD.
The MM Controls Stage and Sprite controls help drive goal #1 (see 1.2. MM Controls Requirements Beyond ActiveX and 3. SDK Part A: The Theatre Control Ensemble), and (by example) goal #2.  The MM Controls SDK (see 4. SDK Part B: Writing Lightweight Controls & Containers addresses goal #3.  To work toward goal #4, the MM Controls team is working with Sweeper and Forms3 to ensure that the standard system components and tools will obviate the need for the MM Controls SDK.
Current MM Controls clients include Sundance '97 (a multimedia electronic greeting cards authoring tool) and the Blue Ribbon ActiveMusic control (which generates interactive music).
For more information, see: http://consweb/tech/mmctl/
IMPORTANT:  If you want to use MM Controls, please mailto:EricLe first so we can make sure we can support your project.
1.2. MM Controls Requirements Beyond ActiveX

The ActiveX Controls architecture defines how a visible (windowed or windowless) or invisible control can be embedded in a container. In addition to the requirements of ActiveX, MM Controls has the following needs:
—	Palette negotiation and optimization:  A container needs to query each control for its ideal palette of colors, and then efficiently merge the colors into a single palette.  Various proposed methods are either too simplistic (e.g. single container-defined palette) or too slow (e.g. octree or median-cut based methods using color histograms).  Our proposed solution is O(n) (for n total colors) and is prototyped in Stage using OCImg.
—	Compositing via DIBSection/DirectDraw:  OC96 allows for off-screen composition, but having controls draw into an HDC is insufficient (e.g. too slow) for some applications (e.g. when the control is an animated sprite).  Our proposed solution is to adopt conventions for drawing into off-screen DIBSection or DirectDraw buffers.  We have partially prototyped this proposal in Sprite and HostLW, also using OCImg.
—	Audio transfer to container:  Various controls may produce audio (either MIDI-style music or waveform data), which the container needs to have control over (e.g. to choose which audio sources to mute, which to mix, which to apply effects to, etc.).  Our experience with the sibling AudioMan project helps us understand how to solve this problem, though no prototyping in this area has been done as of 5/96.
—	Animation event negotiation:  When multiple overlapping controls are animating, it's important to coalesce the redraw requests in order to achieve best performance.  HostLW, Stage, and Sprite prototype a simple IAnimate interface, but a more sophisticated "animation event negotion" mechanism is needed (and a first draft has been proposed).  We hope the SPAM animation team can help us here.
—	Nested windowless conainers:  Certain multimedia applications require that a container of windowless controls itself be windowless (and enabled for DIBSection/DirectDraw compositing) since an HWND gets in the way of compositing.  OC96 leaves some issues (e.g. activation sequence, grab handle drawing) ambiguous in this case; Stage prototypes this concept.
—	Design-time/run-time segmentation:  The design-time (authoring) features of a control are not needed during run-time, and we don't want Internet end users to have to download any unnecessary code (or enable features they didn't pay for), so it's important to allow for separate design-time and run-time versions of control DLLs.  Forms3 has recently proposed a solution; we will likely be the first to try it out.
—	Design-time UI:  Our controls need to be able to provide a rich design-time (authoring) user interface.  For example, the Line sample allows the author to drag and resize the line or its endpoints, as well as displaying context menu items and a property page.  Some of these features are not yet fully enabled in the OC96 spec.
For more information about how we've addressed these issues, see 5. The ActiveX Control Architecture And MM Controls Extensions.
1.3. Lessons Learned (So Far)

MM Controls has been very much a hands-on, "try by doing" project. We started with the idea of seeing how far we could stretch OC96, understanding that we may have to "stretch" the rules to meet our goals.
So far, this is what we learned:
—	OC96 (mostly) works!  It's true we had to extend the OC96/ActiveX rules a bit see 1.2. MM Controls Requirements Beyond ActiveX and 5. The ActiveX Control Architecture And MM Controls Extensions, but for the most part OC96 appears to be a well-designed architecture that allows for the kind of subsetting and supersetting we need. As a result, our controls are valid ActiveX controls, though to get some features you need to use them in an enhanced container (such as HostLW or OCTest).
—	Very small ActiveX controls are possible.  By paying careful attention to what functionality is required and what can be left out, we've written some very small controls.  Our smallest is TinyAuto, which is under 10KB without using any helper DLLs (including the C runtime).  Our other controls use a 30KB helper DLL (OCHelp) to achieve small size with much richer functionality than TinyAuto; these controls can be as small as 10K.  The memory footprint of these controls tends to be small as well -- most of them are windowless.
—	High performance compositing is possible with windowless controls. For example, Sprite directly manipulates the container's frame buffer (when asked to draw) without knowing any specific details about the container, and by this method it appears that Sprite can be made as fast as any component with hard-codeded intimate knowledge of its container.  In other words, packaging a component as an ActiveX controls doesn't introduce any significant performance penalties.
—	more to come...
1.4. Related Efforts

The following projects at Microsoft are similar or related to MM Controls:
ActiveX Controls And Containers:
—	Sweeper:  Owns the Internet Explorer browser, and the Internet Control Pack, as well as all Internet-related underlying system technologies.
For more information, see http://ohserv/
—	Forms3 ("forms cubed"):  Owns the future (IE5?) HTML browser & editor technology, as well as 2D layout container(s).  Hopefully, Stage will be replaced entirely by a future version of the Forms3 form container.
For more information, see http://forms3/
Writing ActiveX Controls:
—	MFC (Microsoft Foundation Classes):  Like the MM Controls SDK, MFC provides a way to write ActiveX controls.  Currently MFC supports only windowed (not windowless) controls.  MFC controls can be relatively small (though not as small as a control developed using the MM Controls SDK), though the MFC support DLL and memory footprint are signficantly larger.
For more information, see Visual C++.
—	MarcWan/Sweeper Base Control:  Provides C++ base classes for developing ActiveX controls.  Controls are relatively small, though the "housekeeping" functionality is not currently pulled out into a separate DLL, so a set of controls using this base control may be larger than a set created using the MM Controls SDK.  On the other hand, the Sweeper Base Control pretty much defines correct control behavior.
For more information, see http://ohserv/
—	ATL (ActiveX Template Library):  Provides C++ class templates for developing controls.  Control size and cababilities are similar to the Sweeper Base Control.
For more information, see http://ohserv/
2. Using The MM Controls SDK

2.1. Setting Up The SDK
2.2. Building Samples
2.3. Building The SDK
2.4. Using OCTest (ActiveX Control Test Container)
2.5. Using OCAuthor (VB-Based ActiveX Control Test Container)
2.6. Support, Feedback, More Information
2.1. Setting Up The SDK

To set up the MM Controls SDK, run file://imt/drop/mmctl/current/setup.exe.
If you just want to set up the controls, helper DLLs, and test application, and you don't need the entire SDK, run file://imt/drop/mmctl/current/setup.exe.  (This will install enough components to run MM Controls demos.)
2.2. Building Samples
Currently, the sample ActiveX controls and containers assume you are using VC4 (Microsoft Visual C++ 4.0).
There are no special environment variables etc. you need to set up to use the MM Controls SDK, since each dependent header file, .lib file, etc. is referred to by a releative pathname instead of assuming a particular INCLUDE path.  However, it's a good idea to do an Update All Dependencies in VC4 on any project before building that project for the first time.
2.3. Building The SDK

The MM Controls SDK components are pre-built, and the .pdb files are provided for debugging, so normally the information in this section is not necessary.  The source code of the MM Controls SDK is provided primarily as a debugging aid.  However, should you need to (e.g. to test a new compiler -- forking the code is not a good reason!) it's possible to build the SDK from the provided source code:
—	As with the samples, the SDK assumes VC4.
—	The makefile in the root of the MM Controls SDK builds all components; see the comments in the makefile for more information.
—	Note that in order to build OCImg, you need to have the MKImg20 project enlisted in a peer directory of the MMCtl directory (so both directories have the same parent), since OCImg makes use of the MKImg20*.lib static link libraries.
2.4. Using OCTest (ActiveX Control Test Container)
OCTest is a simple Windows application that internally uses the SiteLW object provided in the OCMisc helper library (part of the MM Controls SDK) to contain a single OLE/ActiveX control.
For more information, see OCTest.
2.5. Using OCAuthor (VB-Based ActiveX Control Test Container)
OCAuthor is a simple Visual Basic application provided to demonstrate the usage of the OCEdit control.  OCAuthor operates in much the same way as OCTest.
For more information, see OCAuthor.
2.6. Support, Feedback, More Information

For more information: http://consweb/tech/mmctl/.
Your feedback is important to us!  We can't achieve our goals unless we know how well our technology and prototypes apply to a variety of application types, so we're particularly interested in knowing how MM Controls works (or doesn't work) for you.  To provide feedback, mailto:MMCtl or mailto:Ericle.
To report bugs, mailto:MMCtl.
To receive status reports about MM Controls, you can join the MMCtl alias. To do so, mailto:EricLe and ask to be added to the MMCtl alias.
You can also access our RAID bug database: file://imt/drop/mmctl/mmctlro.rdq.
3. SDK Part A: The Theatre Control Ensemble

3.1. Introduction
3.2. Stage Control
3.3. Sprite Control
3.4. HostLW Control
3.5. ABAuto (Audio Mixer) Control
3.6. Animate Control (Coming Soon)
3.7. Theatre Control (Coming Soon)
3.8. OCEdit Control

See Also:
2.4. Using OCTest (ActiveX Control Test Container)
2.5. Using OCAuthor (VB-Based ActiveX Control Test Container)
3.1. Introduction

In order to achieve our goal of representing the needs of media-rich applications to Sweeper and Forms3, we started working on a prototype control, Stage, which is a windowless control that can contain (and position in 2D space with z-ordering) other windowless controls.  (The demo version of Stage also supports animation, though eventually all animation support will move to a separate Animate control.)  We also created Sprite to test bitmap and palette embedding and transparent/translucent blitting and HostLW to allow Stage to be embedded in IE3 (which doesn't yet support windowless controls).
The name "Theatre Control Ensemble" defines the collection of controls which comprise our animation-related ActiveX control-based prototyping work.
Before too long it became clear that a subset of the Theatre ensemble can meet the needs of a specific application: Sundance '97 (a multimedia electronic greeting card application).  In fact, the ideal container for Sundance would be the Forms3 control container, but it won't be ready for use by Sundance in the time frame needed.  So Stage will be used initially, and then Stage will be replaced by the Forms3 form object when it's ready.
This helps underscore a goal for our controls and containers: they are specifically designed to be "pin-compatible" with MS ActiveX standards. (We do extend the standards in a few areas where they're lacking; see 5. The ActiveX Control Architecture And MM Controls Extensions for more information.)
Although Sundance is the driving client for the Theatre ensemble, we are willing to allow the control to be used in other applications provided such an application can get by being a non-driving client (i.e. having limited control over the feature set).  If you're interested in becoming a client of MM Controls, please mailto:EricLe.
The following sections describe the functionality of each control in detail.
Note that one control, OCEdit, is a bit of an oddball because it's not intended for use in IE3 at all -- rather it's designed to be used in Visual Basic, to implement a simple ActiveX control editor much like OCTest.
3.2. Stage Control

Stage is a lightweight windowless ActiveX control which is itself a container for lightweight windowless controls.  Stage is analogous to a Visual Basic or Forms3 form, in the sense that Stage contains controls.  However, Stage is a small (under 50KB for non-demo runtime version) container, and it supports palette negotiation (via OCImg), animation event negotiation (see 5. The ActiveX Control Architecture And MM Controls Extensions), and other animation-related features, and Stage controls can be nested arbitrarily.
For more information, see: Stage.
3.3. Sprite Control

Sprite is a lightweight windowless ActiveX control which displays a multi-frame bitmap and provides a mechanism for cycling through the frames to simulate animation.  Parts of the bitmap can be transparent, and the bitmap can be displayed at a given opacity/translucency level (simulated by drawing an irregular pattern of a given percentage of pixels).
For more information, see: Sprite.
3.4. HostLW Control

HostLW is a lightweight windowed ActiveX control which can embed a lightweight windowless ActiveX control.  Can be used to allow IE3 to host windowless controls.
For more information, see: HostLW.
3.5. ABAuto (Audio Mixer) Control

ABAuto is a lightweight invisible ActiveX control which accesses the AudioBoy mixer to allow playing multiple waveform audio files at once.
For more information, see: ABAuto.
3.6. Animate Control (Coming Soon)

The Animate control has not yet been implemented.  It is planned to be the core animation "engine" which drives animation in Stage. (In the current demo version of Stage, simple animation features are temporarily hard-coded into Stage.)  When used in conjunction with the Stage and Theatre controls, Animate will allow a web page author to create simple animations using any HTML editor.
If you're interested in Animate, please mailto:EricLe.
3.7. Theatre Control (Coming Soon)

The Theatre control has not yet been implemented.  It is planned to be a high-level easy-to-use animation control.  When used in conjunction with the Stage and Animate controls, Theatre will allow a web page author to create simple animations using any HTML editor.
Theatre is currently planned as a demonstration/prototype control, not as a pacakaged product.
If you're interested in Theatre, please mailto:EricLe.
3.8. OCEdit Control

Among controls in the Theatre Control Ensemble, OCEdit is a bit of an oddball because it's not intended for use in IE3 at all.  Instead, OCEdit is designed to be used in Visual Basic, to implement a simple ActiveX control editor much like OCTest.
For more information, see OCEdit.
A sample Visual Basic application, OCAuthor, is provided to demonstrate the usage of OCEdit.  For more information, see OCAuthor.
4. SDK Part B: Writing Lightweight Controls & Containers

4.1. Introduction
4.2. Writing Controls -- Step By Step
4.3. Sample Controls
4.4. Writing Control Containers
4.5. OCHelp Reference
4.6. OCImg Reference
4.7. OCMisc Reference
4.1. Introduction

As described in 1.1. MM Controls: Introduction And Goals, one of the goals of the MM Controls is to make it easy to develop very lightweight "multimedia-enabled" ActiveX controls.  This section describes the following components of the MM Controls SDK designed to satisfy these goals:
—	OCHelp is a small helper DLL (also available in static-link form) that provides the common functionality which many/most controls must implement.  By centralizing this functionality in a single small DLL, individual controls can be much smaller.
—	OCImg is a small DLL that implements certain kinds of graphics-intensive operations needed by many "multimedia-enabled" controls.  OCImg is actually a subset of the MKImage library, packaged as a DLL (instead of as a static-link library) to help minimize the amount of code that would need to be downloaded for Internet controls.
—	OCMisc is a static-link library of helper functions that provide ActiveX control-related functionality that may be useful to some containers and/or controls, but isn't likely to be useful to most or all controls.  For example, OCMisc provides the SiteLW object, which helps an application or control be an ActiveX control container.
The following sections contain both tutorial-style and reference-style information that should help you implement ActiveX controls and containers.
Important: The emphasis of the MM Controls SDK is on windowless controls and containers, although basic support for windowed controls and containers is also provided.  If you find the windowed control/container support lacking, please mailto:EricLe -- no promises, but we'd like to see if we can help.
4.2. Writing Controls -- Step By Step

This section (and the subsections listed below) describe how you can implement an ActiveX windowed or windowless control optionally based on the OCHelp helper library and one of the minimal sample controls provided in this SDK.  The resulting control should be small enough to be downloaded for use on HTML web pages.
4.2.1. Getting Started: Creating A Minimal Control
4.2.2. Adding Support For Persistence And Simple IDispatch
4.2.3. Adding Support For Properties And Methods
4.2.4. Adding Support For Events
4.2.5. Adding Support For Accessing Container's Ambient Properties
4.2.6. Adding Support For Property Pages
4.2.7. Adding Support For Context Menu Items
4.2.8. Adding A Control To An Existing DLL
4.2.9. Other Useful OCHelp Helper Functions
4.2.A. OCImg -- Helpers For Palette & Bitmap Manipulation
4.2.B. OCMisc -- Helpers For Implementing ActiveX Containers

Any control built by the procedures described in this section is implemented in a COM (component object model) self-registering in-process server DLL.  The control is (by default) "lightweight" in the sense that a subset of ActiveX interfaces may be implemented (and for those interfaces that are implemented, a subset of methods may be implemented and others will do nothing or return E_NOTIMPL).
A control based on OCHelp should (hopefully) function identically to one produced using MFC, ATL, or the Sweeper base control.  The advantage of using OCHelp is that it collects common helper functionality into a single small DLL (much smaller than MFC) that need be downloaded only once and can then be shared among multiple controls.  The emphasis here is primarily on making controls very small, and to enable very lightweight windowless controls. Another goal is to make controls relatively easy to implement.
Three kinds of controls, described below, can be built following the procedures in this section.  For each type of control, one or two "skeleton" controls (see the next section) is provided in this SDK -- you can use a skeleton control as the basis for a new ActiveX control you implement.
—	A lightweight invisible control (also known as an "OLE automation server"), like the TinyAuto or MiniAuto skeleton controls.  Such a control has no visible appearance, and is typically used to provide some kind of service to e.g. VBS code.  This control may be embedded in VB4, in HTML (in IE3 and above), in HostLW, and in Stage.
—	A lightweight windowless control, like the TinyOC skeleton control: This control follows the OC96 specifications for windowless controls. The control is visible but does not create an HWND to display itself. (This allows the control to have transparent or translucent parts, and efficiently animate inside an appropriate container such as HostLW or future versons of IE.)  This control may be embedded in HostLW and in Stage, and in HTML (in IE3 and above) and VB4 via HostLW, but such a control cannot be directly embedded in VB4 and IE3.  Future versions of IE (IE5?) will allow direct embedding of windowless controls.
—	A lightweight windowed control, like the CircOC skeleton control: This is the same type of control produced by the Sweeper ActiveX control framework.  The control is visible and uses an HWND to display itself.  Such controls may be embedded in HTML (in IE3 and above), and in HostLW, but currently cannot be directly embedded in Stage.  In theory, CircOC can be embedded in VB4, but currently that doesn't work because of the excessive demands VB4 places on a control (e.g. full type library support), but if VB4 compatibility is important to you it's probably possible to add the necessary features.
All the skeleton controls (and, by default, any control you build based on a skeleton control) have the following in common:
—	The controls have been built using VC 4.0 and tested using Win95. They should work on NT as well, but haven't been extensively tested on that platform.
—	None of the controls requires the C/C++ runtime (either in static-link or dynamic-link form) or the MFC runtime.  This is done to keep the controls as small as possible.
—	All the controls (except those based TinyAuto, described in the next section) rely on the OCHelp helper DLL provided in this SDK.  If you choose, you can use the static-link version of OCHelp instead, so you don't need to rely on the OCHelp DLL.  This will make your control larger, but the combined size of your control and the OCHelp DLL may be smaller.  (Also, in doing so you lose the advantage of having OCHelp downloaded only once and shared among multiple controls.)
(You might ask: why isn't a base class provided instead of a DLL full of helper functions?  The reason is that base classes tend to assume you want a given fixed set of functionality; OCHelp's approach is more "a la carte" -- your control's size is only affected by functionality you use.  Also, base classes tend to break the controls that use them more often than is the case with helper functions, because of the complex interdependencies introduced by shared data members.)
—	Currently, none of the controls requires the Internet (Sweeper) SDK or any of its runtime DLLs (though you can choose to use these features if you wish).
—	A control may optionally have properties and methods, accessible to C++, VBS, VB, and (presumably) Javascript programs.  (Most testing to date has been done using VBS.  Some testing has been done using VB4.  No testing has been done using Javascript.  This information may be out of date -- check with EricLe if this is important to you.)
—	A control may optionally implement persistence (loading and saving of its state) via IPersistPropertyBag (for text-based persistence, to enable properties stored in e.g. HTML <PARAM>) and/or IPersistStream (for binary stream persistence).  If AllocPropertyHelper is used to implement text-based persistence, then an IDispatch implementation is automatically provided that allows the same properties initialized via <PARAM> tags to be accessed via VBS code.
—	A control may optionally fire events to the container, which typically causes script code (e.g. a VBS subroutine) in the container to be executed.  Note that although lightweight invisible controls may fire events which can be used in VBS in IE3 and above, VB4 will ignore these events. events.
—	For testing purposes, the OCTest application can embed all three kinds of controls (though currently support for windowed controls is limited, and there's not a lot of value in embedding an invisible control unless the control supports a property page that you want to test).
 ***********************************************************************
4.2.1. Getting Started: Creating A Minimal Control

This section describes how to create a minimal ActiveX control that's a valid working self-registering in-process server but which doesn't do very much (yet).  If you already have a control, you can skip this section and jump ahead to later sections which describe how to add specific features to your control.
First, choose a "skeleton" control on which your control will be based. (See the previous section for definitions of, and capabilities of, lightweight invisible, windowless, and windowed controls.)  The MM Controls SDK contains these skeleton controls you can use (each located in a directory with the same name):
—	TinyAuto: A lightweight invisible control that doesn't require use of the OCHelp DLL.  This control implements a single test property ("Foo", which has constant value 42) using IDispatch. This is pretty much the smallest ActiveX control you can build.  Note that if you want to add any feature provided by OCHelp these instructions assume you will start with MiniAuto instead of TinyAuto.
—	MiniAuto: A lightweight invisible control similar to TinyAuto, but MiniAuto uses OCHelp to help implement events (which can be fired to the container).
—	TinyOC: A lightweight windowless control that displays a single small ellipse which can be animated using the experimental IAnimate interface.  (Animation only works when TinyOC is embedded in the OCTest application or the HostLW control -- IE3 currently doesn't directly support animation.)  Uses OCHelp.  TinyOC is set up to build separate design-time and run-time versions of its DLL.
—	CircOC: A lightweight windowed control similar to the "Circle" control provided in the Internet (Sweeper) SDK, except that CircOC uses OCHelp instead of the Sweeper base control.  CircOC is set up to build separate design-time and run-time versions of its DLL.
Note that if you're looking for an IE3-compatible full-featured windowed control to start from, see the comments about the "FubarOC" sample control below.
(A different approach would be to start with a more full-featured control like Line, rename it and change its GUIDs, and add and remove features as needed -- feel free to do this if you think your control will need all the features of a control like Line anyway.  In fact, the "FubarOC" sample control is essentially the CircOC skeleton control that has had steps 4.2.2. Adding Support For Persistence And Simple IDispatch, 4.2.3. Adding Support For Properties And Methods, and 4.2.4. Adding Support For Events already applied to it -- if you're looking for an IE3-compatible windowed control to start with, FubarOC might be the control for you.  However, the instructions below help you understand all the parts of a control, including which are optional and can be left out if you need the control to be as small as possible.)
Once you've chosen a skeleton control, do the following steps:
—	Choose a control name.  These instructions assume that your control name is 8 characters or less for a control based on TinyAuto or MiniAuto, or 5 characters or less (replacing the word "Tiny" or "Circ") for a control based on TinyOC or CircOC.  You can probably use longer names provided you don't use SLM, but this hasn't been tested.
—	Copy all the skeleton control's files to a new directory (named with the name of your control).  These instructions assume that the directory is a subdirectory of your "MMCtl" directory (i.e. your control's directory is a sibling of the directory containing the skeleton control you used).  You can delete tinyaut4.mak, miniaut4.mak, and slm.ini from your directory, if present.
—	Rename each file whose name starts with "TinyAuto" (if based on TinyAuto), "MiniAuto" (if based on MiniAuto), "Tiny" (if based on TinyOC), or "Circ" (if based on CircOC) so that it starts with the name of your control.  For example, if your control is based on TinyOC, and your new control's name is "Fubar", rename "TinyOC.def" to "Fubar.def" and rename "TinyOC.mak" to "Fubar.mak".
—	Using your favorite tool, make the following substitutions in all text files in your control's directory (assuming the name of your control is "Fubar"):
If based on TinyAuto: change all "TinyAuto" to "Fubar"
If based on MiniAuto: change all "MiniAuto" to "Fubar"
If based on TinyOC: change all "Tiny" to "Fubar"
If based on CircOC: change all "Circ" to "Fubar"
—	Run guidgen.exe (provided with VC4) and generate a new class ID for your control.  The class ID is stored (in two forms) in "control.h" in your control's directory.  If there are any .htm files in the directory, change the GUID in the <OBJECT> tag to the same GUID; in the case of controls based on TinyOC the GUID you need to change in test.htm is the "value" attribute of the "_embed" <PARAM> tag (because TinyOC is embedded in HostLW in order to allow it to work in IE3).
If there is a .odl file in the directory (currently only for controls based on MiniAuto), the same GUID needs to be used in the "coclass" construct.  Also, a new GUID needs to be generated for the top-level "library" construct in the .odl file, and a new GUID needs to be generated for the dispinterface in MiniAuto.h.
—	In VC4 (MSDev), use Open Workspace to open the .mak file.  (If you have more than one .mak file, you didn't read the directions above :-)  Select Build: Update All Dependencies (check all checkboxes) and make sure you don't get any errors.  Then, build the control using Build: Rebuild All, and make sure the control builds and registers correctly.
You now have a working (but minimal) ActiveX control.  You can test the control in OCTest or (using the provided test.htm) in IE3.  (If your control is invisible, OCTest works but is relatively pointless because there's nothing to see.)  If your control is based on TinyOC, it must be "wrapped" in HostLW (as shown in TinyOC\test.htm) before being embedded in IE3 since IE3 does not support windowless controls.
All the skeleton controls have at least some amount of default functionality that you can delete and replace with your own functionality.  Search for the string "TODO" to find these places in the code.
TinyOC and CircOC can build separate design-time and run-time versions, depending on the project configuration: configurations with "DT" are "design-time" (and may include authoring UI etc.); configurations with "RT" are "run-time" (and do not include authoring UI).  You'll usually want to develop using the DTDebug configuration, since it has debugging information and includes all author-time functionality.
If you care, here's a quick look inside your control (so far):
—	dll.cpp: Contains the functions that implement a COM in-process self-registering server DLL (with some help from OCHelp, or autohelp.cpp in the case of controls based on TinyOC). _DllMainCRTStartup is called when the DLL loads, unloads, and at various other times.  DllRegisterServer and DllUnregisterServer are called when an application (such as a setup program or regsvr32.exe) are used to register or unregister your control with the OS (so that your control can be located by COM when CoCreateInstance is called by a user of your control). DllGetClassObject returns S_FALSE if there are any objects implemented by your DLL that are currently alive. DllGetClassObject creates an instance of the class factory object for your control, which in turn is used to create an instance of your control.  Finally, global new and delete operators are provided so that you don't need the C runtime; note that these operators zero-initialize the memory they allocate (to reduce the need for unnecessary initialization).
—	If based on TinyAuto: autohelp.cpp: This is essentially a very stripped-down version of OCHelp that contains only the most essential functions needed for implementing a class factory, control self-registration, etc.
—	control.h: Declares the C++ object that implements your control. This object is based on each interface that the control supports (via multiple inheritence).  Controls based on TinyOC or CircOC support COM-style aggregation by implementing both a delegating unknown (named IUnknown) and a non-delegating unknown (named INonDelegatingUnknown -- but this is just IUnknown renamed because C++ won't allow a class to inherit the same interface twice).
—	control.cpp: Defines the C++ object that implements your control. Also defines a function named InitAutoObjectInfo or InitControlInfo, which is called once when your control's DLL loads to initialize information about your control.  If you want to change information about your control (such as its "friendly name" or its ProgID) here's where you do it.
—	control.odl: (If present -- curently only in MiniAuto.) Used to generate a type library, which is stored as a resource in the control's DLL.  This is for event support (firing events to the control's container).  Note that a .odl file is not required for supporting properties and methods (if you use OCHelp helper functions DispatchHelpGetIDsOfNames and DispatchGetArgs).
—	purevirt.c: Avoids pulling in the C/C++ runtime.
—	debug.h and debug.cpp: Defines TRACE, ASSERT, and VERIFY macros, the same way they're defined in MFC (but without calling MFC).  Also defines DebugIIDName and DebugCLSIDName (see QueryInterface in control.cpp for an example) which can be used to convert a GUID to an interface ID or class ID string. These functions are disabled and compile to zero code in a release build.
—	*.def, *.rc: The usual.  Note that the .rc file should contain a version resource, especially if you want to be able to use the IE3 downloadable code feature.
For more information:
4.2. Writing Controls -- Step By Step
 ***********************************************************************
4.2.2. Adding Support For Persistence And Simple IDispatch

This section describes how your control can use AllocPropertyhelper load property values from an HTML page or a binary stream.  Saving is also supported (if the container supports it -- note that IE3 doesn't allow saving, but OCTest does).  Also, AllocPropertyHelper provides a "free" (simple) implementation of IDispatch that allows e.g. VBS scripts to access each of the properties exposed by your object. (See 4.2.3. Adding Support For Properties And Methods for information about how to implement methods as well as properties on your control.)
AllocPropertyHelper works like this: when your control is created, you call AllocPropertyHelper to create a PropertyHelper object (which is aggregated with your control).  In your control's QueryInterface function, you pass requests for IPersistStream, IPersistStreamInit, IPropertyBag, and IDispatch onto AllocPropertyHelper.  You also need to make your control support the helper interface IPersistVariantIO; inside the IPersistVariantIO::DoPersist function you provide the names of, and pointers to, all your control's properties, like this:
STDMETHODIMP CFubarOC::DoPersist(IVariantIO* pvio, DWORD dwFlags)
        {
            HRESULT         hr;

            // load or save control properties
            if (FAILED(hr = pvio->Persist(0,
                    "Name", VT_LPSTR, &m_achName,
                    "Height", VT_INT, &m_iHeight,
                    "Married", VT_BOOL, &m_fMarried,
                    NULL)))
                return hr;

            // if any properties changed, redraw the control
            if ((hr == S_OK) && (m_poipsw != NULL))
                m_poipsw->InvalidateRect(NULL, TRUE);

            // clear the dirty bit if requested
            if (dwFlags & PVIO_CLEARDIRTY)
                m_fDirty = FALSE;

            return S_OK;
        }

This example assumes that the control's C++ class contains member variables named "m_achName" (a character array used as a string), "m_iHeight" (an int), and "m_fMarried" (a BOOL).  DoPersist is called by PropertyHelper in the following circumstances:
—	When your control is first loaded.  The value of each property will be stored in the associated member variable by the call to IVariantIO::Persist.
—	When your control is saved.  The value of each property will be copied from each member variable and saved (to a binary stream or a text-based "property bag") using the associated property name.
—	When a property of your control is accessed via IDispatch (e.g. VBS script like "fubar.Height = 5" or "x = fubar.Height"). In this case only the member variable associated with the specified property is read or written; the others are ignored.
PropertyHelper provides file format "version safety": if you use a newer control with older property data, or vice versa, your control shouldn't crash.  The reason is that, assuming you initialize all your member variables to reasonable default values, then during loading:
—	if the data file contains properties that your control doesn't list in the IVariantIO::Persist call, the properties are simply ignored, and
—	if the control lists a property that isn't in the data file, the property is skipped (so it contains its default value).
This is safer (and easier) than loading or saving a structure containing control data.
To add PropertyHelper support to your control, do the following.  These steps are illustrated by the example in AllocPropertyHelper.
—	In e.g. control.h, add member variables named m_fDirty (a BOOL) and m_punkPropHelp (an LPUNKNOWN) to your control's C++ class.
—	In e.g. control.h, make your control's C++ class be based on IPersistVariantIO, and declare the methods of IPersistVariantIO within the body of the class (you can copy them from the example in AllocPropertyHelper).  In e.g. control.cpp, you also need to return IPersistVariantIO from your QueryInterface (or NonDelegatingQueryInterface) function.  Also, you need to write the methods of IPersistVariantIO: you can implement IPersistVariantIO::DoPersist as shown above; you can return E_NOTIMPL for IPersistVariantIO::InitNew; you can return (m_fDirty ? S_OK : S_FALSE) for IPersistVariantIO::IsDirty.
—	In e.g. control.cpp, call AllocPropertyHelper in your constructor and save the returned pointer in m_punkPropHelp.  In your destructor, call m_punkPropHelp->m_punkPropHelp (if non-NULL).
—	In e.g. control.cpp, in your QueryInterface (or NonDelegatingQueryInterface) function, call m_punkPropHelp->QueryInterface in response to queries for IPersistStream, IPersistStreamInit, IPropertyBag, and IDispatch (or in response to any unknown interface, as shown in the example in AllocPropertyHelper).
To test persistence, run OCTest and create an instance of your control, then do File: Save As to save the control's data in CSV or HTML format.  Alternatively, run OCTest and open the supplied "test.htm" file; then do File: Save, which should rewrite test.htm with the new properties added as <PARAM> tags.
***********************************************************************
4.2.3. Adding Support For Properties And Methods

Section 4.2.2. Adding Support For Persistence And Simple IDispatch, describes how you can get "free" properties using AllocPropertyHelper; this section explains how you can add arbitrary properties and methods to your control.
OCHelp supports late-bound properties and methods by helping you implement IDispatch::GetIDsOfNames and IDispatch::Invoke in your control; this method does not provide type information via IDispatch::GetTypeInfoCount and IDispatch::GetTypeInfo.  This means that OCHelp does not directly provide support for implementing "dual interfaces" (which allow for both early-bound and late-bound access).  It's important to understand that OCHelp does not preclude you from implementing dual interfaces -- you simply need to create a .odl file and call CreateStdDispatch when any of your IDispatch functions is first called, and then forward that and future IDispatch calls to the StdDispatch object.
(If you're wondering why OCHelp took the late-bound approach: the reason is that this approach reduces the size, complexity, and memory footprint of a simple control, since no .odl file need be created and the standard type library-based IDispatch object doesn't need to be loaded in memory. Also, we think OCHelp's approach implements a faster IDispatch, though we haven't tested this extensively.  The major drawback is that OCHelp's approach doesn't allow for early-bound function calls, which would be even faster than OCHelp's IDispatch support, but we felt that the speed of script code was less importnat for controls intended for the HTML web pages, which is OCHelp's primary target.  Also, VBS currently doesn't even support early-bound function calls, so the advantage of a dual interface is lost in this case anyway.  Finally, controls like Line provide an interface like ILineOC, which are even more efficient for C++ programs to access than the most efficient dual interfaces, because ILineOC transfers data in structure form rather than as individual properties.)
Also, if you already (or plan to) implement property bag persistence using the method described section 4.2.2. Adding Support For Persistence And Simple IDispatch, see that section for more information about the "free" IDispatch property support you get.  (If you want to use both the IDispatch provided by AllocPropertyHelper and custom extra properties and methods, just call the IDispatch returned by AllocPropertyHelper in your IDispatch::GetIDsOfNames and IDispatch::Invoke functions instead of returning DISP_E_UNKNOWNNAME or DISP_E_MEMBERNOTFOUND.)
To add IDispatch support to your control, do the following.  These steps are illustrated by IDispatch methods in MiniAuto\control.cpp.
—	In e.g. control.h, make your control's C++ class be based on IDispatch, and declare the methods of IDispatch within the body of the class (you can copy them from MiniAuto\control.h).  In e.g. control.cpp, you also need to return IDispatch from your QueryInterface (or NonDelegatingQueryInterface) function.  Also, you need to write the methods of IDispatch -- for now, copy the methods from MiniAuto\control.cpp -- the instructions below expain how to modify IDispatch::Invoke.  (For more information about how IDispatch::GetIDsOfNames works, see the OCHelp function DispatchHelpGetIDsOfNames, though you shouldn't need to modify the default implementation copied from MiniAuto.)
—	In e.g. control.h, define DISPID_ constants corresponding to each of the methods and properties you want to define.  You also need to define METH_PROP_NAMES to contain a list of property & method names, corresponding to the DISPID_ values, with each name terminated by '\n'.  For an example, see the definition of DISPID_* and METH_PROP_NAMES in MiniAuto\MiniAuto.h.  (Note that this example leaves DISPID zero unused, since it has special meaning.)
—	In e.g. control.cpp, in your defininition of IDispatch::Invoke, follow the example shown in the Invoke function copied from MiniAuto, and define one case in the switch statement for each property or method you want to implement.  A given case will be executed whenever e.g. VBS script code accesses (reads, writes, or calls) that property or method.
OCHelp helps you with one aspect of the implementation of Invoke: "parsing" the arguments and coercing them to the desired parameter types.  To do this, call DispatchGetArgs.  For example "DispatchGetArgs(pdispparams, 0, VT_INT, &m_iFoo, 0)" will assume that pdispparams (passed to Invoke) contains a single argument, which is coerced to type "int" and stored in variable m_iFoo.  Note that VT_INT in this example refers to the type of m_iFoo -- the actual passed argument can be of any type that can be coerced to VT_INT.  See DispatchGetArgs for more information.
—	If you need to return a string from a property or method call, the OCHelp function VariantFromString may help.
To test IDispatch support, you can write VBS code as shown in MiniAuto\test.htm.  In the case of controls based on TinyAuto or MiniAuto, you can also test the control in VB4, by loading the control using VB's "CreateObject" function and accessing properties and methods through a VB variable of type Object.
***********************************************************************
4.2.4. Adding Support For Events

A control can notify its container (e.g. an HTML page) that an event has occurred.  This is done by having the control "fire" an event, which just means that the control calls a function provided by the container (typically in the container's code, e.g. VBS script).  OCHelp helps a control implement support for firing events, including implementation of IProvideClassInfo, IConnectionPointContainer, IConnectionPoint, and (via OLE automation helper functions) ITypeLib and ITypeInfo.
Note: As of 5/96, event support does not work for windowless controls embedded in IE3 via HostLW and/or Stage, because HostLW and Stage do not yet implement event transfer.  This information may be out of date -- if you need event support in a windowless control, contact EricLe to get current information.
To add event support to your control, do the following.  These steps are illustrated by MiniAuto\control.odl, MiniAuto\MiniAuto.h, MiniAuto\control.h, and MiniAuto\control.cpp.
—	In e.g. control.h, make your control's C++ class be based on IConnectionPointContainer, and declare the methods of IConnectionPointContainer within the body of the class (you can copy them from MiniAuto\control.h).  In e.g. control.cpp, you also need to return IConnectionPointContainer from your QueryInterface (or NonDelegatingQueryInterface) function. Also, you need to implement the methods of IConnectionPointContainer -- but you can just copy the default implementation from MiniAuto\control.cpp.
In e.g. control.h, declare a member variable m_pconpt of type "IConnectionPointHelper *" in your control's C++ class.  In e.g. control.cpp, call AllocConnectionPointHelper (as shown in MiniAuto\control.cpp) in your C++ class's constructor to initialize m_pconpt, replacing "MiniAuto" with the name of your control (e.g. "FubarOC").  Also, call FreeConnectionPointHelper in your destructor to free m_pconpt.
—	In e.g. control.h, make your control's C++ class be based on IProvideClassInfo, and declare the method of IProvideClassInfo within the body of the class (you can copy them from MiniAuto\control.h).  In e.g. control.cpp, you also need to return IProvideClassInfo from your QueryInterface (or NonDelegatingQueryInterface) function.  Also, you need to implement IProvideClassInfo::GetClassInfo -- but you can just copy the default implementation from MiniAuto\control.cpp (and simply change CLSID_CMiniAuto to the class ID of your control). (For more information about how IProvideClassInfo::GetClassInfo works, see the OCHelp function HelpGetClassInfoFromTypeLib, though you shouldn't need to modify the default implementation copied from MiniAuto.)
—	In e.g. control.h, define DISPID_EVENT_ constants corresponding to each of the events want to define.  For an example, see the definition of DISPID_EVENT_* in MiniAuto\MiniAuto.h.  (Note that this example leaves DISPID zero unused, since it has special meaning.)
—	In e.g. control.h, create a new GUID (using guidgen.exe) corresponding to DIID_DFubarOCEvents, replacing "FubarOC" with the name of your control.  This should look like the definition of _DIID_DMiniAutoEvents and DIID_DMiniAutoEvents in MiniAuto\MiniAuto.h.
—	Create a "control.odl" file that's initially a copy of MiniAuto\control.odl.  Change #include "MiniAuto.h" to #include "control.h".  Replace all other occurrences of "MiniAuto" with the name of your control (e.g. "FubarOC").  Use guidgen.exe to generate a new GUID that replaces the GUID above the "library" line. Replace the list of "methods:" with your control's actual events; the "id()" values must be DISPID_EVENT_ constants as described above. Add the control.odl file to your VC4 project (via Insert Files Into Project).
—	Since you're #include-ing "control.h" into your .odl file, you need to ensure that anything in your "control.h" other than #define statements is surrounded by "#ifndef __MKTYPLIB__ ... #endif". This includes statements like DEFINE_GUID(...), but not #define _CLSID_... .
—	If your control doesn't yet have any resources, create an empty resource script as follows in VC4: click File, New, Resource Script, OK.  Save the resource script (e.g. to "resource.rc").  Click Window, Close All.  Use Insert Files Into Project to add your resource script to your project.
—	In VC4, select View Resource Includes, and in the "Compile-time directives" box type the following:
1 TYPELIB "control.tlb"

This makes the type library file generated from control.odl be linked into your control's DLL as a resource.
—	In the .cpp file (e.g. dll.cpp) that contains "#include <initguid.h>", add "#include <olectlid.h>" after <initguid.h>.
—	Anywhere in your code where you want to fire an event, simply call m_pconpt->FireEvent, which calls IConnectionPointHelper::FireEvent.  For example:
m_pconpt->FireEvent(DISPID_EVENT_BAR, VT_INT, i,
            VT_LPSTR, ach, VT_BOOL, f, 0);

This will invoke the event identified by DISPID_EVENT_BAR, passing parameters i, ach, and f.
To test event support, you can write VBS event processing subroutines (like the "Bar(i, sz, f)" example above) as shown in MiniAuto\test.htm. As of this writing, event support has not been tested in VB4; if it works, it will only likely work for controls based on CircOC (and, eventually, maybe, windowless controls embedded in HostLWOC).
 ***********************************************************************
4.2.5. Adding Support For Accessing Container's Ambient Properties

An "ambient property" is a property (accessible via IDispatch::Invoke typically using special predefined DISPID_ constants with negative value) that is defined on the site object that contains a given control.  Examples of ambient properties are DISPID_AMBIENT_PALETTE (which is the color table used by the container) and DISPID_AMBIENT_USERMODE (which indicates whether the container is in "design" mode or "run" mode).
To access a container ambient property, a control must call QueryInterface on the IOleClientSite pointer (passed to IOleObject::SetClientSite) to acquire a pointer to the IDispatch interface on the site object.
The container notifies the control of changes in the value of an ambient property by calling IOleControl::OnAmbientPropertyChange, passing either the DISPID of the ambient property whose value has changed, or DISPID_UNKNOWN which means that any or all ambient properties may have changed.
To add ambient property access to your control, do the following:
—	If your control does not yet support IOleObject, do the following:
In e.g. control.h, make your control's C++ class be based on IOleObject, and declare the methods of IOleObject within the body of the class (you can copy them from LineOC\control.h). In e.g. control.cpp, you also need to return IOleObject from your QueryInterface (or NonDelegatingQueryInterface) function. Also, you need to implement the desired methods of IOleObject; you can copy a sample implementation from LineOC\control.cpp.
You can return E_NOTIMPL from most IOleObject methods.  The methods you may want to implement are:
—	SetClientSite: Called by the container to pass you a pointer to the container's client site.  See LineOC\control.cpp for an example.  You need to declare as member variables any pointers you want to maintain on the client site.
—	DoVerb: For visible controls, DoVerb is called by the container to request that your control switch states.  For example, iVerb==OLEIVERB_UIACTIVATE indicates that the container wants your control to "UI-activate" (which means e.g. acquiring keyboard focus, perhaps because the user tabbed to your control).  DoVerb is also called in response to selection of right-mouse context menu items, as described in section 4.2.7. Adding Support For Context Menu Items.
—	EnumVerbs, GetUserType: Also required for supporting right-mouse context menu items.  Both can be implemented using helper functions, as demonstrated by LineOC\control.cpp.
—	GetMiscStatus: Tells the container things like whether or not your control wants to be activated whenever it is visible. See the example in LineOC\control.cpp.
For the purposes of adding support for accessing container ambient properties, you only need to implement IOleObject::SetClientSite.
—	If your control does not yet support IOleControl and you want to be notified of ambient property changes, do the following:
In e.g. control.h, make your control's C++ class be based on IOleControl, and declare the methods of IOleControl within the body of the class (you can copy them from LineOC\control.h). In e.g. control.cpp, you also need to return IOleControl from your QueryInterface (or NonDelegatingQueryInterface) function. Also, you need to implement the desired methods of IOleControl; you can copy a sample implementation from LineOC\control.cpp.
You can return E_NOTIMPL from all methods of IOleControl but in order to receive notification of ambient property changes you should implement IOleControl::OnAmbientPropertyChange.  See LineOC\control.cpp for an example; this function uses the OCHelp function DispatchPropertyGet to retrieve the actual ambient property value.
To test ambient property access, load your control into OCTest. When you switch from design mode to run (or "preview") mode, your control's IOleControl::OnAmbientPropertyChange should be called, and you can check the value of ambient property DISPID_AMBIENT_USERMODE to see if OCTest is in design mode (zero) or run mode (nonzero).
Similarly, OCTest changes the value of DISPID_AMBIENT_PALETTE whenever the ambient palette changes; see IOleControl::OnAmbientPropertyChange in PalOC\control.cpp for an example.
 ***********************************************************************
4.2.6. Adding Support For Property Pages

In containers (like OCTest) that allow authoring (i.e. that enable "design mode"), a control's properties may be edited by a user using one or more "property pages" provided by the control.  For example, run OCTest and create a new Line control, then right-click on the line and select "Properties...".
A property page (like the one labelled "Line" in the above example) is really a simple invisible ActiveX control.  "Invisible," you ask?  Yes -- although the property page itself is visible, the ActiveX control that implements the property does not implement IViewObject or any HWND.  Instead, it only implements IPropertyPage, which contains an Activate method which is used to ask the property page to create a child window containing a dialog box.  It's this dialog box that you actually see in the "Line" property page in the example above.  (The window that contains one or more pages, as well as OK, Cancel, and Apply buttons, is called a "property frame".)
OCHelp simplifies the task of implementing a property page for your control: much of the "housekeeping" work of maintaining the property page is done by OCHelp's PropPageHelper object, allocated using AllocPropPageHelper.  Since property pages are normally available only in the design-time version of a control, you may choose to enclose all property-page related code in "#ifdef _DESIGN ... #endif", as shown in LineOC.
To add a property page to your control, do the following:
—	If your control does not yet support ISpecifyPropertyPages, do the following:
In e.g. control.h, make your control's C++ class be based on ISpecifyPropertyPages, and declare the methods of ISpecifyPropertyPages within the body of the class (you can copy them from LineOC\control.h).  In e.g. control.cpp, you also need to return ISpecifyPropertyPages from your QueryInterface (or NonDelegatingQueryInterface) function.  Also, you need to implement ISpecifyPropertyPages::GetPages, but you can simply copy the sample implementation from LineOC\control.cpp (changing "CLSID_CLinePP" to a new class ID for your property page, e.g. "CLSID_CFubarPP" if your control is named "Fubar").
—	Copy LineOC\proppage.cpp and LineOC\proppage.h to your control's directory.  Change all occurrences of "Line" to the name of your control (e.g. "Fubar") -- the class ID name of the property page in proppage.h should match that specified in ISpecifyPropertyPages::GetPages (above).  Use guidgen.exe to change the value of the class ID in proppage.h.
—	When the property page is displayed, the property page object (e.g. FubarPP, defined in proppage.cpp) needs to have a way to communicate with the objects it is operating upon (e.g. FubarOC, defined in control.cpp).  "Objects" is plural because in theory a single property page may operate on a multiple selection, though many containers don't support this.  To accomplish this communication, you need to define a private interface (e.g. IFubarOC) on your control (e.g. FubarOC) that FubarPP can talk to.  (Careful: don't assume you can cast an interface pointer back to a pointer to CFubarOC -- it won't work.)
LineOC's private interface is called ILineOC, and is declared in LineOC\LineOC.h.  The interface is very simple: ILineOC::GetInfo retrieves a structure containing data (attributes) from the control, and ILineOC::SetInfo gives the control new data (attributes). In addition to supporting property pages, this interface serves a second purpose: it's an efficient way for C++ programs to access the functionality of the object.
You need to define an interface like IFubarOC, and if you haven't already you should probably define a .h file (like FubarOC.h) to contain "public" definitions.  (On the other hand, control.h contains definitions private to your control's DLL.  FubarOC.h would need to be #included by any C++ program that wants to access ILineOC.)
—	In VC4, create a dialog box resource that contains the property page (see LineOC for an example).  Make the ID of the property page be IDD_PROPPAGE.  Also, define a string resource that contains the name of the control to be used on the property page's tab (e.g. "Fubar"), and make the ID of that string resource be IDS_PROPPAGE.
—	In proppage.cpp, take a look at FubarPPDialogProc.  This is the dialog box procedure that implements your property page.  This is pretty much an ordinary dialog box procedure, except that:
—	you get extra PropPageHelperInfo * and HRESULT * parameters, and
—	you never call EndDialog, and
—	you receive a WM_PPH_APPLY message when the user hits the "Apply" button.
In WM_INITDIALOG, you get information from the PropPageHelperInfo, including a list of pointers to IFubarOC interfaces, one pointer for each object that the property sheet is operating on, and you copy data from these control(s) into your property sheet dialog.
Similarly, when WM_PPH_APPLY is received, data is copied from the property sheet dialog into IFubarOC.
—	Finally, in order to add the property page object to the list of ActiveX objects implemented by your control's DLL, edit e.g. dll.cpp or control.cpp (wherever the ControlInfo structure or array is initialized).  If you curently have a single ControlInfo structure (e.g. g_ctlinfo), change it to an array of two elements (e.g. ControlInfo g_actlinfo[2]).  If it's already an array, make it one element larger.  Add the property page object to the end of the array as shown in LineOC\dll.cpp; make sure to "link" the previous item of the array to the new last item in the array, as shown (by filling in the pNext field of the previous item to point to the new last item which contains information about CFubarPP).
To test your property sheet, load your control into OCTest and select File: Properties.
***********************************************************************
4.2.7. Adding Support For Context Menu Items

Some containers (like OCTest) implement context menus on controls For example, run OCTest and create a new Line control, then right-click on the line.  The "Close", "Save", and "Properties..." menu items are implemented by OCTest; the "Straighten" menu item is a custom command or "verb" implemented by the Line control.  A control can have any number of context menu items (though it should probably only have a few, else the context menu will become too long).
Coontext menu items probably don't make sense for invisible controls.
Since context menu items are often available only in the design-time version of a control, you may choose to enclose all property-page related code in "#ifdef _DESIGN ... #endif", as shown in LineOC.
To add context menu support to your control, do the following:
—	If your control does not yet support IOleObject, implement IOleObject as described in section 4.2.5. Adding Support For Accessing Container's Ambient Properties
For the purposes of adding context menu support, you need to implement IOleObject::EnumVerbs and IOleObject::GetUserType. Both can be implemented using helper functions, as demonstrated by LineOC\control.cpp.
You also need to implement IOleObject::DoVerb, as demonstrated by LineOC\control.cpp.  When the user selects the first verb from the right-click context menu, DoVerb is called with iVerb==0; the second verb has iVerb==1, and so on.
—	For each verb you want to add, create a string resource formatted like the IDS_VERB_STRAIGHTEN string in LineOC.  Verbs should have consecutive string ID numbers (e.g. 100, 101, 102, ...) and the number to the left of the "=" in the string itself should be consecutively numbered starting from 0 (e.g. "0=Straighten,0,2", then "1=Set Color...,0,2", etc.)
—	In dll.cpp or control.cpp (wherever you initialize the control's ControlInfo structure), set the uiVerbStrID to the ID of the first string resource created above.
To test your context menu items, load your control into OCTest and right-click on it.
 ***********************************************************************
4.2.8. Adding A Control To An Existing DLL

All the skeleton controls except TinyAuto allow for multiple controls to be implemented in the same DLL.  This section explains how to add a control to an existing DLL, assuming the DLL uses OCHelp's RegisterControls and HelpGetClassObject (see in dll.cpp in the skeletons).
To add a control to your DLL, do the following:
—	Edit e.g. dll.cpp or control.cpp (wherever the ControlInfo structure or array is initialized).  If you curently have a single ControlInfo structure (e.g. g_ctlinfo), change it to an array of two elements (e.g. ControlInfo g_actlinfo[2]).  If it's already an array, make it one element larger.  Add the new control's ControlInfo structure to the end of the array; make sure to "link" the previous item of the array to the new last item in the array (by filling in the pNext field of the previous item to point to the new last item which contains information about the new control).
For an example of how to do this, see the _DllMainCRTStartup function in dll.cpp in LineOC.  (The second "control" in this case is actually a property page, which is really a special kind of control, but the registration procedure would be the same for any ordinary ActiveX control.)
—	Create new files similar to e.g. control.cpp and control.h to define the C++ class that implements the new control.  Don't forget to create a GUIDs for the control's class ID.  Add the new .cpp file to your VC4 project.
Once the control DLL is registered again (which usually happens automatically when the DLL is built), you should be able to access the new control from OCTest or any compatible container.
 ***********************************************************************
4.2.9. Other Useful OCHelp Helper Functions

In addition to the OCHelp helper functions described in the previous section, OCHelp contains the following useful helper functions:
For sending messages between threads:
MsgWndPostToCallback
Posts a message to a hidden message-passing window.  When the window receives the message, it calls a given callback function. This can be used to safely pass information between threads.
MsgWndSendToCallback
Sends a message to a hidden message-passing window.  When the window receives the message, it calls a given callback function. This can be used to safely pass information between threads.
For advising the container of changes in the control's display, including changes in the control's palette (IE3 currently doesn't support arbitrary palettes but OCTest does):
InitHelpAdvise
Initializes a HelpAdviseInfo structure, used to help implement IViewObject::SetAdvise and IViewObject::GetAdvise.
HelpSetAdvise
Helps implement IViewObject::SetAdvise.
HelpGetAdvise
Helps implement IViewObject::GetAdvise.
UninitHelpAdvise
Peforms final cleanup of a HelpAdviseInfo structure, including releasing the IAdviseSink pointer if necessary.
For helping implement hit-testing of windowless objects, required in order to fully implement IViewObjectEx:
HelpQueryHitPoint
Helps implement IViewObjectEx::QueryHitPoint on a control by drawing the control into a small bitmap (centered on the point being hit-tested) and checking if any pixels were drawn.
For drawing custom control borders, and/or drawing a rectangular border with 4 or 8 grab handles:
CreateBorderBrush
Creates and returns a hatch pattern brush used to draw control resize borders and grab handles.
DrawControlBorder
Draws a border used to drag and resize controls.
Finally, see section 2.A. Utility Functions for a list of general-purpose handy utility functions, including memory management, UNICODE conversions, HIMETRIC conversions, etc.
 ***********************************************************************
4.2.A. OCImg -- Helpers For Palette & Bitmap Manipulation

OCImg is a small DLL that helps implement certain kinds of graphics-intensive controls.
See section 3.1. What Is OCImg.DLL? for more information about OCImg.
 ***********************************************************************
4.2.B. OCMisc -- Helpers For Implementing ActiveX Containers

OCMisc is a static-link library of helper functions that provide OC-related functionality that may be useful to some containers and/or controls, but isn't likely to be useful to most or all controls.
See 4.1. What Is OCMisc.LIB? for more information about OCMisc.
 ***********************************************************************
4.3. Sample Controls

The MM Controls SDK includes the following sample controls that are built using the SDK.  The source code for each is contained in a directory given the name of the control, with "OC" appendend for windowed and windowless controls and "Auto" for invisible controls (also called OLE automation servers).
—	TinyAuto, MiniAuto, TinyOC, CircOC: These are "skeleton controls" that are used as a basis for the tutorial-like instructions for writing a new ActiveX control.  For more information on these skeleton controls, see 4.2.1. Getting Started: Creating A Minimal Control and 4.2. Writing Controls -- Step By Step.
—	FubarOC is a lightweight windowed control that's equivalent to CircOC, but with the first few steps of 4.2. Writing Controls -- Step By Step already applied to it. (The steps that were applied are the steps that make the most sense if you want IE3 compatibility.)
—	LineOC is a lightweight windowless control that displays a line segment.  See Line for more information.
—	PalOC is a lightweight windowless control that displays the container's ambient palette in a 16x16 grid.  PalOC is also useful for demonstrating simple use of OCImg.
4.4. Writing Control Containers

In addition to providing helper functions for creating multimedia-enabled lightweight ActiveX controls, the MM Controls SDK provides some functions (in a separate static-link library) to help implement ActiveX control containers.  For more information about any of the following, see OCMisc.
—	To embed an ActiveX control, see AllocSiteLW and CreateControlInstance, and PickClass.
—	To persist a control (load and save its data) in binary stream format or HTML or CSV text format, see 4.7.4. Persistence Helper Functions as well as PersistSiteProperties and PersistChild.
—	For various utility functions, see 4.7.A. Miscellaneous Functions and 4.7.5. String and Variant Conversion Functions.
This SDK doesn't provide tutorial-like instructions for building an ActiveX control because so few people write containers.  However, if you need to write a container and would like to discuss the issues related to doing so, please mailto:EricLe.
4.5. OCHelp Reference

This section contains reference documentation for OCHelp. For a more "tutorial" approach, see 4.2. Writing Controls -- Step By Step.
4.5.1. What Is OCHelp?
4.5.2. Implementing An In-Process Control DLL
4.5.3. Implementing Properties And Methods
4.5.4. Calling Properties And Methods
4.5.5. Firing Events
4.5.6. Thread Safety And Popup Menus
4.5.7. Implementing IViewObject
4.5.8. Implementing IViewObjectEx
4.5.9. Implementing Persistence and Simple IDispatch
4.5.A. Utility Functions
4.5.B. Design-Time Functions
4.5.1. What Is OCHelp?
OCHelp is a small (currently about 30KB) DLL that makes it possible to implement very small controls (under 10KB for relatively simple controls).
OCHelp is available in both static-link and dynamic-link forms:
—	The static-link version will increase the size of your control, but will eliminate any dependency on the OCHelp DLL.  To use the the static-link version of OCHelp, link with one of the following libraries:
—	debug/OCHelpSD.lib: the debug version, containing both design-time and run-time functions (your control will link with whatever it needs).
—	release/OCHelpS.lib: the release version.
—	The dynamic-link version can be shared among multiple controls, and is the better choice if you plan to ship more than one control, or if it's likely that the end-user's machine will already have the OCHelp DLL (because the user already viewed a different HTML page or loaded a different application that depends on OCHelp).  To use the dynamic-link version of OCHelp, link with one of the following libraries:
—	debug/OCHelpDD.lib: the design-time debug version, which causes your control to use OCHelpDD.dll.
—	debug/OCHelpRD.lib: the run-time debug version, which causes your control to use OCHelpRD.dll.
—	release/OCHelpD.lib: the design-time release version, which causes your control to use OCHelpD.dll.
—	release/OCHelpR.lib: the run-time release version, which causes your control to use OCHelpR.dll.
The various versions of the OCHelp DLLs are installed in the windows\system directory when MMCtl is set up.
The following sections provide reference documentation for the OCHelp API.  For a more "tutorial" approach, see 4.2. Writing Controls -- Step By Step.
4.5.2. Implementing An In-Process Control DLL

The following functions help implement an in-process control DLL, specifically assisting with the implementation of DllRegisterServer, DllUnregisterServer, and DllGetClassObject.  Also, ControlInfo contains a field which can be used to provide a one-line implementation of DllCanUnloadNow.  These functions allow an arbitrary number of controls to be implemented in a DLL.  (Note that an OLE property page is just a simplified case of a control, so property pages are supported as well.)
HelpGetClassObject
Helps implement DllGetClassObject (including the class factory object it creates) for any number of controls.
RegisterControls
Registers or unregisters one or more controls.  Helps implement DllRegisterServer and DllUnregisterServer.
4.5.3. Implementing Properties And Methods

The following functions make it easier to implement IDispatch in your control, which allows other applications (such as VBS) to access properties and methods of your controls.  Only late-bound OLE automation is supported -- no early-bound or dual interfaces.
DispatchGetArgs
Retrieves arguments from a DISPPARAMS structure passed to IDispatch::Invoke.  Arguments are stored in variables that are passed to DispatchGetArgs as a va_list array. Used to help implement IDispatch::Invoke.
DispatchGetArgsList
Retrieves arguments from a DISPPARAMS structure passed to IDispatch::Invoke.  Arguments are stored in variables that are passed to DispatchGetArgsList as a va_list array. Used to help implement IDispatch::Invoke.
DispatchHelpGetIDsOfNames
Helps implement IDispatch::GetIDsOfNames given a string that contains the list of IDispatch member names.
VariantFromString
Initializes a VARIANT to contain the copy of an LPCTSTR string.
4.5.4. Calling Properties And Methods

The following functions make it easier to call IDispatch to access the properties and methods of another object (e.g. to fire events from your control to the container, or to access ambient properites of the container).
DispatchInvoke
Calls IDispatch::Invoke on a given IDispatch object, passing arguments specified as a variable-length list of arguments.
DispatchInvokeList
Calls IDispatch::Invoke on a given IDispatch object, passing arguments specified as a va_list array.
DispatchPropertyGet
Gets the value of a given property on a given IDispatch object. Used to help call IDispatch::Invoke.
DispatchPropertyPut
Sets the value of a given property on a given IDispatch object. Used to help call IDispatch::Invoke.
4.5.5. Firing Events

The following functions make it easier to fire events (e.g. that cause VBS code to be executed in the container).  Multicasting is supported. Only a single IDispatch-based event set is supported per control.
AllocConnectionPointHelper
Allocates a ConnectionPointHelper object, which provides a simple implementation of an IDispatch-based IConnectionPoint, and methods for firing events. Also contains helper functions for implementing IConnectionPointContainer::EnumConnectionPoints in the case where this is only connection maintained by the connection point container.
FreeConnectionPointHelper
Frees a ConnectionPointHelper object allocated using AllocConnectionPointHelper.
HelpGetClassInfoFromTypeLib
Helps implement IProvideClassInfo::GetClassInfo using a caller-provided type library.
4.5.6. Thread Safety And Popup Menus

The following functions allow messages to be passed from one thread to another by sending or posting window messages to a hidden window.
MsgWndCreate
Creates the hidden message-passing window (if it doesn't exist). This window is used by MsgWndSendToCallback, MsgWndPostToCallback, and MsgWndTrackPopupMenuEx.
MsgWndDestroy
Destroys a hidden message-passing window that was previously created by calling MsgWndCreate.  Before the window is destroyed, all pending messages are dispatched in it.
MsgWndPostToCallback
Posts a message to the control's hidden message-passing window (typically created by calling MsgWndCreate in the control's constructor).  When the window receives the message, it calls a given callback function.  This can be used to safely pass information between threads.
MsgWndSendToCallback
Sends a message to the control's hidden message-passing window (typically created by calling MsgWndCreate in the control's constructor).  When the window receives the message, it calls a given callback function.  This can be used to safely pass information between threads.
MsgWndTrackPopupMenuEx
Calls TrackPopupMenuEx to display a popup menu, and directs WM_COMMAND messages to a given callback function.  Can be used by a windowless control to display a popup context menu.
4.5.7. Implementing IViewObject

The following functions help a control writer implement IViewObject.
InitHelpAdvise
Initializes a HelpAdviseInfo structure, used to help implement IViewObject::SetAdvise and IViewObject::GetAdvise.
HelpSetAdvise
Helps implement IViewObject::SetAdvise.
HelpGetAdvise
Helps implement IViewObject::GetAdvise.
UninitHelpAdvise
Peforms final cleanup of a HelpAdviseInfo structure, including releasing the IAdviseSink pointer if necessary.
4.5.8. Implementing IViewObjectEx

The following functions help a control writer implement IViewObjectEx.
HelpQueryHitPoint
Helps implement IViewObjectEx::QueryHitPoint on a control by drawing the control into a small bitmap (centered on the point being hit-tested) and checking if any pixels were drawn.
4.5.9. Implementing Persistence and Simple IDispatch

The following functions help implement IPersistPropertyBag, IPersistStreamInit, and a simple (simplistic?) but very lightweight (control code size) IDispatch.
AllocPropertyBagOnStream
Creates a PropertyBagOnStream object which implements IPropertyBag whose properties are contained in a given IStream.
AllocPropertyBagOnVariantProperty
Creates a PropertyBagOnVariantProperty object which implements IPropertyBag whose only property is contained in a given VariantProperty.
AllocPropertyHelper
Allocates a PropertyHelper object which provides an implementation of IPersist, IPersistPropertyBag, IPersistStream, IPersistStreamInit, and a simplified implementation of IDispatch, for any object which implements IPersistVariantIO.
AllocVariantIOOnPropertyBag
Creates a VariantIOOnPropertyBag object which provides an implementation of IVariantIO (and IManageVariantIO) that operates on a given IPropertyBag.
AllocVariantIOToMapDISPID
Creates a VariantIOToMapDISPID object which provides an implementation of IVariantIO which is used to map a property name to a DISPID (property number) or vice versa.  Can also be used to get or set the value of that property.
LoadPropertyBagFromStream
Load properties that are stored in an IStream (in the simple tagged binary format written by WriteVariantProperty) into an IPropertyBag object.
PersistVariantIO
Loads or saves a list of property name/value pairs, specified as a variable-length list of arguments that's formatted in the same way as IVariantIO::Persist, to/from an IPropertyBag object.
PersistVariantIOList
Loads or saves a list of property name/value pairs, specified as a va_list array that's formatted in the same way as IVariantIO::Persist, to/from an IPropertyBag object.
ReadVariantProperty
Reads a VariantProperty from an IStream in a simple tagged binary format.
VariantPropertyClear
Frees data maintained in a VariantProperty structure.
VariantPropertyInit
Initializes a VariantProperty structure.
WriteVariantProperty
Writes a VariantProperty to an IStream in a simple tagged binary format.
4.5.A. Utility Functions

The following are general-purpose utility functions.
ANSIToUNICODE
Converts an ANSI string to UNICODE.
CompareUNICODEStrings
Compares two UNICODE strings.  The comparison is case-insensitive.
FindCharInString
Searches a string to find a specific character.
FindCharInString
Searches a string from back-to-front to find a specific character.
FindStringByIndex
Finds a string with a given index in a list of strings.
FindStringByValue
Looks up string in a list of strings and returns the index of the string (if found).
HelpDelete
Frees memory allocated by HelpNew.  This is simply a macro that calls HelpMemFree with specific flags.
HelpMemAlloc
Allocates memory using either GlobalAlloc or the task memory allocator retrieved using CoGetMalloc.  Optionally zero-initializes the memory.  Optionally performs simple memory leak detection.
HelpMemFree
Frees a block of memory previously allocated using HelpMemAlloc.
HelpMemSetFailureMode
Sets failure conditions for the memory allocator.  This can be used to simulate low-memory conditions and test a system's ability to detect and/or handle these conditions.  Only available in DEBUG builds of OCHelp.
HelpNew
Helps implement a version of the "new" operator that doesn't use the C runtime.  Zero-initializes the allocated memory. This is simply a macro that calls HelpMemAlloc with specific flags.
HIMETRICToPixels
Converts a width and height from HIMETRIC units to pixels (on the default monitor).
PixelsToHIMETRIC
Converts a width and height from pixels (on the default monitor) to HIMETRIC units.
TaskMemAlloc
Allocates memory using the task memory allocator (see CoGetMalloc). This is simply a macro that calls HelpMemAlloc with specific flags.
TaskMemFree
Frees a block of memory previously allocated using TaskMemAlloc. This is simply a macro that calls HelpMemFree with specific flags.
UNICODEToANSI
Converts a UNICODE string to ANSI.
UNICODEConcat
Concatenates one UNICODE string to another.
UNICODECopy
Copies one UNICODE string to another.
4.5.B. Design-Time Functions

The following are only available in the design-time version of OCHelp.
AllocPropPageHelper
Allocates a PropPageHelper object which helps a control implement a property page.
AllocVerbEnumHelper
Allocates and initializes a verb enumeration helper.  Aids in implementing IOleObject::EnumVerbs.
CreateBorderBrush
Creates and returns a hatch pattern brush used to draw control resize borders and grab handles.
DrawControlBorder
Draws a border used to drag and resize controls.
4.6. OCImg Reference

4.6.1. What Is OCImg?
4.6.2. Working With Bitmaps
4.6.3. Working With Palettes
4.6.4. Utility Functions
4.6.1. What Is OCImg?

OCImg is a small (30-40KB as of 5/96) DLL that helps implement certain kinds of graphics-intensive controls.
OCImg is actually a subset of the MKImage library, packaged as a DLL (instead of as a static-link library) to help minimize the amount of code that would need to be downloaded for Internet controls.  Specifically, any topic in the sections below that is not hyperlinked is not contained in OCImg -- though if you think should be, contact the MM Controls team.
A.1. What Is MKImage 2.0?
A.2. MKImage Fundamentals
A.3. Using MKImage 2.0
A.4. MKImage Interfaces
A.5. MKImage Structures
A.6. Sample Code
A.7. MKImage HRESULT Codes
A.8. Changes Since MKImage 1.0
A.9. Known Bugs
A.A. MKImage Code Size

To use OCImg, link with one of the following libraries:
—	debug/OCImgDD.lib: the design-time debug version, which causes your control to use OCImgDD.dll.
—	debug/OCImgRD.lib: the run-time debug version, which causes your control to use OCImgRD.dll.
—	release/OCImgD.lib: the design-time release version, which causes your control to use OCImgD.dll.
—	release/OCImgR.lib: the run-time release version, which causes your control to use OCImgR.dll.
The various versions of the OCImg DLLs are installed in the windows\system directory when MMCtl is set up.
Since the contents of each of the four variants of the OCImg DLL are still in flux, the easiest way to see what functionality from MKImage is included in run-time vs design-time versions is to take a look at the .def files which define this: OCImg/OCImgD.def and OCImg/OCImgR.def, respectively.
4.6.2. Working With Bitmaps

Important:  The following is documentation from MKImage, from which OCImg*.DLL is derived.  Any topic in the sections below that is not hyperlinked is not contained in OCImg -- though if you think should be, contact the MM Controls team.
B.1. Creating And Converting Bitmaps
B.2. Bitmap I/O Via IStream
B.3. Bitmap I/O Convenience Utilities
B.4. Bitmap Clipboard Operations
B.5. Bitmap Drag & Drop Operations
B.6. Bitmap Drawing Operations
B.7. Bitmap Blt And Pixel Access Operations
B.8. Bitmap Filtering Operations
B.9. Bitmap Information/Utility Functions
4.6.3. Working With Palettes

Important:  The following is documentation from MKImage, from which OCImg*.DLL is derived.  Any topic in the sections below that is not hyperlinked is not contained in OCImg -- though if you think should be, contact the MM Controls team.
C.1. Creating And Converting Palettes
C.2. Palette I/O Via IStream
C.3. Palette Clipboard Operations
C.4. Palette Utilities
4.6.4. Utility Functions

Important:  The following is documentation from MKImage, from which OCImg*.DLL is derived.  Any topic in the sections below that is not hyperlinked is not contained in OCImg -- though if you think should be, contact the MM Controls team.
D.1. Initializing MKImage
D.2. IStream Utilities
D.3. General-Purpose Utilities
4.7. OCMisc Reference

4.7.1. What Is OCMisc?
4.7.2. Wrapping Windowless Controls
4.7.3. Creating Controls
4.7.4. Persistence Helper Functions
4.7.5. String and Variant Conversion Functions
4.7.6. Debugging Helper Functions
4.7.7. Component Categories
4.7.8. Implementing Persistence and Simple IDispatch In Containers
4.7.9. Implementing a File MRU List
4.7.A. Miscellaneous Functions
4.7.1. What Is OCMisc?

OCMisc is a static-link library of helper functions that provide OC-related functionality that may be useful to some containers and/or controls, but isn't likely to be useful to most or all controls. Contrast this with OCHelp which contains functionality that is required by many/most full-featured controls.
To use OCMisc, link with one of the following libraries:
—	debug/OCMiscDD.lib: the design-time debug version.
—	debug/OCMiscRD.lib: the run-time debug version.
—	release/OCMiscD.lib: the design-time release version.
—	release/OCMiscR.lib: the run-time release version.
The following sections provide an overview of the OCMisc API.
4.7.2. Wrapping Windowless Controls

These functions aid in wrapping an ActiveX lightweight, windowless control inside of an ActiveX windowed control.
AllocSiteLW
Creates a SiteLW object that can host a single lightweight windowless ActiveX control.  (Actually SiteLW can also host a windowed control, but support for windowed controls isn't nearly as robust.  If you need this functionality, please mailto:EricLe.)
SiteLW
Implements ISiteLW, which implements an ActiveX windowed control that hosts an ActiveX lightweight windowless control.
ISiteLW
Interface to a SiteLW object, which implements an ActiveX windowed control that hosts an ActiveX lightweight windowless control.
4.7.3. Creating Controls

These functions aid in creating controls.
CreateControlInstance
Creates a new instance of a control given either a class ID (in string form) or a ProgID.
4.7.4. Persistence Helper Functions

These functions aid in implementing streams.
4.7.4.1. Generic Persistence Helper Functions
4.7.4.2. CSV (Comma-Separated-Values) Persistence Helper Functions
4.7.4.3. HTML Persistence Helper Functions
4.7.4.1. Generic Persistence Helper Functions

These functions aid in implementing streams independent of the stream format.
GetStreamLengthToEnd
Calculates the distance (in bytes) between the current position in a stream and the end of the stream.
ReadStreamToMemory
Read bytes from a stream into memory (which is allocated by this function).  Reads either a given number of bytes or until the end of the stream.  The returned block of memory is null-terminated.
LoadFromStream
Read a stream that contains the class ID and data of an object previously saved using IPersistStream::Save, and create an object that contains the data from the stream.
SaveToStream
Save an object that supports IPersistStream to an IStream in a simple binary tagged file format. Can also be used to save just a class ID to a stream (which is useful for saving an object that doesn't support any persistence interface).
4.7.4.2. CSV (Comma-Separated-Values) Persistence Helper Functions

These functions aid in implementing streams which store that contain data in CSV format.
LoadFromCSV
Read a CSV (Excel-readable comma-delimited) format stream and create an object that contains the data from that stream.
LoadPropertyBagFromCSV
Load properties that are stored in an IStream in CSV (Excel-readable comma-delimited) format into a given IPropertyBag object.
ReadVariantPropertyFromCSV
Reads a VariantProperty that's stored in CSV (Excel-readable comma-delimited) format in a memory buffer.
SaveToCSV
Save an object that supports IPersistPropertyBag to an IStream in CSV (Excel-readable comma-delimited) format.
SaveVariantPropertiesToCSV
Save an IEnumVariantProperty object to an IStream in CSV (Excel-readable comma-delimited) format.
WriteVariantPropertyToCSV
Writes a VariantProperty to an IStream in CSV (Excel-readable comma-delimited) format.
4.7.4.3. HTML Persistence Helper Functions

These functions aid in implementing streams which store that contain data in HTML format.  (Actually, only the a single <OBJECT> tag within an HTML file can be edited, although the formatting of the rest of the file is retained.)
LoadFromHTML
Reads an HTML format stream and creates an object specified by an <OBJECT> tag in that stream.
LoadPropertyBagFromHTML
Loads properties that are stored in a <OBJECT> tag in an IStream in HTML format into a given IPropertyBag object.
ReadHTMLTagToVariantIO
Reads an HTML tag from a memory buffer and returns an VariantIO object that contains the contents of that tag.
ReadHTMLToken
Reads an HTML token (word, quoted string, etc.) from an ANSI buffer and returns it as a BSTR.
SaveToHTML
Saves an object that supports IPersistPropertyBag to an IStream in HTML format.
SaveVariantPropertiesToHTML
Saves an IEnumVariantProperty object to an IStream in HTML format.
WriteHTMLTagFromVariantIO
Writes an HTML tag whose attributes are stored in an VariantIO object to an IStream.
WriteHTMLToken
Writes an HTML token (given as an LPOLESTR) to an IStream in ANSI format.
WriteVariantPropertyToHTML
Writes a VariantProperty to an IStream in HTML format as a "<PARAM>" tag.
4.7.5. String and Variant Conversion Functions

These functions aid in converting strings and variants.
PrintableANSIToUNICODE
Converts a printable ANSI string to UNICODE.
UNICODEToPrintableANSI
Converts a UNICODE string to a printable ANSI string.
VariantTypeNameToNumber
Converts a VARTYPE string name to a VARTYPE number.
VariantTypeNumberToName
Converts a VARTYPE value to a string name that can serve as the name of the type.
CLSIDToFriendlyName
Finds the "friendly name" associated with a given class in the system registry.
TCHARFromGUID
Converts a GUID to a TCHAR-based string representation.
CLSIDFromTCHAR
Converts a TCHAR-based string into a CLSID.
4.7.6. Debugging Helper Functions

These functions aid in debugging.  They are only available in DEBUG builds.
DebugIIDName
Finds the name of an interface in the system registration database given the interface's IID (for debugging purposes only).
4.7.7. Component Categories

These functions help select controls which implement particular component categories.
PickClass
Displays a modal "class picker" dialog which lists all the registered classes which support a given set of component categories and lets the user choose one, returning its CLSID.
4.7.8. Implementing Persistence and Simple IDispatch In Containers

The following functions (along AllocPropertyHelper and related functions) help a control container implement IPersistPropertyBag, IPersistStreamInit, and a simple (simplistic?) but very lightweight (control code size) IDispatch.
AllocVariantIO
Creates a VariantIO object which provides a property bag implementation which supports IPropertyBag as well as IVariantIO, IManageVariantIO, and IEnumVariantProperty.
PersistSiteProperties
Loads or saves a list of property name/value pairs associated with the site of the child of a given object from/to a given IVariantIO object.  Used to help implement persistence in control containers.
PersistChild
Loads or saves a child of a given container object from/to a given. IVariantIO object.  Used to help implement persistence in control containers.
AllocChildPropertyBag
Creates a ChildPropertyBag object which implements IPropertyBag that provides a child object (contained within a parent object) access to the child's properties, which are stored within the parent's property bag.  The name of each child's property is prefixed with a given string (e.g. "Controls(7).").
AllocPropertyBagCompactor
Creates a PropertyBagCompactor object which implements IPropertyBag, and which reads and writes its data in a more compact way in a second IPropertyBag by "folding" multiple properties with the same period-terminated prefix (e.g. "Foo.X = 42, Foo.Y = 'Hello'") into a single property (e.g. "Foo = 'X=42,Y=Hello'").
AllocBindHostService
Allocates an implementation of IServiceProvider which provides the IBindHost service (SID_IBindHost, IID_IBindHost), which provides for relative path name resolution when using functions such as URLOpenStream.
4.7.9. Implementing a File MRU List

The following functions can be used to implement a registry-based file MRU list.  The entries in an MRU list are stored as values under a given registry key.  The list contains a caller-specified maximum number of entries.  When an entry is added to the list, it always becomes the "most recent" entry, bumping down less recent entries and, if the list is full, bumping the least recent entry off the list.  Entries in an MRU list can be retrieved sequentially from most to least recent; entries can also be retrieved by index.  Entries can be removed from an MRU list either by index or by name, and the entire list can be cleared en masse.  Finally, a utility function exists to map an MRU list into an application menu.
OpenMRUList
Opens a new or existing registry-based MRU list.
CloseMRUList
Closes a previously opened MRU list.
GetMRUListInfo
Gets information about an MRU list such as the number of entries in the list, the length of the longest entry, and the maximum number of entries.
SetMRUListMaxEntries
Sets the maximum number of entries in an MRU list, possibly truncating the list.
GetNextMRUListEntry
Retrieves the next entry in an MRU list.
GetIthMRUListEntry
Retrieves the i-th entry in an MRU list.
AtEndOfMRUList
Tests if GetNextMRUListEntry has advanced to the end of an MRU list.
ResetMRUList
Resets an MRU list so that the next call to GetNextMRUListEntry will retrieve the first entry.
AddMRUListEntry
Adds an entry to the head of an MRU list.
RemoveAllMRUListEntries
Removes all the entries in an MRU list.
RemoveIthMRUListEntry
Removes an MRU list entry by index.
RemoveMRUListEntry
Removes an MRU list entry by name.
MapMRUListToMenu
Maps an MRU list into an application's menu.
4.7.A. Miscellaneous Functions

The following are miscellaneous functions that don't fit in any other category.  In some cases these functions which may become obsolete (see the descriptions for more information).  Note that since OCMisc is a static link library your application is not penalized for the code size of these functions unless you call them.
FindStringInString
Finds a string within another string.  The comparison can be either case-sensitive or case-insensitive.
HelpGetClassInfo
Helps implement IProvideClassInfo::GetClassInfo.  The implementation provides very limited class information -- just enough to allow firing events to VBS.  Warning: you should probably use HelpGetClassInfoFromTypeLib instead.  See comments for more information.
GetObjectSafety
Determines if an object is safe-for-scripting and/or safe-for-initializing vis-a-vis a given set of interfaces.
5. The ActiveX Control Architecture And MM Controls Extensions

(This section is under construction...)
See also 1.2. MM Controls Requirements Beyond ActiveX.
(Don't forget the IViewObject::Draw S_FALSE thing.)
TBD...
xxx
About Autodoc
The sources for this Help file were generated by Autodoc, the source code documentation tool that generates Print or Help files from tagged comments in C, C++, Assembly, and Basic source files.
For more information, contact Eric Artzt (mailto:erica@microsoft.com).
CircOC
See 4.3. Sample Controls.
FubarOC
See 4.3. Sample Controls.
LineOC
See 4.3. Sample Controls.
MiniAuto
See 4.3. Sample Controls.
OCAuthor
OCAuthor is a simple Visual Basic application provided as part of the MM Controls SDK that functions as a editor and viewer for lightweight windowed and windowless controls.  OCAuthor supports saving and editing an <OBJECT> tag in an HTML file. Most importantly, OCAuthor is a sample application that demonstrates how to use the OCEdit control to build ActiveX control editors in Visual Basic.
Comments
OCAuthor has the following features and restrictions:
—	OCAuthor is a lightweight container that doesn't support all OC96 site interfaces and methods.  This should not be a problem for a well-behaved OC96 control, since controls should not expect every site interface to be fully implemented.  However, some controls may operate incorrectly, or even crash, when used in OCAuthor.
—	OCAuthor can contain only one control at a time.  However, that control can be Stage (or HostLW containing a Stage), which allows an arbitrary number of controls to be embedded.  Nested Stage controls (i.e. Stage controls within Stage controls) are supported.
—	OCAuthor can save a control's data in HTML (Hypertext Markup Language):  If you create and edit a new control instance (via File New) and Save As HTML, OCAuthor saves the control's data (including its class ID) as a simple HTML file containing a single <OBJECT> tag that contains the data of the control in <PARAM> tags.  If you open an existing HTML file, then OCAuthor searches for the first <object> tag (with "object" spelled in lowercase -- so you can "mark" the one object you want to edit by making its tag name lowercas), or, if not found, the first <OBJECT> tag (with "OBJECT" spelled in uppercase), and lets you edit that object; the rest of the HTML file is left untouched when you use File Save.  HTML format is only supported for controls that implement IPersistPropertyBag.
—	OCAuthor supports the concept of both "design mode" and "run mode" (also called "preview" mode, since it uses the design-time version of the loaded control and simply places that control in run mode).
—	OCAuthor will display a property pages for the loaded control if the control implements ISpecifyPropertyPages (typically only in design mode).
—	OCAuthor will display a right-click context menu for the control if the control implements IOleObject::EnumVerbs (typically only in design mode).
—	In design mode, OCAuthor will display a border with grab handles around a control, unless the control returns S_FALSE from IViewObject::Draw indicating that it wants to draw its own grab handles (see 5. The ActiveX Control Architecture And MM Controls Extensions for more information about this MM Controls convention).
—	OCAuthor implements IAnimate, the very simple beginnings of an "animation event negotiation" interface that allows an ActiveX container to animate contained controls.  See 5. The ActiveX Control Architecture And MM Controls Extensions for more information.
OCAuthor accepts a single command-line parameter, which may be any of the following:
—	The ProgID of a control to create a new instance of (e.g. "line.line.1").
—	The class ID of a control to create a new instance of (e.g. "{BA6B5D20-8614-11CF-B8ED-0020AF344E0A}").
—	The name of an HTML file to open.
OCHelp
For information about OCHelp, see: 4.5. OCHelp Reference and 4.2. Writing Controls -- Step By Step.
OCImg
For information about OCImg, see: 4.6. OCImg Reference.
OCMisc
For information about OCMisc, see: 4.7. OCMisc Reference and 4.4. Writing Control Containers.
OCTest
OCTest is a simple Windows application provided as part of the MM Controls SDK that functions as a editor and viewer for lightweight windowed and windowless controls.  OCTest supports saving and editing an <OBJECT> tag in an HTML file.
Comments
OCTest is a simple Windows application that internally uses the SiteLW object provided in the OCMisc helper library (part of the MM Controls SDK) to contain a single OLE/ActiveX control.
OCTest has the following features and restrictions:
—	OCTest is a lightweight container that doesn't support all OC96 site interfaces and methods.  This should not be a problem for a well-behaved OC96 control, since controls should not expect every site interface to be fully implemented.  However, some controls may operate incorrectly, or even crash, when used in OCTest.
—	OCTest can contain only one control at a time.  However, that control can be Stage (or HostLW containing a Stage), which allows an arbitrary number of controls to be embedded.  Nested Stage controls (i.e. Stage controls within Stage controls) are supported.
—	OCTest can save a control's data in one of three formats:
—	HTML (Hypertext Markup Language):  If you create and edit a new control instance (via File New) and Save As HTML, OCTest saves the control's data (including its class ID) as a simple HTML file containing a single <OBJECT> tag that contains the data of the control in <PARAM> tags.  If you open an existing HTML file, then OCTest searches for the first <object> tag (with "object" spelled in lowercase -- so you can "mark" the one object you want to edit by making its tag name lowercas), or, if not found, the first <OBJECT> tag (with "OBJECT" spelled in uppercase), and lets you edit that object; the rest of the HTML file is left untouched when you use File Save.  HTML format is only supported for controls that implement IPersistPropertyBag.
—	CSV (Comma-Separated Variable):  This is a simple format that Excel understands (helpful for debugging).  Unlike HTML, CSV saves the data type (e.g.  VT_I4) of each property, which is useful for testing a control's behavior when used with property bags that preserve type information.  CSV format is only supported for controls that implement IPersistPropertyBag.
—	STM (IPersistStream Binary Format):  This binary format consists of a class ID followed by the data saved via the control's IPersistStream interface.
—	OCTest supports the concept of both "design mode" and "run mode" (also called "preview" mode, since it uses the design-time version of the loaded control and simply places that control in run mode).
—	OCTest will display a property pages for the loaded control if the control implements ISpecifyPropertyPages (typically only in design mode).
—	OCTest will display a right-click context menu for the control if the control implements IOleObject::EnumVerbs (typically only in design mode).
—	In design mode, OCTest will display a border with grab handles around a control, unless the control returns S_FALSE from IViewObject::Draw indicating that it wants to draw its own grab handles (see 5. The ActiveX Control Architecture And MM Controls Extensions for more information about this MM Controls convention).
—	OCTest implements IAnimate, the very simple beginnings of an "animation event negotiation" interface that allows an ActiveX container to animate contained controls.  See 5. The ActiveX Control Architecture And MM Controls Extensions for more information.
OCTest accepts a single command-line parameter, which may be any of the following:
—	The ProgID of a control to create a new instance of (e.g. "line.line.1").
—	The class ID of a control to create a new instance of (e.g. "{BA6B5D20-8614-11CF-B8ED-0020AF344E0A}").
—	The name of a file (HTML, CSV, STM) to open.  OCTest determines the type of the file based on the extension (.htm or .html for HTML files, .csv for CSV files, .stm for STM files).
PalOC
See 4.3. Sample Controls.
TinyAuto
See 4.3. Sample Controls.
TinyOC
See 4.3. Sample Controls.

ABAuto Object
Description
A lightweight invisible ActiveX control which accesses the AudioBoy mixer to allow playing multiple waveform audio files at once.
Defined in: C:/DEV/MMCTL21/AUTODOC/ABAUTO.D
Methods
 ABAuto::PlayFile
Loads a .wave file into memory and plays it, then automatically frees it when it's finished playing.
 ABAuto::LoadFile
Loads a .wav file into memory and creates and returns an ABSound object to refer to it.
 ABauto::AttachSound
Creates and returns an ABChannel object (associated with the ABAuto mixer) and attaches an ABSound object to it.  The sound can then be played, stopped, etc. using methods of ABChannel.
Comments
ABAuto is a sound mixer.  You can load sounds (using e.g. ABAuto::LoadFile) and play the sounds through the mixer by first creating a "channel" for each sound to play through (using ABAuto::AttachSound) and then controlling the channel (using e.g. ABChannel::Play, ABChannel::Stop, etc.) A given sound can be played through multiple channels at once. All sounds are mixed.  See ABAuto::LoadFile for an example.
Alternatively, you can play a sound simply by calling ABAuto::PlayFile, but this doesn't give you as much control over the playback.  See ABAuto::PlayFile for an example.
For all users:
—	This control can be directly embedded in IE3, but not in VB4 because VB doesn't support embedding of lightweight invisible controls.
—	The class ID of the design-time version of this control is "DA3327A0-C543-11CF-B705-00AA00BF27FD"
—	All files played back using ABAuto must be of the same format (e.g. 8 or 16 bit, mono or stero, and same sampling rate such as 22050 or 44100 samples per second).
—	Currently, compressed files are not supported.
For C++ users:
—	The class ID of this control is defined as CLSID_CABAuto in "ABAuto.h".
—	The ProgID of this control is "ABAuto.ABAuto.1".
—	This control implements the following interfaces:
—	IUnknown: A delegating IUnknown that supports aggregation
—	IDispatch: Provides access to the control's properties. Does not provide type information.
—	This control sources (calls) the following interfaces (if available) on the container-provided site object:
—	IOleClientSite: The client site pointer provided by the container.

ABAuto::AttachSound Method
ABChannel AttachSound(ABSound Sound)
Creates and returns an ABChannel object (associated with the ABAuto mixer) and attaches a given ABSound object to it. The sound can then be played, stopped, etc.  using methods of ABChannel.
Defined in: C:/DEV/MMCTL21/AUTODOC/ABAUTO.D
Return Value
Returns an ABChannel object which can be used to control the playback of Sound.
Parameters
Sound
The sound to attach to the mixer.
Example
See LoadFile for an example.

ABAuto::LoadFile Method
ABSound LoadFile(String FileName)
Loads a .wav file into memory and creates and returns an ABSound object to refer to it.
Defined in: C:/DEV/MMCTL21/AUTODOC/ABAUTO.D
Return Value
Returns an ABSound object which can be played using AttachSound and ABChannel::Play.
Parameters
FileName
The name of the file to load.
Example
Assuming "mixer" is an ABAuto object, the following VBS code plays the file "c:\foo.wav".
Dim snd ' an ABSound object
Dim chn ' an ABChannel object
Set snd = mixer.LoadFile("c:\foo.wav")
Set chn = mixer.AttachSound(snd)
chn.Play

ABAuto::PlayFile Method
 PlayFile(String FileName)
Loads a .wav file into memory and plays it, then automatically frees it when it's finished playing.
Defined in: C:/DEV/MMCTL21/AUTODOC/ABAUTO.D
Parameters
FileName
The name of the file to play.
Example
Assuming "mixer" is an ABAuto object, the following VBS code plays the file "c:\foo.wav".
mixer.PlayFile "c:\foo.wav"

ABChannel Object
Description
An AudioBoy channel object.  A channel can have one ABSound associated with it; the channel can then perform playback operations such as Play, Stop, etc.
Defined in: C:/DEV/MMCTL21/AUTODOC/ABAUTO.D
Properties
 ABChannel::Sound
The associated ABSound object.  Read-only.
Methods
 ABChannel::Play
Starts the associated ABSound object playing.  When the sound reaches the end, playing does not stop automatically -- so executing Rewind at this point will cause the sound to play again.
 ABChannel::Stop
Stops playback of the associated ABSound object.  If Play is subsequently executed, playback continues from the point at which it was stopped.
 ABChannel::Rewind
Rewinds playback to the beginning of the ABSound object.  If the ABChannel object is in "play" mode (i.e.  Play was previously called, then playback begins immediately from the beginning of the sound.
Comments
Note that a given ABSound object can be associated with multiple ABChannel objects (using ABAuto::AttachSound).  Each channel will access the sound independently; for example, one channel may be playing near the beginning of the sound, while another channel is playing near the end of the sound, and a third channel is stopped.

ABChannel::Play Method
 Play()
Starts the associated ABSound object playing.  When the sound reaches the end, playing does not stop automatically -- so executing Rewind at this point will cause the sound to play again.
Defined in: C:/DEV/MMCTL21/AUTODOC/ABAUTO.D
Example
See LoadFile for an example.

ABChannel::Rewind Method
 Rewind()
Rewinds playback to the beginning of the ABSound object.  If the ABChannel object is in "play" mode (i.e. Play was previously called, then playback begins immediately from the beginning of the sound.
Defined in: C:/DEV/MMCTL21/AUTODOC/ABAUTO.D

ABChannel::Sound Property
Data Type
ABSound
Description
Returns the ABSound object associated with the ABChannel. Read-only.
Defined in: C:/DEV/MMCTL21/AUTODOC/ABAUTO.D
Example
Assuming "mixer" is an ABAuto object, the following VBS code creates a new ABChannel, chn2, that is associated with the same sound that chn1 (an ABChannel) is associated with.
Dim chn2 ' an ABChannel
Set chn2 = mixer.AttachSound(chn1.Sound)

ABChannel::Stop Method
 Stop()
Stops playback of the associated ABSound object. If Play is subsequently executed, playback continues from the point at which it was stopped.
Defined in: C:/DEV/MMCTL21/AUTODOC/ABAUTO.D

ABSound Object
Description
An AudioBoy sound object.  Represents a waveform audio sound (which may or may not be stored in a file).
Defined in: C:/DEV/MMCTL21/AUTODOC/ABAUTO.D
Properties
Long ABSound::NumSamples
The number of samples in the sound. Files typically contain 11025, 22050, or 44100 samples per second. Read-only.

ABSound::NumSamples Property
Data Type
Long
Description
Returns the number of samples in the sound.  Files typically contain 11025, 22050, or 44100 samples per second.  Read-only.
Defined in: C:/DEV/MMCTL21/AUTODOC/ABAUTO.D

AddMRUListEntry
HRESULT AddMRUListEntry(HMRULIST hMRUList, const TCHAR* szEntry) 
Adds an entry to the head of an MRU list.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/MRU.CPP
Parameters
hMRUList
[in] A handle to a previously opened MRU list.
szEntry
[in] The entry to add.
Comments
The maximum number of entries the list may contain is established when the list is opened (see OpenMRUList) or through the last call to SetMRUListMaxEntries.
If szEntry is already at the head of the list, nothing happens. If szEntry is already in the list, it is moved from its current position to the head of the list.  In any event, szEntry is already added to the head of the list, possibly moving less recent elements down a slot. ---------------------------------------------------------------------------
Return Codes
S_OK	Success.	
(other)	Failure.	

AllocBindHostService
HRESULT AllocBindHostService(LPCTSTR szContainerFileName, IServiceProvider * * ppsp) 
Allocates an implementation of IServiceProvider which provides the IBindHost service (SID_IBindHost, IID_IBindHost), which provides for relative path name resolution when using functions such as URLOpenStream.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ABHS.CPP
Parameters
szContainerFileName
The name of the file that relative path names will be relative to.  For example, if szContainerFileName is "c:\foo\bar.htm" and the caller calls URLOpenStream to open "blorg.gif", then the file "file://c:\foo\blorg.gif" will be opened (assuming that the IUnknown * parameter of URLOpenStream implements IServiceProvider which delegates to *ppsp).  If szContainerFileName is NULL or "", then file names are assumed to be relative to the current directory. szContainerFileName should be under _MAX_PATH characters in length.
ppsp
Where to store a pointer to the newly created object.  NULL is stored in *ppsp on error.
Comments
Whenver the container's file name changes, the old IBindHost servie provider should be freed and AllocBindHostService should be called again to create a new IBindHost service provider.

AllocChildPropertyBag
HRESULT AllocChildPropertyBag(IPropertyBag * ppbParent, LPCSTR szPropNamePrefix, DWORD dwFlags, IPropertyBag * * pppbChild) 
Creates a ChildPropertyBag object which implements IPropertyBag that provides a child object (contained within a parent object) access to the child's properties, which are stored within the parent's property bag.  The name of each child's property is prefixed with a given string (e.g. "Controls(7).").
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ACPB.CPP
Parameters
ppbParent
Parent's property bag.
szPropNamePrefix
Prefix on the property name of each of the child's properties that are stored within the parent's property bag. This prefix does not appear on the properties in the returned property bag *pppbChild.
dwFlags
Currently unused.  Must be set to 0.
pppbChild
Where to store the IPropertyBag pointer to the new ChildPropertyBag object.  NULL is stored in *pppbChild on error.
Return Codes
S_OK	Success.	
E_OUTOFMEMORY	Out of memory.	

AllocConnectionPointHelper
HRESULT AllocConnectionPointHelper(IUnknown * punkParent, REFIID riid, IConnectionPointHelper * ppconpt) 
Allocates a ConnectionPointHelper object, which provides a simple implementation of an IDispatch-based IConnectionPoint. Also contains helper functions for implementing IConnectionPointContainer::EnumConnectionPoints in the case where this is only connection maintained by the connection point container.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/CONNECT.CPP
Parameters
punkParent
The parent of the connection point, which is the object that implements IConnectionPointContainer.
riid
The dispinterface (interface based on IDispatch) which is the event set that the parent object fires methods of.
ppconpt
Where to store the pointer to the newly-allocated object.  NULL is stored in *ppconpt on error.
Comments
Important Unlike most COM objects, the parent object needs to free the ConnectionPointHelper object by calling FreeConnectionPointHelper, not Release.  The reason is that the ConnectionPointHelper object doesn't maintain a reference count if its own -- it simply forwards AddRef and Release calls to punkParent.  Therefore, calling Release on the ConnectionPointHelper object will simply cause Release to be called on the parent.
To use the ConnectionPointHelper object, call IConnectionPointHelper::FireEvent to fire events to any object connected to the ConnectionPointHelper object.
Return Codes
S_OK	Success.	
E_OUTOFMEMORY	Out of memory.	

AllocPropertyBagCompactor
HRESULT AllocPropertyBagCompactor(IPropertyBag * ppbCompact, DWORD dwFlags, IPropertyBag * * pppb) 
Creates a PropertyBagCompactor object which implements IPropertyBag, and which reads and writes its data in a more compact way in a second IPropertyBag by "folding" multiple properties with the same period-terminated prefix (e.g. "Foo.X = 42, Foo.Y = 'Hello'") into a single property (e.g. "Foo = 'X=42,Y=Hello'").
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/APBC.CPP
Parameters
ppbCompact
Compacted property bag. PropertyBagCompactor will save compacted properties to this property bag (if dwFlags doesn't include PBC_ISLOADING) or load compacted properties from this property bag (if dwFlags includes PBC_ISLOADING).
dwFlags
May contain the following:
PBC_ISLOADING
*pppb will be used to load data, i.e. (*pppb)->Read() will be called.  If this flag is not set, then *pppb will be used to save data, i.e. (*pppb)->Write() will be called.
pppb
Where to store the IPropertyBag pointer to the new PropertyBagCompactor object.  This "virtual property bag" contains the uncompacted properties.  When writing into this property bag, write a property with name and value equal to NULL in order to "flush" the compacted property bag (i.e. complete writing its contents).  NULL is stored in *pppb on error.
Comments
The returned IPropertyBag must be used either exclusively for reading (i.e. only IPropertyBag::Read is called) or exclusively for writing (i.e. only IPropertyBag::Write is called), depending on whether PBC_ISLOADING is specified.
Return Codes
S_OK	Success.	
E_OUTOFMEMORY	Out of memory.	

AllocPropertyBagOnStream
HRESULT AllocPropertyBagOnStream(IStream * pstream, DWORD dwFlags, IPropertyBag * * pppb) 
Creates a PropertyBagOnStream object which implements IPropertyBag whose properties are contained in a given IStream.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/APBOS.CPP
Parameters
pstream
Stream to read from or write to (depending on whether the returned IPropertyBag is used for reading or writing).
dwFlags
Currently unused.  Must be set to 0.
pppb
Where to store the IPropertyBag pointer to the new PropertyBagOnStream object.  NULL is stored in *pppb on error.
Comments
The returned IPropertyBag must be used either exclusively for reading (i.e. only IPropertyBag::Read is called) or exclusively for writing (i.e. only IPropertyBag::Write is called).  The properties are read/written starting from the current position of pstream.  When reading/writing is complete, the current position of pstream will be the end of the properties in the stream.
See VariantPropertyHeader for a description of the format of the data in the IStream.
Return Codes
S_OK	Success.	
E_OUTOFMEMORY	Out of memory.	

AllocPropertyBagOnVariantProperty
HRESULT AllocPropertyBagOnVariantProperty(VariantProperty * pvp, DWORD dwFlags, IPropertyBag * * pppb) 
Creates a PropertyBagOnVariantProperty object which implements IPropertyBag whose only property is contained in a given VariantProperty.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/APBOVP.CPP
Parameters
pvp
Holds the single property that the implemented property bag contains.  The caller must allocate *pvp; the PropertyBagOnVariantProperty object holds onto *pvp for the duration of its lifetime, so the caller is responsible for ensuring that *pvp is valid for the lifetime of this object. Both pvp->bstrPropName and pvp->varValue must be valid; at the very least, pvp->varValue must contain an empty VARIANT (initialized using VariantInit).  After the allocated object is freed, the caller is responsible for freeing the contents of *pvp.
dwFlags
Currently unused.  Must be set to 0.
pppb
Where to store the IPropertyBag pointer to the new PropertyBagOnVariantProperty object.  NULL is stored in *pppb on error.
Comments
If the returned IPropertyBag is written to, all properties are ignored except the property named pvp->bstrPropName, whose value is saved to pvp->varValue.  If the property bag is read from, IPropertyBag::Read will return E_FAIL for all properties except pvp->bstrPropName, whose returned value is pvp->varValue.
PropertyBagOnVariantProperty is really only useful in specialized applications which want to efficiently set or get a single property value from an object.
Return Codes
S_OK	Success.	
E_OUTOFMEMORY	Out of memory.	

AllocPropertyHelper
HRESULT AllocPropertyHelper(LPUNKNOWN punkOuter, IPersistVariantIO * ppvio, REFCLSID rclsid, DWORD dwFlags, LPUNKNOWN * ppunk) 
Allocates a PropertyHelper object which provides an implementation of IPersist, IPersistPropertyBag, IPersistStream, IPersistStreamInit, and a simplified implementation of IDispatch, for any object which implements IPersistVariantIO.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/APH.CPP
Parameters
punkOuter
The IUnknown of the parent object object (presumably the same object that implements IPersistVariantIO).  Will be used as the controlling unknown of PropertyHelper.
ppvio
The interface used to access the properties of the parent object.  Note that this interface is not AddRefd by AllocPropertyHelper, since doing so would likely cause a circular reference count.  Therefore it is the caller's responsibility to ensure that ppvio remain valid for the lifetime of the PropertyHelper object.
rclsid
The class of the containing object (the object which implements IPersistVariantIO).
dwFlags
Currently unused.  Must be set to 0.
ppunk
Where to store a pointer to the non-delegating IUnknown of the allocated PropertyHelper object.  NULL is stored in *ppunk on error.
Comments
See PropertyHelper for more information.
Example
The following example shows how a control might use AllocPropertyHelper.  This example control is aggregatable, though the control need not be aggregatable to use AllocPropertyHelper.
// control implementation
class CMyControl : public INonDelegatingUnknown, public IOleControl,
	public IPersistVariantIO ...
{

///// general control state
protected:
	BOOL            m_fDirty;       // TRUE iff control needs saving
	IUnknown *      m_punkPropHelp; // aggregated PropertyHelper object
	...

///// construction, destruction
public:
	CMyControl(IUnknown *punkOuter, HRESULT *phr);
	virtual ~CMyControl();

///// non-delegating IUnknown implementation
protected:
	ULONG           m_cRef;         // object reference count
	STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, LPVOID *ppv);
	STDMETHODIMP_(ULONG) NonDelegatingAddRef();
	STDMETHODIMP_(ULONG) NonDelegatingRelease();

///// delegating IUnknown implementation
protected:
	LPUNKNOWN       m_punkOuter;    // controlling unknown
	STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv)
	  { return m_punkOuter->QueryInterface(riid, ppv); }
	STDMETHODIMP_(ULONG) AddRef()
	  { return m_punkOuter->AddRef(); }
	STDMETHODIMP_(ULONG) Release()
	  { return m_punkOuter->Release(); }

///// IOleControl implementation
protected:
	STDMETHODIMP GetControlInfo(LPCONTROLINFO pCI);
	STDMETHODIMP OnMnemonic(LPMSG pMsg);
	STDMETHODIMP OnAmbientPropertyChange(DISPID dispid);
	STDMETHODIMP FreezeEvents(BOOL bFreeze);

///// IPersistVariantIO implementation
protected:
	STDMETHODIMP InitNew();
	STDMETHODIMP IsDirty();
	STDMETHODIMP DoPersist(IVariantIO* pvio, DWORD dwFlags);

...
};

CMyControl::CMyControl(IUnknown *punkOuter, HRESULT *phr)
{
	// initialize IUnknown state
	m_cRef = 1;
	m_punkOuter = (punkOuter == NULL ?
		(IUnknown *) (INonDelegatingUnknown *) this : punkOuter);

	// set the control's default properties
	...

	// allocate a PropertyHelper object (to be aggregated with this
	// object) to implement persistence and properties
	if (FAILED(*phr = AllocPropertyHelper(m_punkOuter, this,
			CLSID_CMyControl, 0, &m_punkPropHelp)))
		return;

	// other initialization
	...

	*phr = S_OK;
}

CMyControl::~CMyControl()
{
	// clean up
	if (m_punkPropHelp != NULL)
		m_punkPropHelp->Release();
	...
}

STDMETHODIMP CMyControl::NonDelegatingQueryInterface(REFIID riid,
	LPVOID *ppv)
{
	*ppv = NULL;
	if (IsEqualIID(riid, IID_IUnknown))
		*ppv = (IUnknown *) (INonDelegatingUnknown *) this;
	else
	if (IsEqualIID(riid, IID_IOleControl))
		*ppv = (IOleControl *) this;
	else
	...
	else
		return m_punkPropHelp->QueryInterface(riid, ppv);

	((IUnknown *) *ppv)->AddRef();
	return S_OK;
}

AllocPropPageHelper
HRESULT AllocPropPageHelper(LPUNKNOWN punkOuter, PropPageHelperInfo * pInfo, UINT cbInfo, LPUNKNOWN * ppunk) 
Allocates a PropPageHelper object which helps a control implement a property page.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/PROPHELP.CPP
Parameters
punkOuter
The IUnknown of the control's property page object.  Will be used as the controlling unknown of PropPageHelper.
pInfo
Points to a PropPageHelperInfo structure allocated within the control's property page object. Note that PropPageHelper will hold onto a pointer to this structure.  These fields of pInfo must be initialized by the caller: idDialog, idTitle, hinst, pproc, iid, and dwUser.  The other fields will be initialized by PropPageHelper.
cbInfo
The size of the structure pointed to by punkOuter (used for version checking).
ppunk
Where to store a pointer to the non-delegating IUnknown of the allocatedd PropPageHelper object.  NULL is stored in *ppunk on error.

AllocSiteLW
HRESULT AllocSiteLW(HWND hwnd, HINSTANCE hinst, ISiteLW * * ppsite) 
Creates a SiteLW object that can host a single lightweight windowless ActiveX control.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Parameters
hwnd
Window into which the site object will display the loaded control.
hinst
Instance handle of the DLL which contains the resources used by SiteLW.
ppsite
Where to store the new ISiteLW pointer.  NULL is stored in *ppsite on error.
Comments
The newly-created site object initially has no ActiveX control loaded.
Return Codes
S_OK	Success.	
E_OUTOFMEMORY	Out of memory.	

AllocVariantIO
HRESULT AllocVariantIO(IManageVariantIO * * ppmvio) 
Creates a VariantIO object which provides a property bag implementation which supports IPropertyBag as well as IVariantIO, IManageVariantIO, and IEnumVariantProperty.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/AVIO.CPP
Parameters
ppmvio
Where to store the IManageVariantIO pointer to the new VariantIO object.  NULL is stored in *ppmvio on error.
Comments
Note that IManageVariantIO is based on IVariantIO, so the pointer returned in *ppmvio can be safely cast to an IVariantIO pointer.
Return Codes
S_OK	Success.	
E_OUTOFMEMORY	Out of memory.	

AllocVariantIOOnPropertyBag
HRESULT AllocVariantIOOnPropertyBag(IPropertyBag * ppb, IManageVariantIO * * ppmvio) 
Creates a VariantIOOnPropertyBag object which provides an implementation of IVariantIO (and IManageVariantIO) that operates on a given IPropertyBag.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/AVIOOPB.CPP
Parameters
ppb
Property bag that the new object is to operate on.
ppmvio
Where to store the IManageVariantIO pointer to the new VariantIOOnPropertyBag object.  NULL is stored in *ppmvio on error.
Comments
Note that IManageVariantIO is based on IVariantIO, so the pointer returned in *ppmvio can be safely cast to an IVariantIO pointer.
Return Codes
S_OK	Success.	
E_OUTOFMEMORY	Out of memory.	

AllocVariantIOToMapDISPID
HRESULT AllocVariantIOToMapDISPID(char * pchPropName, DISPID * pdispid, VARIANT * pvar, DWORD dwFlags, IVariantIO * * ppvio) 
Creates a VariantIOToMapDISPID object which provides an implementation of IVariantIO which is used to map a property name to a DISPID (property number) or vice versa.  Can also be used to get or set the value of that property.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/AVIOTMD.CPP
Parameters
pchPropName
A pointer to a caller-allocated buffer containing (on entry) either a property name to search for the DISPID of, or "" if it's the property name being searched for (if *pdispid contains a non-negative number on entry). pchPropName must remain valid for the lifetime of the allocated object.  If pchPropName is "" on entry, then it must have enough space for _MAX_PATH characters.
pdispid
A pointer to a caller-allocated DISPID variable containing (on entry) either a DISPID to find the property name of, or -1 if it's the DISPID that's being searched for (if pchPropName is non-empty on entry).  *pdispid must remain valid for the lifetime of the allocated object.
pvar
A pointer to a caller-allocated VARIANT variable, if either VIOTMD_GETPROP or VIOTMD_PUTPROP are specified in dwFlags -- see those flags for more information.  If provided, *pvar must be initialized by VariantInit on entry and must remain valid for the lifetime of the allocated object.
dwFlags
May optionally contain the following flags:
VIOTMD_GETPROP
The value of the property (if found) is copied to *pvar.  The previous value in *pvar is cleared using VariantClear.
VIOTMD_PUTPROP
The value of the property (if found) is set to *pvar, which must contain a valid valu on entry.
ppvio
Where to store the IVariantIO pointer to the new VariantIOToMapDISPID object.  NULL is stored in *ppvio on error.
Comments
DISPIDs assigned by this function start at DISPID_BASE (defined in ochelp.h) to avoid colliding with the DISPID values assigned by DispatchHelpGetIDsOfNames.
Example
To find the DISPID of property "Foo" implemented by an object ppvio that implements IPeristVariantIO, do the following.  Error checking is not shown.
char *achPropName = "Foo";
DISPID dispid = -1;
IVariantIO *pvio;
AllocVariantIOToMapDISPID(&szPropName, &dispid, NULL, 0, &pvio);
ppvio->DoPersist(pvio, PVIO_PROPNAMESONLY);
if (dispid != -1)
	... found DISPID <dispid> ...

To find the property name of a property with DISPID 7 implemented by an object ppvio that implements IPeristVariantIO, do the following.  Error checking is not shown.
char achPropName[_MAX_PATH];
achPropName[0] = 0;
DISPID dispid = 7;
IVariantIO *pvio;
AllocVariantIOToMapDISPID(&achPropName, &dispid, NULL, 0, &pvio);
ppvio->DoPersist(pvio, PVIO_PROPNAMESONLY);
if (achPropName[0] != 0)
	... found property name <achPropName>...

To set the value of the property with DISPID 7 to 32-bit integer value 42, do the following.  Error checking is not shown.
char achPropName[_MAX_PATH];
achPropName[0] = 0;
DISPID dispid = 7;
IVariantIO *pvio;
VARIANT var;
var.vt = VT_I2;
V_I2(&var) = 42;
AllocVariantIOToMapDISPID(&achPropName, &dispid, &var, VIOTMD_PUTPROP,
	&pvio);
ppvio->DoPersist(pvio, 0);
if (achPropName[0] != 0)
	... successfully set property <dispid> to value <var> ...

Return Codes
S_OK	Success.	
E_OUTOFMEMORY	Out of memory.	

AllocVerbEnumHelper
IEnumOLEVERB* AllocVerbEnumHelper(LPUNKNOWN punkOuter, void* pOwner, CLSID clsidOwner, VERB_ENUM_CALLBACK* pCallback) 
Allocates and initializes a verb enumeration helper.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/ENUMVERB.CPP
Return Value
The verb enumeration helper's IEnumOLEVerb interface or NULL if out of memory.
Parameters
punkOuter
[in] The controlling unknown.  May be NULL.
pOwner
[in] The verbs' "owner".  That is, the object to which the verbs refer.  May not be NULL.
clsidOwner
[in] The class ID of pOwner.  When the verb helper is allocated, clsidOwner is passed to OleRegEnumVerbs to get an IEnumOLEVERB interface.
pCallback
[in] This function will be called whenever the verb helper is asked for verbs via its internal IEnumOLEVERB::Next method. pCallback is passed a pointer to each OLEVERB.  May not be NULL.  VERB_ENUM_CALLBACK is defined as follows:
typedef HRESULT (VERB_ENUM_CALLBACK)(OLEVERB* pVerb, void* pOwner);
Comments
To implement IOleObject::EnumVerbs, make sure that pObject's class registers its verbs, define a VERB_ENUM_CALLBACK callback function and implement IOleObject::EnumVerbs by calling AllocVerbEnumHelper.  That's all it takes.
Typically the pCallback function adjusts the state of the verb's menu item based on the state of the pOwner object.
Example
The following example shows a typical implementation of IOleObject::EnumVerbs, and the verb helper callback function:
STDMETHODIMP CMyControl::EnumVerbs(IEnumOLEVERB** ppEnumOleVerb)
{
	HRESULT hResult;
	*ppEnumOleVerb = AllocVerbEnumHelper(NULL, CLSID_CMyControl,
						&VerbEnumCallback, this);
	hResult = (*ppEnumOleVerb != NULL) ? S_OK : E_OUTOFMEMORY;
	return (hResult);
}

HRESULT VerbEnumCallback(
OLEVERB* pVerb,
void* pOwner)
{
	int flag;
	CMyControl* pMyControl = (CMyControl*)pOwner;

	switch (pVerb->lVerb)
	{
		case 0: // verb 0
			// if pMyControl indicates that verb 0 should be enabled
			//		flag = MF_ENABLED;
			// else
			//		flag = MF_GRAYED;
			break;
		case 1: // verb 1
			// if pMyControl indicates that verb 1 should be enabled
			//		flag = MF_ENABLED;
			// else
			//		flag = MF_GRAYED;
			break;

		// etc.

		default:
			break;
	}
	pVerb->fuFlags |= flag;
	return (S_OK);
}
---------------------------------------------------------------------------

ANSIToUNICODE
int ANSIToUNICODE(LPWSTR pwchDst, LPCSTR pchSrc, int cwchDstMax) 
Converts an ANSI string to UNICODE.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/UNICODE.CPP
Parameters
pwchDst
The buffer that will hold the output UNICODE string.
pchSrc
The input ANSI string.
cwchDstMax
The capacity of pwchDst (in wide characters).

AtEndOfMRUList
BOOL AtEndOfMRUList(HMRULIST hMRUList) 
Tests if GetNextMRUListEntry has advanced to the end of an MRU list.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/MRU.CPP
Return Value
Returns one of the following:
TRUE
At the end.
FALSE
Not at the end. ---------------------------------------------------------------------------
Parameters
hMRUList
[in] A handle to a previously opened MRU list.

ChildPropertyBag Object
Description
Implements IPropertyBag that provides a child object (contained within a parent object) access to the child's properties, which are stored within the parent's property bag.  The name of each child's property is prefixed with a given string (e.g. "Controls(7).").
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ACPB.CPP
Supported Interfaces
IPropertyBag
The interface through which the child object accesses its properties.
Comments
Use AllocChildPropertyBag to create a ChildPropertyBag object.

CloseMRUList
HRESULT CloseMRUList(HMRULIST hMRUList) 
Closes a previously opened MRU list.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/MRU.CPP
Parameters
hMRUList
[in] A handle to a previously opened MRU list.
Return Codes
S_OK	Success. ---------------------------------------------------------------------------	

CLSIDFromTCHAR
HRESULT CLSIDFromTCHAR(const TCHAR* pszCLSID, CLSID* pclsid) 
Converts a string into a CLSID.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/TCH2CLSD.CPP
Parameters
pszCLSID
[in] A TCHAR-based string representation of the CLSID.  Can't be NULL.
pclsid
[out] Set to the resultant class ID.
Comments
This function is a TCHAR equivalent of CLSIDFromString which only works with an OLESTR.
Return Codes
S_OK	Success.	
(other)	Failure.  The value of pclsid is indeterminate.	

See Also
TCHARFromGUID ---------------------------------------------------------------------------

CLSIDToFriendlyName
HRESULT CLSIDToFriendlyName(REFCLSID clsid, TCHAR* pszFriendlyName, int cchMaxFriendlyNameLen) 
Finds the "friendly name" associated with a given class in the system registry.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/CLSID2FN.CPP
Parameters
clsid
[in] The ID of the target class.
pszFriendlyName
[out] If successful, set to the first cchMaxFriendlyNameLen charactes of the friendly name.  Assumed, on entry, to point to a buffer of at least cchMaxFriendlyNameLen characters. Cannot be NULL.
cchMaxFriendlyNameLen
[in] The maximum number of characters of the friendly name to retrieve.  Must be greater than 0.
Comments
Assumes that the system registry is structured as follows:
HKEY_CLASSES_ROOT CLSID clsid ProgID=<progID> : <progID>=<friendly name> ---------------------------------------------------------------------------
Return Codes
S_OK	Success.	
E_FAIL	Failure.  pszFriendlyName is guaranteed to be set to an empty string.	

CompareUNICODEStrings
int CompareUNICODEStrings(LPCWSTR wsz1, LPCWSTR wsz2) 
Compares two UNICODE strings.  The comparison is case-insensitive.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/CUS.CPP
Return Value
Returns the same values as lstrcmpi.
Parameters
wsz1
First string.
wsz2
Second string.
Comments
Currently, neither wsz1 or wsz2 can be longer than _MAX_PATH characters.

ConnectionPointHelper Object
Description
Contains functions for implementing the ConnectionPointHelper object, which provides a simple implementation of an IDispatch-based IConnectionPoint.  Also contains helper functions for implementing IConnectionPointContainer in the case where this is only connection maintained by the connection point container.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/CONNECT.CPP
Supported Interfaces
IConnectionPoint
Standard OLE connection point interface. An arbitrary number of connections are supported.
IConnectionPointHelper
Contains methods for firing events to the objects connected to this object via IConnectionPoint. Also contains helper functions for implementing IConnectionPointContainer in the container object.

CreateBorderBrush
HBRUSH CreateBorderBrush(void) 
Creates and returns a hatch pattern brush used to draw control resize borders and grab handles.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/BRUSH.CPP
Return Value
Returns a handle to the created brush.  The caller is responsible for freeing the brush using DeleteObject.
Comments
The returned brush is the standard brush for use in drawing control borders and grab handles.

CreateControlInstance
HRESULT CreateControlInstance(LPCSTR szName, LPUNKNOWN punkOuter, DWORD dwClsContext, LPUNKNOWN * ppunk, CLSID * pclsid, BOOL * pfSafeForScripting, BOOL * pfSafeForInitializing, DWORD dwFlags) 
Creates a new instance of a control given either a class ID (in string form) or a ProgID.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/CCI.CPP
Parameters
szName
The class ID or ProgID of the control to create.
punkOuter
The controlling unknown to use for the new object.
dwClsContext
Specifies the context in which the executable is to be run. The values are taken from the enumeration CLSCTX. A typical value is CLSCTX_INPROC_SERVER.
ppunk
Where to store the pointer to the loaded object. NULL is stored in *ppunk on error.
pclsid
Where to store the class ID of the loaded object. If pclsid is NULL then this information is not returned.
pfSafeForScripting
If non-NULL, *pfSafeForScripting is set to TRUE or FALSE depending on whether the control is safe-for-scripting.
pfSafeForInitializing
If non-NULL, *pfSafeForInitializing is set to TRUE or FALSE depending on whether the control is safe-for-initializing.
dwFlags
Currently unused.  Must be set to 0.

CRegMRUList::Init
HRESULT CRegMRUList::Init(int cMaxEntries, HKEY hKey, [in] LPCTSTR pszSubkey, [in] LPCTSTR pszListName) 
Initializes an MRU list.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/MRU.CPP
Parameters
cMaxEntries
[in] The maximum number of entries in the list.
hKey
[in] The list will be opened at the registry path, hKey\pszSubkey\pszListName.
pszSubkey
(See hKey.)
pszListName
(See hKey.)
Comments
This must be the first function called on the list after it has been created.
If the registry key contains more than cMaxEntries, it will be truncated to cMaxEntries. ---------------------------------------------------------------------------
Return Codes
S_OK	Success.	
(other)	Failure.	

DebugCLSIDName
ifdef _DEBUGLPCSTR DebugCLSIDName(REFCLSID rclsid, LPSTR pchName) 
Finds the name of an interface in the system registration database given the interface's CLSID (for debugging purposes only).
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/DEBUG.CPP
Return Value
Returns a pointer to pchName.
Parameters
rclsid
Class ID to find the name of.
pchName
Where to store the class ID name string.  This buffer should be large enough to hold _MAX_PATH characters.
Comments
If the interface name is not found, a hexadecimal string form of rclsid will be returned (e.g. "{209D2C80-11D7-101B-BF00-00AA002FC1C2}").
This function is only available in a debug build.

DebugIIDName
LPCSTR DebugIIDName(REFIID riid, LPSTR pchName) 
Finds the name of an interface in the system registration database given the interface's IID (for debugging purposes only).
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/DEBUG.CPP
Return Value
Returns a pointer to pchName.
Parameters
riid
Interface ID to find the name of.
pchName
Where to store the class ID name string.  This buffer should be large enough to hold _MAX_PATH characters.
Comments
If the interface name is not found, a hexadecimal string form of riid will be returned (e.g. "{209D2C80-11D7-101B-BF00-00AA002FC1C2}").
This function is only available in a debug build.

DispatchGetArgs
HRESULT DispatchGetArgs(DISPPARAMS * pdp, DWORD dwFlags, (varying) (arguments)) 
Retrieves arguments from a DISPPARAMS structure passed to IDispatch::Invoke.  Arguments are stored in variables that are passed to DispatchGetArgs as a va_list array. Used to help implement IDispatch::Invoke.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/DISPHELP.CPP
Parameters
pdp
The structure to retrieve arguments from.
dwFlags
May contain the following flags:
DGA_EXTRAOK
Don't return an error code if pdp contains more actual arguments than the number of formal parameters specified in (arguments).  Instead, just ignore the extra arguments in pdp.
DGA_FEWEROK
Don't return an error code if pdp contains fewer actual arguments than the number of formal parameters specified in (arguments).  Instead, ignore the extra parameters.  In this case, the variables pointed to by elements of (arguments) should be pre-initialized to default values before this function is called.
(arguments)
A list of pointers to variables which will receive the values of arguments from pdp.  These must consist of N pairs of arguments followed by a 0 (zero value).  In each pair, the first argument is a VARTYPE value that indicates the type of variable that the the second argument points to.  (The actual arguments in pdp will be coerced to the types specified in (arguments), if possible.) The following VARTYPE values are supported:
VT_INT
The following argument is an int *.
VT_I2
The following argument is a short *.
VT_I4
The following argument is a long *.
VT_R4
The following argument is a float *.
VT_R8
The following argument is a double *.
VT_BOOL
The following argument is a BOOL * (not a VARIANT_BOOL *).  Note that this behavior differs slightly from the usual definition of VT_BOOL.
VT_BSTR
The following argument is a BSTR *.  The caller of DispatchGetArgs should free this BSTR using SysFreeString.  IMPORTANT This behavior has changed: previously the caller was NOT supposed to free this BSTR. (Note that the caller must free the BSTR because it may have been coerced from e.g. an integer.)
VT_LPSTR
The following argument is an LPSTR that points to a char array capable of holding at least _MAX_PATH characters including the terminating NULL.
VT_DISPATCH
The following argument is an LPDISPATCH *. The caller of DispatchGetArgs should not call Release on this LPDISPATCH.
VT_VARIANT
The following arguement is a VARIANT *. This allows arbitrary parameters to be passed using this function.  Note that this behavior differs from the usual definition of VT_VARIANT.  The caller of DispatchGetArgs should not call VariantClear on this VARIANT.
Example
The following example shows two parameters, an integer and a string, being retrieved from pdispparams and stored into i and ach.
int i;
char ach[_MAX_PATH];
DispatchGetArgs(pdispparams, 0, VT_INT, &i, VT_LPSTR, ach, 0);

Return Codes
S_OK	Success.	
DISP_E_BADPARAMCOUNT	The number of arguments in pdp doesn't match the number of arguments specified in (arguments).	
DISP_E_BADVARTYPE	One of the VARTYPE values in (arguments) is invalid.	
DISP_E_TYPEMISMATCH	One of the arguements in pdp could not be coerced to the type of the corresponding parameter in (arguments).	

DispatchGetArgsList
HRESULT DispatchGetArgsList(DISPPARAMS * pdp, DWORD dwFlags, va_list args) 
Retrieves arguments from a DISPPARAMS structure passed to IDispatch::Invoke.  Arguments are stored in variables that are passed to DispatchGetArgsList as a va_list array. Used to help implement IDispatch::Invoke.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/DISPHELP.CPP
Parameters
pdp
The structure to retrieve arguments from.
dwFlags
May contain the following flags:
DGA_EXTRAOK
Don't return an error code if pdp contains more actual arguments than the number of formal parameters specified in args.  Instead, just ignore the extra arguments in pdp.
DGA_FEWEROK
Don't return an error code if pdp contains fewer actual arguments than the number of formal parameters specified in args.  Instead, ignore the extra parameters. In this case, the variables pointed to by elements of args should be pre-initialized to default values before this function is called.
args
A list of pointers to variables which will receive the arguments from pdp.  See DispatchGetArgs for a description of the organizatin of args.
Return Codes
S_OK	Success.	
DISP_E_BADPARAMCOUNT	The number of arguments in pdp doesn't match the number of arguments specified in args.	
DISP_E_BADVARTYPE	One of the VARTYPE values in args is invalid.	
DISP_E_TYPEMISMATCH	One of the arguements in pdp could not be coerced to the type of the corresponding parameter in args.	

DispatchHelpGetIDsOfNames
HRESULT DispatchHelpGetIDsOfNames(REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgdispid, char * szList) 
Helps implement IDispatch::GetIDsOfNames given a string that contains the list of IDispatch member names.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/DISPHELP.CPP
Return Value
Returns the same return codes as IDispatch::GetIDsOfNames.
Parameters
riid
As defined for IDispatch::GetIDsOfNames.
rgszNames
As defined for IDispatch::GetIDsOfNames.
cNames
As defined for IDispatch::GetIDsOfNames.
lcid
As defined for IDispatch::GetIDsOfNames.
rgdispid
As defined for IDispatch::GetIDsOfNames.
szList
The list of member names.  Each name in the list must be terminated by a newline.  The first member name is assigned DISPID value 0, the second 1, and so on.  For example, if szList is "\nFoo\nBar\n", then "Foo" is assigned DISPID value 1 and "Bar" is assigned 2 (because, in this example, the first string in szList is "").

DispatchIDToName
DISPID DispatchIDToName(char * szList, DISPID dispid) 
Look up a DISPID in a list of names of methods and properties and return the member name (if found).
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/DISPID.CPP
Return Value
Returns a pointer to member number dispid in szList if found, or NULL if not found.  Note that the returned string is terminated by a newline character, not a null character -- user ppch to copy the string (see the example below).
Parameters
szList
The list of member names to look up szName in. szList consists of the concatenation of each member name, where each member name is terminated by a newline character (e.g. "Foo\nBar\n").
dispid
The member ID to look up.  The first member in szList has DISPID 1; the second 2, and so on.
Example
The following code stores "Bar" in ach.
int cch;
char ach[100];
char *sz;
DISPID dispid = 2;
sz = DispatchIDToName("Foo\nBar\n", dispid, &cch);
if (sz != NULL)
	lstrcpyn(ach, sz, cch + 1);

DispatchInvoke
HRESULT DispatchInvoke(IDispatch * pdisp, DISPID dispid, WORD wFlags, VARIANT * pvarResult, (varying) (arguments)) 
Calls IDispatch::Invoke on a given IDispatch object, passing arguments specified as a variable-length list of arguments.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/DISPHELP.CPP
Return Value
Returns the same HRESULT as IDispatch::Invoke.
Parameters
pdisp
The interface to call IDispatch::Invoke on.
dispid
The ID of the property or method to invoke.  See IDispatch::Invoke for more information.
wFlags
May be one of the following values (see IDispatch::Invoke for more information):
DISPATCH_METHOD
The member dispid is being invoked as a method.  If a property has the same name, both this and the DISPATCH_PROPERTYGET flag may be set.
DISPATCH_PROPERTYGET
The member dispid is being retrieved as a property or data member.
DISPATCH_PROPERTYPUT
The member dispid is being changed as a property or data member.
pvarResult
Where to store the return value from the method or property-get call.  If pvarResult is NULL, the result (if any) is discarded.  If pvarResult is non-NULL, then it is the caller's responsibility to call VariantClear(pvarResult) on exit (but the caller doesn't have to call VariantInit(pvarResult) on entry).
(arguments)
The arguments to pass to the method or property.  These must consist of N pairs of arguments followed by a 0 (zero value).  In each pair, the first argument is a VARTYPE value that indicates the type of the second argument.  The following VARTYPE values are supported:
VT_INT
The following argument is an int.  Invoke passes this as VT_I4, so this parameter should be declared as a Long in BASIC.
VT_I2
The following argument is a short.  In BASIC this parameter should be declared as Integer.
VT_I4
The following argument is a long.  In BASIC this parameter should be declared as Long.
VT_R4
The following argument is a float.  In BASIC this parameter should be declared as Single.
VT_R8
The following argument is a double.  In BASIC this parameter should be declared as Double.
VT_BOOL
The following argument is a BOOL (not a VARIANT_BOOL).  In BASIC this parameter should be declared as Boolean or Integer.  Note that this behavior differs slightly from the usual definition of VT_BOOL.
VT_BSTR
The following argument is a BSTR.  In BASIC this parameter should be declared as String.
VT_LPSTR
The following argument is an LPSTR.  Invoke passes this as a BSTR, so this parameter should be declared as a String in BASIC.  Note that this behavior differs from the usual definition of VT_LPSTR.
VT_DISPATCH
The following argument is an LPDISPATCH.  In BASIC this parameter should be declared as an Object.
VT_VARIANT
The following arguement is a VARIANT that is passed as-is to Invoke.  This allows arbitrary parameters to be passed using this function.  Note that this behavior differs from the usual definition of VT_VARIANT.
Comments
Named arguments are not supported by this function.
Don't forget to add a 0 argument to the end of the argument list.
Example
The following example calls method DISPID_BAR, passing arguments 42, "Hi There", and TRUE.
pdisp->DispatchInvoke(pdisp, DISPID_BAR, DISPATCH_METHOD,
	VT_INT, 42, VT_LPSTR, "Hi There", VT_BOOL, TRUE, 0);

DispatchInvokeList
HRESULT DispatchInvokeList(IDispatch * pdisp, DISPID dispid, WORD wFlags, VARIANT * pvarResult, va_list args) 
Calls IDispatch::Invoke on a given IDispatch object, passing arguments specified as a va_list array.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/DISPHELP.CPP
Return Value
Returns the same HRESULT as IDispatch::Invoke.
Parameters
pdisp
The interface to call IDispatch::Invoke on.
dispid
The ID of the property or method to invoke.  See IDispatch::Invoke for more information.
wFlags
May be one of the following values (see IDispatch::Invoke for more information):
DISPATCH_METHOD
The member dispid is being invoked as a method.  If a property has the same name, both this and the DISPATCH_PROPERTYGET flag may be set.
DISPATCH_PROPERTYGET
The member dispid is being retrieved as a property or data member.
DISPATCH_PROPERTYPUT
The member dispid is being changed as a property or data member.
pvarResult
Where to store the return value from the method or property-get call.  If pvarResult is NULL, the result (if any) is discarded.  If pvarResult is non-NULL, then it is the caller's responsibility to call VariantClear(pvarResult) on exit (but the caller doesn't have to call VariantInit(pvarResult) on entry).
args
The arguments to pass to the method or property. See DispatchInvoke for a description of the organization of args.
Comments
Named arguments are not supported by this function.

DispatchNameToID
DISPID DispatchNameToID(char * szList, char * szName) 
Look up a IDispatch member name (e.g. the name of a method or property) in a list of names and return the DISPID of the member name (if found).
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/DISPID.CPP
Return Value
Returns the DISPID of szName if szName is found in szList.  Returns -1 if szName is not found.
Parameters
szList
The list of member names to look up szName in. szList consists of the concatenation of each member name, where each member name is terminated by a newline character (e.g. "Foo\nBar\n").
szName
The member name to look up.
Example
The following line of code sets dispid to 2.
dispid = DispatchNameToID("Foo\\nBar\\n", "bar");

DispatchPropertyGet
HRESULT DispatchPropertyGet(IDispatch * pdisp, DISPID dispid, VARIANT * pvarResult) 
Gets the value of a given property on a given IDispatch object. Used to help call IDispatch::Invoke.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/DISPHELP.CPP
Return Value
Returns the same HRESULT as IDispatch::Invoke.
Parameters
pdisp
The interface to call IDispatch::Invoke on.
dispid
The ID of the property.  See IDispatch::Invoke for more information.
pvarResult
Where to store the return value from the method or property-get call.  It is the caller's responsibility to call VariantClear(pvarResult) on exit (but the caller doesn't have to call VariantInit(pvarResult) on entry).
Comments
Properties with parameters are not supported -- use DispatchInvoke instead.

DispatchPropertyPut
HRESULT DispatchPropertyPut(IDispatch * pdisp, DISPID dispid, VARTYPE vt, (varying) value) 
Sets the value of a given property on a given IDispatch object. Used to help call IDispatch::Invoke.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/DISPHELP.CPP
Return Value
Returns the same HRESULT as IDispatch::Invoke.
Parameters
pdisp
The interface to call IDispatch::Invoke on.
dispid
The ID of the property.  See IDispatch::Invoke for more information.
vt
The type of the value parameter.  The valid values for vt are the same as the VT_ values documented in DispatchInvoke.
value
The new property value.
Comments
Properties with parameters are not supported -- use DispatchInvoke instead.

DrawControlBorder
HRESULT DrawControlBorder(HDC hdc, RECT * prc, POINT * ppt, POINT * pptNew, int * piHit, DWORD dwFlags) 
Draws a border used to drag and resize controls.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/BORDER.CPP
Parameters
hdc
Device context to draw into.  If hdc is NULL then no drawing is performed.
prc
Where to draw border.  The border is drawn outside this border.  If both ppt and pptNew are non-NULL, then on exit *prc is modified to contain the border rectangle obtained after the mouse is dragged from ppt to pptNew.
ppt
Mouse position.  See prc and piHit.
pptNew
New mouse position.  See prc and piHit. Note that if pptNew specifies an invalid mouse move (e.g. it would cause the right side of *prc to be dragged to the left of the left side of *prc) then *pptNew is adjusted so that it is valid.
piHit
If pptNew is NULL, then on exit *piHit contains a "hit test code" that indicates which part of the contro border was hit by *ppt.  If pptNew is not NULL, then on entry *piHit must contain a hit test code (usually returned from a previous call to DrawControlBorder) indicating which part of the control border the user wants to drag.  The hit test codes are as follows:
DCB_HIT_NONE
No part of the border was hit.
DCB_HIT_EDGE
The edge of the border was hit, but no grab handle was hit.
DCB_HIT_GRAB(i, j)
Grab handle (i, j) was hit, where i is the horizontal position of the grab handle (0=left, 1=middle, 2=right) and j is the vertical position of the handle (0=top, 1=middle, 2=bottom).  See Comments below for more information about how to interpret *piHit.
dwFlags
May contain the following flags:
DCB_CORNERHANDLES
Draw resize grab handles at the corners of the border rectangle.
DCB_SIDEHANDLES
Draw resize grab handles at the sides of the border rectangle.
DCB_EDGE
Draw the edge of the border rectangle of the border rectangle.
DCB_XORED
Draw the border with an exclusive-or brush.
DCB_INFLATE
On exit, inflate *prc enough so that it encloses the control border.
Comments
You can test if *piHit refers to a specific category of grab handle by computing the value (1 << *piHit) and peforming a bitwise and (&) with any of the following bit masks:
DCB_CORNERHANDLES
*piHit refers to a corner grab handle.
DCB_SIDEHANDLES
*piHit refers to a side grab handle.
DCB_SIZENS
*piHit refers to a vertical (north-south resize grab handle (on the left or right sides).
DCB_SIZEWE
*piHit refers to a horizontal (west-east) resize grab handle (on the left or right sides).
DCB_SIZENESW
*piHit refers to a resize grab handle at the north-east or south-west corner.
DCB_SIZENWSE
*piHit refers to a resize grab handle at the north-west or south-east corner.
Example
The following example shows how to use DrawControlBorder to draw a border around a control (which is at position g_rcControl in the client area of a window) and allow the control to be moved and resized.
// globals
HINSTANCE       g_hinst;     // application instance handle
RECT            g_rcControl;// location of simulated control
RECT            g_rcGhost;  // location of ghost (XOR) image of border
POINT           g_ptPrev;   // previous mouse location
int             g_iDrag;    // which part of control border is dragged

// window procedure of the window that contains the control
LRESULT CALLBACK AppWndProc(HWND hwnd, UINT uiMsg, WPARAM wParam,
	LPARAM lParam)
{
	PAINTSTRUCT     ps;
	int             iHit;
	HDC             hdc;
	POINT           ptCursor;
	RECT            rc;
	LPCTSTR         sz;

	switch (uiMsg)
	{

	case WM_PAINT:

		hdc = BeginPaint(hwnd, &ps);

		// draw the control
		...

		// draw the control border outside <g_rcControl>
		DrawControlBorder(hdc, &g_rcControl, NULL, NULL, NULL,
			DCB_EDGE | DCB_CORNERHANDLES | DCB_SIDEHANDLES);

		EndPaint(hwnd, &ps);
		return 0;

	case WM_SETCURSOR:

		// set <ptCursor> to the mouse position
		GetCursorPos(&ptCursor);
		ScreenToClient(hwnd, &ptCursor);

		// set <iHit> to a hit code which indicates which part of the
		// control border (if any) <ptCursor> is over
		DrawControlBorder(NULL, &g_rcControl, &ptCursor, NULL, &iHit,
				DCB_EDGE | DCB_CORNERHANDLES | DCB_SIDEHANDLES);

		// set the cursor based on <iHit>
		if ((1 << iHit) & DCB_SIZENS)
			sz = IDC_SIZENS;
		else
		if ((1 << iHit) & DCB_SIZEWE)
			sz = IDC_SIZEWE;
		else
		if ((1 << iHit) & DCB_SIZENESW)
			sz = IDC_SIZENESW;
		else
		if ((1 << iHit) & DCB_SIZENWSE)
			sz = IDC_SIZENWSE;
		else
			sz = IDC_ARROW;
		SetCursor(LoadCursor(NULL, sz));
		return TRUE;

	case WM_LBUTTONDOWN:

		// set <ptCursor> to the mouse position
		ptCursor.x = (short) LOWORD(lParam);
		ptCursor.y = (short) HIWORD(lParam);

		// do nothing if <ptCursor> is not within the control border
		if (DrawControlBorder(NULL, &g_rcControl,
				&ptCursor, NULL, &g_iDrag,
				DCB_EDGE | DCB_CORNERHANDLES | DCB_SIDEHANDLES) != S_OK)
			break;

		// capture the mouse
		SetCapture(hwnd);

		// set the initial position of the border "ghost" (the XOR image
		// of the border) to be the current position of the control
		g_rcGhost = g_rcControl;

		// draw the control border XOR'd
		hdc = GetDC(hwnd);
		DrawControlBorder(hdc, &g_rcGhost, NULL, NULL, NULL,
			DCB_EDGE | DCB_CORNERHANDLES | DCB_SIDEHANDLES | DCB_XORED);
		ReleaseDC(hwnd, hdc);

		// remember the current cursor position
		g_ptPrev = ptCursor;
		break;

	case WM_MOUSEMOVE:

		// do nothing if we're not dragging
		if (GetCapture() != hwnd)
			break;

		// set <ptCursor> to the mouse position
		ptCursor.x = (short) LOWORD(lParam);
		ptCursor.y = (short) HIWORD(lParam);

		// move the control XOR image
		hdc = GetDC(hwnd);
		DrawControlBorder(hdc, &g_rcGhost,
			&g_ptPrev, &ptCursor, &g_iDrag,
			DCB_EDGE | DCB_CORNERHANDLES | DCB_SIDEHANDLES | DCB_XORED);
		ReleaseDC(hwnd, hdc);

		// remember the current cursor position
		g_ptPrev = ptCursor;
		break;

	case WM_LBUTTONUP:

		// do nothing if we're not dragging
		if (GetCapture() != hwnd)
			break;

		// erase the control border XOR image
		hdc = GetDC(hwnd);
		DrawControlBorder(hdc, &g_rcGhost, NULL, NULL, NULL,
			DCB_EDGE | DCB_CORNERHANDLES | DCB_SIDEHANDLES | DCB_XORED);
		ReleaseDC(hwnd, hdc);

		// stop dragging
		ReleaseCapture();

		// move the control to the new location
		rc = g_rcControl;
		DrawControlBorder(NULL, &rc, NULL, NULL, NULL,
			DCB_EDGE | DCB_CORNERHANDLES | DCB_SIDEHANDLES |
			DCB_INFLATE);
		InvalidateRect(hwnd, &rc, TRUE);
		g_rcControl = g_rcGhost;
		rc = g_rcControl;
		DrawControlBorder(NULL, &rc, NULL, NULL, NULL,
			DCB_EDGE | DCB_CORNERHANDLES | DCB_SIDEHANDLES |
			DCB_INFLATE);
		InvalidateRect(hwnd, &rc, TRUE);
		break;

	...

	}

	return DefWindowProc(hwnd, uiMsg, wParam, lParam);
}

Return Codes
S_OK	Success.	
S_FALSE	Success.  Also indicates that *ppt does not fall within any portion of the control border.	

FindCharInString
char * FindCharInString(const char * sz, char chFind) 
Search a string to find a specific character.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/FINDSTR.CPP
Return Value
Returns a pointer to the first occurence of chFind in sz.  Returns NULL if chFind was not found.
Parameters
sz
String to search.
chFind
Character to find.  May be '\0' to search for the end of the string.
Comments
The search is case-sensitive.

FindCharInStringRev
char * FindCharInStringRev(const char * sz, char chFind) 
Search a string to find the last occurrence of a specific character.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/FINDSTR.CPP
Return Value
Returns a pointer to the last occurence of chFind in sz.  Returns NULL if chFind was not found.
Parameters
sz
String to search.  If NULL, the function returns NULL.
chFind
Character to find.  May be '\0' to search for the end of the string.
Comments
The search is case-sensitive.

FindStringByIndex
const char * FindStringByIndex(const char * szList, int iString) 
Find a string with a given index in a list of strings.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/FINDSTR.CPP
Return Value
Returns a pointer to string number iString in szList if found, or NULL if not found.  Note that the returned string is terminated by a newline character, not a null character -- user ppch to copy the string (see the example below).
Parameters
szList
The list of strings to look up iString in. szList consists of the concatenation of each string, where each string is terminated by a newline character (e.g. "Foo\nBar\n").
iString
The index of the string to find.  The first string in szList has index 0; the second 1, and so on.
Example
The following code stores "Bar" in ach.
int cch;
char ach[100];
char *sz = FindStringByIndex("Foo\nBar\n", 1, &cch);
if (sz != NULL)
	lstrcpyn(ach, sz, cch + 1);

FindStringByValue
int FindStringByValue(const char * szList, const char * szFind) 
Look up string in a list of strings and return the index of the string (if found).
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/FINDSTR.CPP
Return Value
Returns the index of szFind if szFind is found in szList.  The first string in szList has index 0; the second 1, and so on.  Returns -1 if szFind is not found.
Parameters
szList
The list of strings to look up szFind in. szList consists of the concatenation of each string in the list, where each string is terminated by a newline character (e.g. "Foo\nBar\n").
szFind
The string to look up.
Comments
The search is case-insensitive.
Example
The following line of code sets iString to12.
iString = FindStringByValue("Foo\\nBar\\n", "bar");

FindStringInString
LPCSTR FindStringInString(LPCSTR szToSearch, LPCSTR szToFind, DWORD dwFlags) 
Finds a string within another string.  The comparison can be either case-sensitive or case-insensitive.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/FSIS.CPP
Return Value
Returns a pointer to the substring within szToSearch that equals szToFind.  Returns NULL if szToFind is not found in szToSearch.
Parameters
szToSearch
The string to search.
szToFind
The string to search for.
dwFlags
May contain the following flags:
FSIS_IGNORECASE
The search is case-insensitive.  If this flag is not specified, the search is case-sensitive.

FreeConnectionPointHelper
HRESULT FreeConnectionPointHelper(void) 
Frees a ConnectionPointHelper object allocated using AllocConnectionPointHelper.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/CONNECT.CPP
Comments
See AllocConnectionPointHelper for information about why you should not try to free the ConnectionPointHelper object using Release.
Return Codes
S_OK	Success.	

GetHalftonePalette
HPALETTE GetHalftonePalette(DWORD dwFlags) 
Return a halftone palette by calling CreateHalftonePalette in the way appropriate for the current color depth and operating system.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/GHP.CPP
Parameters
dwFlags
Currently unused.  Must be set to 0.

GetIthMRUListEntry
HRESULT GetIthMRUListEntry(HMRULIST hMRUList, int iEntry, TCHAR* szEntry, int* pcchEntryLen) 
Retrieves the i-th entry in an MRU list.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/MRU.CPP
Parameters
hMRUList
[in] A handle to a previously opened MRU list.
iEntry
[in] The 0-based index of the desired entry.
szEntry
[out] If successful, set to the first pcchEntryLen characters of the next entry.  Cannot be NULL.
pcchEntryLen
[in/out] On entry, the number of characters of the next entry to copy into szEntry.  On exit, the actual number of characters copied.  Cannot be NULL and cannot reference a number less than 1.
Return Codes
S_OK	Success.	
(other)	Failure. ---------------------------------------------------------------------------	

GetMRUListInfo
HRESULT GetMRUListInfo(HMRULIST hMRUList, int* pcEntries, int* pcchMaxEntryLen, int* pcMaxEntries) 
Gets information about an MRU list such as the number of entries in the list, the length of the longest entry, and the maximum number of entries.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/MRU.CPP
Parameters
hMRUList
[in] A handle to a previously opened MRU list.
pcEntries
[out] If non-NULL on entry, set to the number of entries in the MRU list.
pcchMaxEntryLen
[out] If non-NULL on entry, set to the length (in characters) of the longest entry in the MRU list.
pcMaxEntries
[out] If non-NULL on entry, set to the maximum number of entries allowed in the list.
Return Codes
S_OK	Success.	
(other)	Failure. ---------------------------------------------------------------------------	

GetNextMRUListEntry
HRESULT GetNextMRUListEntry(HMRULIST hMRUList, TCHAR* szEntry, int* pcchEntryLen) 
Retrieves the next entry in an MRU list.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/MRU.CPP
Parameters
hMRUList
[in] A handle to a previously opened MRU list.
szEntry
[out] If successful, set to the first pcchEntryLen characters of the next entry.  Can't be NULL.
pcchEntryLen
[in/out] On entry, the number of characters of the next entry to copy into szEntry.  On exit, the actual number of characters copied.  Can't be NULL and can't reference a number less than 1.
Comments
Each time GetNextMRUListEntry is called, it retrieves the next entry and then advance the current entry pointer. Call Reset to move the current entry pointer to the first entry. ---------------------------------------------------------------------------
Return Codes
S_OK	Success.	
(other)	Failure.  A failure may indicate that there are no more entries.  Call AtEndOfMRUList to test for this.	

GetObjectSafety
HRESULT GetObjectSafety(BOOL* pfSafeForScripting, BOOL* pfSafeForInitializing, IUnknown* punk, CLSID* pclsid, IID* (interfaces)) 
Determines if an object is safe-for-scripting and/or safe-for-initializing vis-a-vis a given set of interfaces.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/OBJSAFE.CPP
Parameters
pfSafeForScripting
[out] If non-NULL, set to TRUE if the object is safe-for-scripting.
pfSafeForInitializing
[out] If non-NULL, set to TRUE if the object is safe-for-initializing
punk
[in] The object's IUnknown interface.  If non-NULL, an attempt will be made to assess the object's safety via its IObjectSafety interface.  If NULL, or the the object doesn't support this interface, its safety will be assessed using pclsid and the system registry.
pclsid
[in] The object's class ID.  If punk is NULL or the object doesn't support IObjectSafety, then pclsid will be used to look up the object's safety in the system registry (as long as pclsid is also non-NULL).
(interfaces)
[in] A variable number of interfaces pointers, the last of which must be NULL.  If the object's safety is assessed via IObjectSafety (see punk) then it's safety is assessed vis-a-vis this set of interfaces.  These interfaces are not used if the object's safety is examined via the system registry.
Comments
If your code uses OCMisc (i.e., #includes ocmisc.h), it should also [#include <objsafe.h>] whereever it #includes <initguid.h>.  This will cause IID_IObjectSafety to be defined.
Example
The following example shows how to test whether an object is safe-for-scripting and safe-for-initializing by checking the system registry only:
BOOL fSafeForScripting;
BOOL fSafeForInitializing;
GetObjectSafety(&fSafeForScripting, &fSafeForInitializing,
	NULL, &CLSID_MyObject, NULL);

The following example shows how to test whether an object is safe-for-scripting via IDispatch using the object's IObjectSafety interface:
BOOL fSafeForScripting;
GetObjectSafety(&fSafeForScripting, NULL, punk, NULL,
	&IID_IDispatch, NULL);

The following example shows how to test whether an object is safe-for-initialzing via IPersistStream, IPersistStreamInit, or IPersistPropertyBag using the object's IObjectSafety interface or, if IObjectSafety is not supported, the registry:
BOOL fSafeForInitializing;
GetObjectSafety(NULL, &safeForInitializing, punk, &CLSID_MyObject,
	&IID_IPersistStream, &IID_IPersistStreamInit,
	&IID_IPersistPropertyBag, NULL);

Return Codes
S_OK	Success.  The object's safety was assessible and *pfSafeForScripting and/or *pfSafeForInitializing have been set accordingly.	
E_FAIL	Failure.  The object's safety couldn't be assessed.  The values of *pfSafeForScripting and *pfSafeForInitializing are indeterminate.	

GetStreamLengthToEnd
HRESULT GetStreamLengthToEnd(IStream * pstream, ULONG * pcb) 
Calculates the distance (in bytes) between the current position in a stream and the end of the stream.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/GSLTE.CPP
Parameters
pstream
The stream to use.
pcb
Where to store the number of bytes left to read in pstream.
Return Codes
S_OK	Success.	
E_FAIL	The distance between the current position in pstream and the end of pstream exceeds the capacity of a ULONG.  Or, an I/O error occurred.	

HelpDelete
void HelpDelete(void * pv) 
Frees memory allocated by HelpNew.  This is simply a macro that calls HelpMemFree with specific flags.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/HELPMEM.CPP
Parameters
pv
The pointer to the memory to free.
Comments
See HelpNew for more information.

HelpGetAdvise
HRESULT HelpGetAdvise(DWORD * pdwAspects, DWORD * pdwAdvf, IAdviseSink * * ppAdvSink, HelpAdviseInfo * pha) 
Helps implement IViewObject::GetAdvise.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/ADVISE.CPP
Parameters
pdwAspects
See IViewObject::GetAdvise.
pdwAdvf
See IViewObject::GetAdvise.
ppAdvSink
See IViewObject::GetAdvise.
pha
Caller-allocated structure that was previously initialized using InitHelpAdvise.
Comments
You must call InitHelpAdvise before calling HelpGetAdvise and HelpGetAdvise, and UninitHelpAdvise when the object that contains the HelpAdviseInfo structure is deleted.
This function fills in *pdwAspects, *pdwAdvf, and *ppAdvSink with information from pha.
Example
The following example shows how to use HelpGetAdvise to help implement IViewObject::GetAdvise, assuming m_advise is a member variable of type HelpAdviseInfo.
STDMETHODIMP CMyControl::GetAdvise(DWORD *pdwAspects, DWORD *pdwAdvf,
	IAdviseSink **ppAdvSink)
{
	return HelpGetAdvise(pdwAspects, pdwAdvf, ppAdvSink, &m_advise);
}

HelpGetClassInfo
HRESULT HelpGetClassInfo(LPTYPEINFO * ppti, REFCLSID rclsid, char * szEventList, DWORD dwFlags) 
Helps implement IProvideClassInfo::GetClassInfo.  The implementation provides very limited class information -- just enough to allow firing events to VBS.  Warning: you should probably use HelpGetClassInfoFromTypeLib instead.  See comments for more information.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/HGCI.CPP
Parameters
ppti
Where to return the pointer to the newly-allocated ITypeInfo interface.  NULL is stored in *ppti on error.
rclsid
The class ID of the object that is implementing IProvideClassInfo.
szEventList
A list of events that can be fired by the parent object that is implementing IProvideClassInfo.  The event names are concatenated, and each event name is terminated by a newline character.  The first member name is assigned DISPID value 0, the second 1, and so on.  For example, if szEventList is "\nFoo\nBar\n", then "Foo" is assigned DISPID value 1 and "Bar" is assigned 2 (because the first element is "").  (These DISPID values are passed to functions such as IConnectionPointHelper::FireEvent to invoke events on objects such as VBS scripts connected to the parent object.)
dwFlags
Currently unused.  Must be set to 0.
Comments
WARNING HelpGetClassInfo makes assumptions about the script engine calling it.  Currently, this works with VBS, but the VBS group will not guarantee that the assumptions made by HelpGetClassInfo will remain valid in the future, so use at your own risk!  Consider using HelpGetClassInfoFromTypeLib instead.
Example
In the following example, CMyControl is a class that implements (among other things) IConnectionPointContainer and IProvideClassInfo.  The first part of this example shows how IProvideClassInfo::GetClassInfo is implemented by CMyControl. The second part of the example shows how an event is fired, assuming m_pconpt is a IConnectionPointHelper object. (It's not required that you use ConnectionPointHelper, but it's helpful.)
// IDispatch IDs for events fired by this object, and the
// corresponding method/property names (the order MUST MATCH)
#define DISPID_EVENT_FOO        1
#define DISPID_EVENT_BAR        2
#define EVENT_NAMES "\n" \
					"Foo\n" \
					"Bar\n"

STDMETHODIMP CMyControl::GetClassInfo(LPTYPEINFO FAR* ppTI)
{
	return HelpGetClassInfo(ppTI, CLSID_CMyControl, EVENT_NAMES, 0);
}

// fire the "Bar" event (which has 3 parameters, which in BASIC
// are of these types: Integer, String, Boolean)
m_pconpt->FireEvent(DISPID_EVENT_BAR, VT_INT, 300 + i,
	VT_LPSTR, ach, VT_BOOL, TRUE, 0);

HelpGetClassInfoFromTypeLib
HRESULT HelpGetClassInfoFromTypeLib(LPTYPEINFO * ppti, REFCLSID rclsid, ITypeLib * plib, HINSTANCE hinst, DWORD dwFlags) 
Helps implement IProvideClassInfo::GetClassInfo using a caller-provided type library.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/TYPELIB.CPP
Parameters
ppti
Where to return the pointer to the newly-allocated ITypeInfo interface.  NULL is stored in *ppti on error.
rclsid
The class ID of the object that is implementing IProvideClassInfo.
plib
The type library containing events.  Should be NULL if plib is non-NULL.
hinst
The DLL instance containing a type library resource.  Should be NULL if plib is non-NULL.
dwFlags
Currently unused.  Must be set to 0.
Comments
This function accesses type information in the type library specified by either plib (if the type library is already loaded) or hinst (in which case this function loads the type library).
It is assumed that the type library contains a "coclass" typeinfo and a an outgoing (source) "dispinterface" typeinfo.  The class ID of the "coclass" typeinfo should be rclsid.
Example
In the following example, CMyControl is a class that implements (among other things) IConnectionPointContainer and IProvideClassInfo.  The first part of this example shows how IProvideClassInfo::GetClassInfo is implemented by CMyControl. The second part of the example shows how an event is fired, assuming m_pconpt is a IConnectionPointHelper object. (It's not required that you use ConnectionPointHelper, but it's helpful.)
// in MyControl.h...

// IDispatch IDs for events fired by this object
#define DISPID_EVENT_BAR        1
#define DISPID_EVENT_LOAD       2

// class ID
#define _CLSID_CMyControl 3CE08A80-9440-11CF-B705-00AA00BF27FD
#ifndef __MKTYPLIB__
DEFINE_GUID(CLSID_CMyControl, 0x3CE08A80L, 0x9440, 0x11CF,
	0xB7, 0x05, 0x00, 0xAA, 0x00, 0xBF, 0x27, 0xFD);
#endif

// dispinterface ID for event set
#define _DIID_DMyControlEvents 296CC160-9F5A-11CF-B705-00AA00BF27FD
#ifndef __MKTYPLIB__
DEFINE_GUID(DIID_DMyControlEvents, 0x296CC160L, 0x9F5A, 0x11CF,
	0xB7, 0x05, 0x00, 0xAA, 0x00, 0xBF, 0x27, 0xFD);
#endif

// in the .odl  file...

#include <olectl.h>
#includ  "MyControl.h"

[ uuid(B1179240-9445-11CF-B705-00AA00BF27FD), version(1.0), control ]
library MyControlLib
{
	importlib(STDOLE_TLB);
	importlib(STDTYPE_TLB);

	// event dispatch interface for CMyControl
	[ uuid(_DIID_DMyControlEvents) ]
	dispinterface _DMyControlEvents
	{
		properties:
		methods:
			[id(DISPID_EVENT_BAR)] void Bar(long i, BSTR sz, boolean f);
			[id(DISPID_EVENT_LOAD)] void Load();
	};

	// class information for CMyControl
	[ uuid(_CLSID_CMyControl), control ]
	coclass MyControl
	{
		[default, source] dispinterface _DMyControlEvents;
	};
};

// in some .cpp file...

STDMETHODIMP CMyControl::GetClassInfo(LPTYPEINFO FAR* ppTI)
{
	return HelpGetClassInfoFromTypeLib(ppTI, CLSID_CMyControl, NULL,
		g_hinst, 0);
}

// in some .cpp file...

// fire the "Bar" event (which has 3 parameters, which in BASIC
// are of these types: Integer, String, Boolean)
m_pconpt->FireEvent(DISPID_EVENT_BAR, VT_INT, 300 + i,
	VT_LPSTR, ach, VT_BOOL, TRUE, 0);

HelpGetClassObject
HRESULT HelpGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID * ppv, ControlInfo * pci) 
Helps implement DllGetClassObject (including the class factory object it creates) for any number of controls.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/FACTORY.CPP
Parameters
rclsid
See DllGetClassObject.
riid
See DllGetClassObject.
ppv
See DllGetClassObject.
pci
Information about the control that's implemented by the DLL.  See ControlInfo for more information.
Comments
HelpGetClassObject can support one control by making a linked list out of your ControlInfo structures -- set each pNext field to the next structure, and set the last pNext to NULL.
Example
The following example shows how to implement DllGetClassObject using HelpGetClassObject.
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
	return HelpGetClassObject(rclsid, riid, ppv, &g_ctlinfo);
}

HelpMemAlloc
LPVOID HelpMemAlloc(DWORD dwFlags, ULONG cb) 
Allocates memory using either GlobalAlloc or the task memory allocator retrieved using CoGetMalloc.  Optionally zero-initializes the memory.  Optionally performs simple memory leak detection.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/HELPMEM.CPP
Return Value
Returns a pointer to the allocated block of memory.  Returns NULL on error.
Parameters
dwFlags
May contain the following flags:
HM_TASKMEM
The memory is allocated using IMalloc::Alloc (using the task memory allocator retrieved from CoGetMalloc).  If HM_TASKMEM is not specified, then GlobalAlloc is used to allocate the memory.
HM_ZEROINIT
The memory is zero-initialized.
HM_LEAKDETECT
This DLL will keep track of the allocated memory block using a simple leak detection mechanism. Important: If HM_LEAKDETECT is specified, then the returned memory pointer cannot be freed directly by GlobalFree or IMalloc::Free -- it must be freed using HelpMemFree.
cb
The number of bytes of memory to allocate.
Comments
This function allocates a block of cb bytes of memory, using the allocation function (and optional zero-initialization) specified by dwFlags.
If HM_LEAKDETECT is specified, then an extra few bytes is allocated to keep track of leak detection information, and the returned pointer actually points several bytes beyond the beginning of the memory block. Therefore, HelpMemFree must be called to free the block of memory.
If HM_LEAKDETECT is not specified, then GlobalFree or IMalloc::Free (depending on dwFlags) can be called directly to free the block of memory.  (HelpMemFree may also be used to free the memory block).
If HelpMemFree is called, the HM_TASKMEM and HM_LEAKDETECT flags (if any) specified for HelpMemAlloc must also be passed to HelpMemFree.
Leak detection occurs automatically when this DLL unloads: if an unfreed block is detected, a message box (in the debug build) or an OutputDebugString message (in the release build) is displayed.

HelpMemFree
void HelpMemFree(DWORD dwFlags, LPVOID pv) 
Frees a block of memory previously allocated using HelpMemAlloc.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/HELPMEM.CPP
Parameters
dwFlags
May contain the following flags:
HM_TASKMEM
The memory was allocated using IMalloc::Alloc (using the task memory allocator retrieved from CoGetMalloc).  If HM_TASKMEM is not specified, then it is assumed that GlobalAlloc is used to allocate the memory.
HM_LEAKDETECT
The memory was allocated using HelpMemAlloc with the HM_LEAKDETECT flag specified.
pv
A pointer to the block of memory that was previously allocated using HelpMemAlloc or a NULL pointer.
Comments
The HM_TASKMEM and HM_LEAKDETECT flags (if any) specified for HelpMemAlloc must also be passed to HelpMemFree.

HelpMemSetFailureMode
void HelpMemSetFailureMode(LONG lParam, DWORD dwFlags) 
Sets failure conditions for the memory allocator.  This can be used to simulate low-memory conditions and test a system's ability to detect and/or handle these conditions.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/HELPMEM.CPP
Parameters
lParam
Argument used in conjunction with dwFlags.
dwFlags
May contain the following flags (all of which are mutually exclusive):
HM_FAILNEVER
Never fail memory allocation unless memory is truly exhausted. ulParam is ignored.  This is the default failure mode for the memory allocator.
HM_FAILAFTER
Begin failing memory allocation after ulParam allocations have been attempted.  If, for example, ulParam is 100, the next 100 calls to HelpMemAlloc will succeed (memory availability permitting), but the 101-st, 102-nd, etc. calls will fail.
HM_FAILUNTIL
Start failing memory allocation immediately and continue until ulParam allocations have been attempted.  If, for example, ulParam is 100, the next 100 calls to HelpMemAlloc will fail, but the 101-st, 102-nd, etc. calls will succeed (memory availability permitting).
HM_FAILEVERY
Fail every ulParam-th attempted memory allocation.  If, for example, ulParam is 3, every third call to HelpMemAlloc will fail.
HM_FAILRANDOMLY
Simulate random memory allocation failure.  (ulParam mod 100) indicates the percentage chance that a given call to HelpMemAlloc will fail.  (Note: This flag currently has the same effect as HM_FAILNEVER.)
Comments
This function is only available in DEBUG builds of OCHelp.  (There is a stub implementation that does nothing in the release builds.) Also, this function resets the allocation counter.  So, ulParam is counted relative to the last call to this function.

HelpNew
void * HelpNew(size_t cb) 
Helps implement a version of the "new" operator that doesn't use the C runtime.  Zero-initializes the allocated memory. This is simply a macro that calls HelpMemAlloc with specific flags.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/HELPMEM.CPP
Return Value
Returns a pointer to the allocated block of memory.  Returns NULL on error.
Parameters
cb
The number of bytes to allocate.
Example
The following example shows how to use HelpNew and HelpDelete to define default "new" and "delete" operators.
void * operator new(size_t cb)
{
	return HelpNew(cb);
}

void operator delete(void *pv)
{
	HelpDelete(pv);
}

HelpQueryHitPoint
HRESULT HelpQueryHitPoint(IViewObject * pvo, DWORD dwAspect, LPCRECT prcBounds, POINT ptLoc, LONG lCloseHint, DWORD * pHitResult) 
Helps implement IViewObjectEx::QueryHitPoint on a control by drawing the control into a small bitmap (centered on the point being hit-tested) and checking if any pixels were drawn.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/QUERYHIT.CPP
Parameters
pvo
The IViewObject interface on the control being hit-tested.
dwAspect
See IViewObjectEx::QueryHitPoint.
prcBounds
See IViewObjectEx::QueryHitPoint.
ptLoc
See IViewObjectEx::QueryHitPoint.
lCloseHint
See IViewObjectEx::QueryHitPoint.
pHitResult
See IViewObjectEx::QueryHitPoint.
Comments
This function helps implement IViewObjectEx::QueryHitPoint for the object pvo, by drawing pvo into a small monochrome bitmap centered on ptLoc pHitResult is set to HITRESULT_HIT if ptLoc is directly over a non-transparent pixel of pvo; HITRESULT_CLOSE if ptLoc is within lCloseHint himetric units of a non-transparent pixel of pvo; HITRESULT_OUTSIDE otherwise.
In order for this function to work, pvo must implement DVASPECT_MASK (as the first parameter to IViewObject::Draw), which is defined to be the same as DVASPECT_CONTENT except that non-transparent parts of the object are drawn black, and transparent parts are either left untouched or drawn in white.

HelpSetAdvise
HRESULT HelpSetAdvise(DWORD dwAspects, DWORD dwAdvf, IAdviseSink * pAdvSink, HelpAdviseInfo * pha) 
Helps implement IViewObject::SetAdvise.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/ADVISE.CPP
Parameters
dwAspects
See IViewObject::SetAdvise.
dwAdvf
See IViewObject::SetAdvise.
pAdvSink
See IViewObject::SetAdvise.
pha
Caller-allocated structure that was previously initialized using InitHelpAdvise.
Comments
You must call InitHelpAdvise before calling HelpSetAdvise and HelpGetAdvise, and UninitHelpAdvise when the object that contains the HelpAdviseInfo structure is deleted.
This function updates *pha with information given by the parameters dwAspects, dwAdvf, and pAdvSink.  In particular, the IAdviseSink pointer is stored in pha->pAdvSink, and you can use this pointer (when non-NULL) to advise the view site object of changes in your object's view (e.g. by calling pha->pAdvSink->OnViewChange()).
Example
The following example shows how to use HelpSetAdvise to help implement IViewObject::SetAdvise, assuming m_advise is a member variable of type HelpAdviseInfo.
STDMETHODIMP CMyControl::SetAdvise(DWORD dwAspects, DWORD dwAdvf,
	IAdviseSink *pAdvSink)
{
	return HelpSetAdvise(dwAspects, dwAdvf, pAdvSink, &m_advise);
}

HIMETRICToPixels
void HIMETRICToPixels(int cx, int cy, SIZE * psize) 
Converts a width and height from HIMETRIC units to pixels (on the default monitor).
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/HIMETRIC.CPP
Parameters
cx
The input width in HIMETRIC units.
cy
The input height in HIMETRIC units.
psize
The output size in pixels.

HostLW Object
Description
A lightweight windowed ActiveX control which can embed a lightweight windowless ActiveX control.  Can be used to allow IE3 to host windowless controls.
Defined in: C:/DEV/MMCTL21/AUTODOC/HOSTLW.D
Properties
Long HostLW::TickInterval
The number of milliseconds between ticks.  The frame rate (ticks per second) is approximately 1000 / TickInterval.
Methods
 HostLW::ToggleAnimation
Starts the animation running if it is currently stopped, or stops the animation if it is currently running.  Don't confuse this with the Play/Stop feature in OCTest, which affects OCTest's internal animation timer and not HostLW's animation timer.
 HostLW::RefreshBackground
Causes the container's background image (e.g. the tiled bitmap in IE) to be "re-captured" by HostLW, so that the background of HostLW appears to be "transparent" (i.e.  you can see through to the container). Normally, if the Capture Background checkbox is set (see below), RefreshBackground is called automatically whenever the container's background changes.
 HostLW::SetMemoryFailureMode
Available only in the debugging version of HostLW.  This is a debugging function which will simulate an out-of-memory condition (i.e. HelpMemAlloc and functions which call it will fail) under specified circumstances.
Comments
For all users:
—	The easiest way to construct an HTML page that uses HostLW to embed a windowless control is to run OCTest, use File New to create a new instance of HostLW, and then right-click in HostLW and embed a new instance of the desired windowless control.  Then, use OCTest's File Save As to save the HostLW control's data (and the embedded windowless control's data) to an HTML file.  You can then edit that HTML file using any HTML tools.
Later, you can open the HTML file in OCTest, edit the embedded windowles control, and save back to HTML -- the contents of the HTML file outside of the HostLW <object>...</object> construct will be untouched. (If you have more than one <object> tag in the HTML tag, you can specify the one you want OCTest to edit by naming the HostLW <object> tag in lowercase and all other <OBJECT> tags in uppercase -- only the word "object" itself needs to be made lowercase or uppercase.)
—	HostLW is still undergoing continuing development, both to improve compatibility with all important containers (e.g. Nashville, Forms3, etc.)
—	This control is packaged in both design-time and run-time versions. The design time version allows a control to be embedded via the right-click context menu.  (There is also a property page, which may or may not exist in the final version of HostLW.) The run-time version has no such authoring features, in order to reduce code size.
—	The class ID of the design-time version of this control is "861301A0-99FA-11CF-B705-00AA00BF27FD".
—	The class ID of the run-time version of this control is "TBD" (currently the same as the design-time version).
—	HostLW implements a property sheet (which can be accessed by File Properties in OCTest) with the following properties:
—	Stretch To Window (unchecked by default): If checked, the control loaded into HostLW is sized to occupy the entire size of the HostLW control.
—	Off-Screen Buffer (checked by default): If checked, then the control loaded into HostLW (if windowless) is drawn into an off-screen DIBSection bitmap buffer before being drawn.  This makes greatly reduces animation flicker, and some controls (e.g. Sprite) require this feature in order to operate correctly (since some controls cannot draw directly to the screen and must have an off-screen buffer to "compose" into).
—	Hatched Background (unchecked by default): If checked, and if Capture Background is unchecked, then the background behind the loaded control is a hatched pattern (mostly useful for debugging).  If unchecked, and if Capture Background is also unchecked, then the background is a solid color (currently always black).  If Capture Background is checked, then Hatched Background is ignored.
—	Always Show Border (unchecked by default): Causes the resize border (with grab handles) to be displayed around the control even when the control is not UI active (i.e. "selected"). This only affects the design-time version of HostLW, since the run-time version does not show a resize border.
—	No Custom Palette (checked by default): If checked, HostLW will not ask the container of HostLW to use the color palette of the loaded control, and instead HostLW will simply use whatever palette the container of HostLW uses (e.g. the halftone palette).
—	Capture Background (checked by default): If checked, then HostLW attempts to use whatever is behind the HostLW control (e.g. the tiled background bitmap in IE3) as the background for the loaded control.
—	Disable Double-Click Start/Stop (unchecked by default): If checked, then double-clicking the HostLW control will not toggle (i.e. start and stop) the animation.
—	Auto-Start (unchecked by default): If checked, then animation begins as soon as the HostLW control is loaded.
—	Save Compacted Properties (checked by default): If checked, then properties are saved in a compacted form.  For example, rather than storing Players(1).Width="17" and Players(1).Height="42" as two separate properties (in an HTML, CSV, or other file), Save Compacted Properties will cause a single property to be saved: Players(1)="Width=17,Height=42".  This makes files (particularly HTML files) smaller and improves load time.
—	Tick Interval: The number of milliseconds between frames. The frame rate (ticks per second) is approximately 1000 / Tick Interval.  Note: OCTest has its own fixed tick rate, which you get if you use OCTest's Play/Stop menu item; to avoid this, use HostLW::ToggleAnimation or DoubleClick or Alt+DoubleClick to start/stop animation instead of using Play/Stop in OCTest.
—	HostLW treats certain keyboard-mouse combinations specially:
—	Alt+Click advances animation by one frame.
—	Alt+DoubleClick toggles (i.e. starts and stops) the animation, unless the "Disble Double-Click Start/Stop" checkbox in the property sheet is checked (see above).
—	Alt+Ctrl+DoubleClick toggles the animation, regardless of the setting of the "Disble Double-Click Start/Stop" checkbox in the property sheet.
—	Alt+Shift+DoubleClick toggles (i.e. turns on/off) display of performance statistics during animation, as described under "Monitoring performance".
—	Monitoring performance: As described above, Alt+Shift+DoubleClick toggles (i.e. turns on/off) display of performance statistics during animation.  When turned on, the following information is displayed in the upper-left corner of the HostLW control.  When turned off, all statistics are reset to zero.
—	E.g. "76:": The current "frame number" since performance monitoring was last turned on.
—	E.g. "002+008ms": The amount of time (in milliseconds) required to process IAnimate::Tick and UpdateWindow (including compositing loop), respectively.  This time is the average over the last two frames.  Generally, the first number should be very small (e.g. no more than a few milliseconds, and certainly a small fraction of the second number).
—	E.g. "7x": The number of extra WM_PAINT messages, i.e. WM_PAINT messages that were not the result of IAnimate::Tick.  During animation, this number should remain constant -- if it increases over time a this may be an indication that the loaded control (or some control it contains) may be calling UpdateWindow which can significantly reduce performance.
—	E.g. "3s": The number of skipped ticks.  Although (by definition) frames are nevers skipped, it's possible that an animation timer tick may be skipped if a frame is taking too long to display.  Typically, ticks are skipped whenever the container is in a tight loop (e.g. while dragging the IE window) or if the frame rate is too fast for the computer.
—	E.g. "avg: 012ms": The average number of milliseconds required to process a frame (including both IAnimate::Tick and UpdateWindow).  This average is measured since the performance monitoring was turned on (i.e. since frame 0).
—	E.g. "10f/s": The average number of frames per second being displayed.  This average is measured since the performance monitoring was turned on (i.e. since frame 0).  Meaningless while single-stepping.
—	E.g. "012%": The average CPU saturation caused by frame display.  If there are no other threads running, this is the approximate percentage of CPU time consumed by HostLW. When this number reaches approximately 100%, the CPU is fully "saturated", meaning that the frame rate cannot be further increased.  At this point, HostLW will automatically slow the frame rate as needed.  Meaningless while single-stepping.
—	Event support: Since Stage cannot fire events originating from embedded controls via the normal IConnectionPoint mechanism, HostLW provides a hack workaround.  (Important: This workaround is temporary -- expect it to change!)  HostLW implements an event named "Event" which can be handled in VBS in the usual way.  The "Event" event has three parameters:
—	ctl (type Variant, containing an Object, i.e. a VT_DISPATCH value): the control (or x-object/site aggregated with the control) that caused the event;
—	evname (type Variant, containing a String, i.e. a VT_BSTR value): the name of the event (e.g. "Click");
—	args (type Variant, containing an Array of Variants, i.e. a VT_ARRAY | VT_BYVAL | VT_VARIANT): the arguments of the event.  The first argument is in element 1 of args, the second is in element 2, and so on.  args may in fact have elements with indices below 1, but the event function is required to ignore these.
VBS users: See HostLW\test.htm for an example of how to use the "Event" event.  Typically you'll get the Name property of the control that fired the event (via "ctl.Name") and then handle the event based on which control fired it.  But: beware that ctl may not have a Name property in all cases, so use "On Error Resume Next" before "ctl.Name".
C++ users: To cause HostLW to fire the "Event" event from within a control, you need to do the following.  See HostLW\control.cpp (search for SAFEARRAYBOUND) for an example.
—	Use SafeArrayCreate to create an array that contains N+2 elements of type VT_VARIANT, where N is the number of parameters of the event.  The lower bound of the array should be -1.
—	Set element -1 of the array to the IDispatch pointer of the control or site/x-object that caused the event -- don't forget to AddRef this pointer.  Set element 0 of the array to a VT_BSTR element containing the string name of the event (e.g. "Click").  Set slements 1...N of the array to the arguments of the event.
—	Get the HWND of HostLW, by calling IOleWindow::GetWindow on the site of your control.  (If the container is not HostLW, then the event will be harmlessly ignored.)  Use RegisterWindowMessage to get the message ID of the window message named "HostLWEvent".  Use SendMessage to send this message to the container window (hopefully the HostLW window); wParam of the message should be the SAFEARRAY pointer allocated above, and lParam should be zero.
—	Use SafeArrayDestroy to free the array.
For C++ users:
—	The class ID of this control is defined as CLSID_CHostLWOC in "HostLWOC.h".
—	The ProgID of this control is "HostLW.HostLW.1".
—	This control implements the following interfaces:
—	IUnknown: A delegating IUnknown that supports aggregation
—	IHostLWOC: Provides low-level efficient access to the properties of a HostLW control.  See that interface for more information.
—	IOleObject subset: Used to allow the container to provide the client site pointer, invoke control verbs, and get control state.  Only SetClientSite, Close, DoVerb, EnumVerbs (design time version only), and GetMiscStatus are implemented.
—	IOleInPlaceObject subset (based on IOleWindow): Used to change control state.  Only InPlaceDeactivate, UIDeactivate, and SetObjectRects, are implemented.
—	IOleControl subset: Used to inform the control of ambient property changes.  Only OnAmbientPropertyChange is implemented.
—	ISpecifyPropertyPages (only in the design-time version): Used to retrieve information about the control's property page.
—	IPersistStreamInit (based on IPersistStream): Used to persist the control's data to/from an IStream, including the data of the embedded control (if any). The file format is compatible with past and future versions of this control (i.e. adding and removing properties won't break the control).
—	IPersistPropertyBag: Used to persist the control's data to/from an IPropertyBag.
—	IDispatch:  Provides access to the control's properties. Does not provide type information.
—	This control sources (calls) the following interfaces (if available) on the container-provided site object:
—	IOleClientSite: The client site pointer provided by the container.
—	IDispatch: Used to access ambient properties (currently DISPID_AMBIENT_USERMODE).

HostLW::RefreshBackground Method
 RefreshBackground()
Causes the container's background image (e.g. the tiled bitmap in IE) to be "re-captured" by HostLW, so that the background of HostLW appears to be "transparent" (i.e.  you can see through to the container). Normally, if the Capture Background checkbox is set (see below), RefreshBackground is called automatically whenever the container's background changes.
Defined in: C:/DEV/MMCTL21/AUTODOC/HOSTLW.D

HostLW::SetMemoryFailureMode Method
 SetMemoryFailureMode(Long param, Long flags)
Available only in the debugging version of HostLW.  This is a debugging function which will simulate an out-of-memory condition (i.e. HelpMemAlloc and functions which call it will fail) under specified circumstances.
Defined in: C:/DEV/MMCTL21/AUTODOC/HOSTLW.D
Parameters
param
The meaning of this parameter depends on flags.
flags
May be one of the following values:
HM_FAILNEVER (value 1)
Never fail memory allocation unless memory is truly exhausted. param is ignored.  This is the default failure mode for the memory allocator.
HM_FAILAFTER (value 2)
Begin failing memory allocation after param allocations have been attempted.  If, for example, param is 100, the next 100 calls to HelpMemAlloc will succeed (memory availability permitting), but the 101-st, 102-nd, etc. calls will fail.
HM_FAILUNTIL (value 4)
Start failing memory allocation immediately and continue until param allocations have been attempted.  If, for example, param is 100, the next 100 calls to HelpMemAlloc will fail, but the 101-st, 102-nd, etc. calls will succeed (memory availability permitting).
HM_FAILEVERY (value 8)
Fail every param-th attempted memory allocation.  If, for example, param is 3, every third call to HelpMemAlloc will fail.

HostLW::TickInterval Property
Data Type
Long
Description
The number of milliseconds between ticks.  The frame rate (ticks per second) is approximately 1000 / TickInterval.
Defined in: C:/DEV/MMCTL21/AUTODOC/HOSTLW.D
Example
The following VBS code sets the frame rate to approximately 24 frames per second (assuming host is a HostLW object).
host.TickInterval = 1000 / 24

HostLW::ToggleAnimation Method
 ToggleAnimation()
Starts the animation running if it is currently stopped, or stops the animation if it is currently running.  Don't confuse this with the Play/Stop feature in OCTest, which affects OCTest's internal animation timer and not HostLW's animation timer.
Defined in: C:/DEV/MMCTL21/AUTODOC/HOSTLW.D

IConnectionPointHelper Interface
Contains functions for implementing the ConnectionPointHelper object, which provides a simple implementation of an IDispatch-based IConnectionPoint.  Also contains helper functions for implementing IConnectionPointContainer in the case where this is only connection maintained by the connection point container.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/CONNECT.CPP
Methods
HRESULT FireEventList
Fire a given IDispatch-based event on all objects (e.g. VBS) connected to this ConnectionPointHelper object.  Parameters for the event are passed as a va_list array.
HRESULT FireEvent
Fire a given IDispatch-based event on all objects (e.g. VBS) connected to this ConnectionPointHelper object.  Parameters for the event are passed as a varying argument list.
HRESULT EnumConnectionPoints
Helps implement IConnectionPointContainer::EnumConnectionPoints in the case where this object implements the only connection maintained by the connection point container.
HRESULT FindConnectionPoint
Helps implement IConnectionPointContainer::FindConnectionPoint in the case where this object implements the only connection maintained by the connection point container.
Comments
To allocate an ConnectionPointHelper object, call AllocConnectionPointHelper.  To free the object, call FreeConnectionPointHelper (not Release -- see AllocConnectionPointHelper for more information).
This interface is based on IConnectionPoint.

IConnectionPointHelper::EnumConnectionPoints Method
HRESULT EnumConnectionPoints(LPENUMCONNECTIONPOINTS * ppEnum)
Helps implement IConnectionPointContainer::EnumConnectionPoints in the case where this object implements the only connection maintained by the connection point container.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/CONNECT.CPP
Return Value
Returns the same error codes as IConnectionPointContainer::EnumConnectionPoints.
Parameters
ppEnum
See IConnectionPointContainer::EnumConnectionPoints.
Example
In the following example, CMyControl is a class that is based on (among other things) IConnectionPointContainer.  This example shows how to use this EnumConnectionPoints function to implement IConnectionPointContainer::EnumConnectionPoints.
STDMETHODIMP CMyControl::EnumConnectionPoints(
	LPENUMCONNECTIONPOINTS *ppEnum)
{
	return m_pconpt->EnumConnectionPoints(ppEnum);
}

IConnectionPointHelper::FindConnectionPoint Method
HRESULT FindConnectionPoint(LPENUMCONNECTIONPOINTS * ppFindConnectionPoint)
Helps implement IConnectionPointContainer::FindConnectionPoint in the case where this object implements the only connection maintained by the connection point container.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/CONNECT.CPP
Return Value
Returns the same error codes as IConnectionPointContainer::FindConnectionPoint.
Parameters
ppFindConnectionPoint
See IConnectionPointContainer::FindConnectionPoint.
Example
In the following example, CMyControl is a class that is based on (among other things) IConnectionPointContainer.  This example shows how to use this FindConnectionPoint function to implement IConnectionPointContainer::FindConnectionPoint.
STDMETHODIMP CMyControl::FindConnectionPoint(REFIID riid,
	LPCONNECTIONPOINT *ppCP)
{
	return m_pconpt->FindConnectionPoint(riid, ppCP);
}

IConnectionPointHelper::FireEvent Method
HRESULT FireEvent(DISPID dispid, (varying) (arguments))
Fire a given IDispatch-based event on all objects (e.g. VBS) connected to this ConnectionPointHelper object.  Parameters for the event are passed as a varying argument list.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/CONNECT.CPP
Return Codes
S_OK	Success.	

Parameters
dispid
The ID of the event to fire.
(arguments)
The arguments to pass to the event. These must consist of N pairs of arguments followed by a 0 (zero value).  In each pair, the first argument is a VARTYPE value that indicates the type of the second argument.  Only a certain subset of VARTYPEs are supported.  See DispatchInvoke for more information about the format of these arguments.
Example
The following example fires the event DISPID_EVENT_BAR, which has two parameters (which in BASIC would be a Long and a String) -- 42 and "Hello", respectively, are passed as arguments.
pconpt->FireEvent(DISPID_EVENT_BAR, VT_INT, 42, VT_LPSTR, "Hello", 0);

IConnectionPointHelper::FireEventList Method
HRESULT FireEventList(DISPID dispid, va_list args)
Fire a given IDispatch-based event on all objects (e.g. VBS) connected to this ConnectionPointHelper object.  Parameters for the event are passed as a va_list array.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/CONNECT.CPP
Return Codes
S_OK	Success.	

Parameters
dispid
The ID of the event to fire.
args
The arguments to pass.  See FireEventList for information about the organization of these arguments.

IEnumVariantProperty Interface
Allows the properties of an object to be enumerated.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/AVIO.CPP
Methods
HRESULT Next
Retrieves a specified number of items in the enumeration sequence.
HRESULT Skip
Skips over a specified number of items in the enumeration sequence.
HRESULT Reset
Resets the enumeration sequence to the beginning.
HRESULT Clone
Creates another enumerator that contains the same enumeration state as the current one.  Note that VariantIO does not implement this method.
Comments
The VariantIO implementation of IEnumVariantProperty has these restrictions:
—	Clone is not supported.
—	Reset is automatically called whenever a property is removed from the VariantIO object.

IEnumVariantProperty::Clone Method
HRESULT Clone(IEnumVariantProperty * * ppenum)
Creates another enumerator that contains the same enumeration state as the current one.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/AVIO.CPP
Return Codes
S_OK	Success.	
E_OUTOFMEMORY	Out of memory.	
E_UNEXPECTED	An unexpected error occurred.	

Parameters
ppenum
On exit, contains the duplicate enumerator.  If the function was unsuccessful, this parameter's value is undefined.
Comments
Note that VariantIO does not implement this method.

IEnumVariantProperty::Next Method
HRESULT Next(unsigned long celt, VariantProperty * rgvp, unsigned long * pceltFetched)
Retrieves a specified number of items in the enumeration sequence.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/AVIO.CPP
Return Codes
S_OK	The number of elements returned is celt.	
S_FALSE	The number of elements returned is not celt.	

Parameters
celt
The number of elements being requested.
rgvp
Receives an array of size celt (or larger) of the elements to be returned.  The caller is responsible for calling SysFreeString and VariantClear on the bstrPropName and varValue fields, respectively, of each element returned in rgvp.  (Alternatively, the caller can simply call VariantPropertyClear on each element returned in rgvp.)
pceltFetched
On return, contains the number of elements actually returned in rgelt.  If pceltFetched is NULL, this information is not returned.

IEnumVariantProperty::Reset Method
HRESULT Reset()
Resets the enumeration sequence to the beginning.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/AVIO.CPP
Return Codes
S_OK	Success.	

Comments
There is no guarantee that the same set of objects will be enumerated after the reset, because it depends on the collection being enumerated.

IEnumVariantProperty::Skip Method
HRESULT Skip(unsigned long celt)
Skips over a specified number of items in the enumeration sequence.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/AVIO.CPP
Return Codes
S_OK	The number of elements skipped is celt.	
S_FALSE	The number of elements skipped is not celt.	

Parameters
celt
The number of elements that are to be skipped.

IHostLWOC Interface
Provides low-level efficient access to the properties of a HostLW control.
Defined in: C:/DEV/MMCTL21/AUTODOC/HOSTLW.D
Methods
HRESULT GetInfo
Retrieves control properties.
HRESULT SetInfo
Sets control properties.
Comments
This interface is defined in "HostLWOC.h".

IHostLWOC::GetInfo Method
HRESULT GetInfo(HostLWOCInfo * pInfo, UINT cbInfo)
Retrieves control properties.
Defined in: C:/DEV/MMCTL21/AUTODOC/HOSTLW.D
Return Codes
S_OK	Success.	
E_INVALIDARG	This object supports an earlier version of the HostLWOCInfo structure than is specified by cbInfo.	

Parameters
pInfo
Points to a caller-provided buffer.  Information retrieved by GetInfo will be stored in this buffer.
cbInfo
The size (in bytes) of the structure pointed to by pInfo (used for version checking).

IHostLWOC::SetInfo Method
HRESULT SetInfo(HostLWOCInfo * pInfo, UINT cbInfo)
Sets control properties.
Defined in: C:/DEV/MMCTL21/AUTODOC/HOSTLW.D
Return Codes
S_OK	Success.	
E_INVALIDARG	This object supports an earlier version of the HostLWOCInfo structure than is specified by cbInfo.	

Parameters
pInfo
Points to a caller-provided buffer containing information that is to be stored in the control.
cbInfo
The size (in bytes) of the structure pointed to by pInfo (used for version checking).
Comments
If you only want to change some of the fields of pInfo, call GetInfo first to initialize pInfo and then change the desired fields and call SetInfo.

ILineOC Interface
Provides low-level efficient access to the properties of a Line control.
Defined in: C:/DEV/MMCTL21/AUTODOC/LINE.D
Methods
HRESULT GetInfo
Retrieves control properties.
HRESULT SetInfo
Sets control properties.
Comments
This interface is defined in "LineOC.h".

ILineOC::GetInfo Method
HRESULT GetInfo(LineOCInfo * pInfo, UINT cbInfo)
Retrieves control properties.
Defined in: C:/DEV/MMCTL21/AUTODOC/LINE.D
Return Codes
S_OK	Success.	
E_INVALIDARG	This object supports an earlier version of the LineOCInfo structure than is specified by cbInfo.	

Parameters
pInfo
Points to a caller-provided buffer.  Information retrieved by GetInfo will be stored in this buffer.
cbInfo
The size (in bytes) of the structure pointed to by pInfo (used for version checking).

ILineOC::SetInfo Method
HRESULT SetInfo(LineOCInfo * pInfo, UINT cbInfo)
Sets control properties.
Defined in: C:/DEV/MMCTL21/AUTODOC/LINE.D
Return Codes
S_OK	Success.	
E_INVALIDARG	This object supports an earlier version of the LineOCInfo structure than is specified by cbInfo.	

Parameters
pInfo
Points to a caller-provided buffer containing information that is to be stored in the control.
cbInfo
The size (in bytes) of the structure pointed to by pInfo (used for version checking).
Comments
If you only want to change some of the fields of pInfo, call GetInfo first to initialize pInfo and then change the desired fields and call SetInfo.

IManageVariantIO Interface
Based on IVariantIO.  Allows the caller to control how the methods of the IVariantIO object operate (e.g. whether the IVariantIO object is in loading mode or saving mode).
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/AVIO.CPP
Methods
HRESULT SetMode
Sets the mode of the IVariantIO object.
HRESULT SetMode
Gets the mode of the IVariantIO object.
HRESULT DeleteAllProperties
Removes all property/value pairs from the VariantIO object.

IManageVariantIO::DeleteAllProperties Method
HRESULT DeleteAllProperties()
Removes all property/value pairs from the VariantIO object.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/AVIO.CPP
Return Codes
S_OK	Success.	
E_OUTOFMEMORY	Out of memory.	

IManageVariantIO::GetMode Method
HRESULT GetMode(DWORD * *pdwFlags)
Gets the mode of the IVariantIO object.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/AVIO.CPP
Return Codes
S_OK	Success.	

Parameters
*pdwFlags
Returns the flag specifying the current mode of the IVariantIO object.  See SetMode for a description of these flags.
Comments
When a VariantIO object is created, its initial mode is such that none of the flags in dwFlags are specified.

IManageVariantIO::SetMode Method
HRESULT SetMode(DWORD dwFlags)
Sets the mode of the IVariantIO object.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/AVIO.CPP
Return Codes
S_OK	Success.	

Parameters
dwFlags
May contain the following flags:
VIO_ISLOADING
Set the IVariantIO object to loading mode, so that IVariantIO::Persist and IVariantIO::PersistList copy data from properties to variables.  If this flag is not spacified, then the IVariantIO object will be set to saving mode, so that IVariantIO::Persist and IVariantIO::PersistList copy data from variables to properties.
VIO_ZEROISDEFAULT
Inform the IVariantIO object that 0 is the default values for properties and that 0-valued properties should not be saved via IVariantIO::Persist and IVariantIO::PersistList.
Comments
When a VariantIO object is created, its initial mode is such that none of the flags in dwFlags are specified.

InitHelpAdvise
HRESULT InitHelpAdvise(HelpAdviseInfo * pha) 
Initializes a HelpAdviseInfo structure, used to help implement IViewObject::SetAdvise and IViewObject::GetAdvise.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/ADVISE.CPP
Parameters
pha
Caller-allocated structure that contains information used to help implement IViewObject::SetAdvise and IViewObject::GetAdvise.
Comments
You must call InitHelpAdvise before calling HelpSetAdvise and HelpGetAdvise, and UninitHelpAdvise when the object that contains the HelpAdviseInfo structure is deleted.

IPersistVariantIO Interface
Loads or saves properties from/to a given IVariantIO object (control).  Used by PropertyHelper to help an object implement IPersistpropertyBag, IPersistStream, IPersistStreamInit, and a simplified implementation of IDispatch, for any object which implements IPersistVariantIO.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/APH.CPP
Methods
HRESULT InitNew
Informs the control that it has been created in a "new" state, so it should initialize its state data (if not done already).  If the control is being loaded from a stream, DoPersist will be called instead of InitNew.
HRESULT IsDirty
Returns S_OK if the object has changed since it was last saved, S_FALSE otherwise.
HRESULT DoPersist
Instructs the object to load or save its properties to a gieven IVariantIO object.

IPersistVariantIO::DoPersist Method
HRESULT DoPersist(IVariantIO * pvio, DWORD dwFlags)
Instructs the object to load or save its properties to a gieven IVariantIO object.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/APH.CPP
Parameters
pvio
IVariantIO object to save to or load from.
dwFlags
May contain the following flags:
PVIO_PROPNAMESONLY
The caller is calling DoPersist purely to get a list of the names of properties from the control.  The control can safely ignore this flag, unless it wishes to use this information for optimization purposes.
PVIO_CLEARDIRTY
The control should clear its dirty flag (so that the next call to IsDirty should return S_FALSE).
PVIO_NOKIDS
The control need not persist any child controls that it may contain.  For example, this flag is used by the property helper object when it calls DoPersist inside its IDispatch::GetIDsOfNames and IDispatch::Invoke.
Example
The following example shows how a control might implement DoPersist
STDMETHODIMP CMyControl::DoPersist(IVariantIO* pvio, DWORD dwFlags)
{
	// load or save control properties to/from <info>
	HRESULT hr;
	if (FAILED(hr = pvio->Persist(0,
			"BorderWidth", VT_INT, &m_iWidth,
			"BorderColor", VT_INT, &m_rgb,
			"X1", VT_INT, &m_iX1,
			"Y1", VT_INT, &m_iY1,
			"X2", VT_INT, &m_iX2,
			"Y2", VT_INT, &m_iY2,
			NULL)))
		return hr;
	if (hr == S_OK)
		...one or more properties changed, so repaint etc. control...

	// clear the dirty bit if requested
	if (dwFlags & PVIO_CLEARDIRTY)
		m_fDirty = FALSE;

	return S_OK;
}

IPersistVariantIO::InitNew Method
HRESULT InitNew()
Informs the control that it has been created in a "new" state, so it should initialize its state data (if not done already).  If the control is being loaded from a stream, DoPersist will be called instead of InitNew.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/APH.CPP
Return Codes
S_OK	Success.	
E_NOTIMPL	The control does not implement this method.	

Comments
The control can safely return E_NOTIMPL from this method if it initializes its data when it is created.  In this case, if the control needs to be re-initialized, the container will simply destroy and re-create it (which is what almost every container does anyway).

IPersistVariantIO::IsDirty Method
HRESULT IsDirty()
Returns S_OK if the object has changed since it was last saved, S_FALSE otherwise.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/APH.CPP
Return Codes
S_OK	The object has changed since it was last saved.	
S_FALSE	The object has not changed since it was last saved.	

Comments
The control should maintain an internal "dirty flag" (e.g. a BOOL m_fDirty class member), which should be initialized to FALSE, but set to TRUE whenever the control's data changes and set to FALSE in DoPersist when the PVIO_CLEARDIRTY flag is specified.
Example
The following example shows how a control might implement IsDirty
STDMETHODIMP CMyControl::IsDirty()
{
	return (m_fDirty ? S_OK : S_FALSE);
}

ISiteLW Interface
Interface to a SiteLW object, which implements an ActiveX windowed control that hosts an ActiveX lightweight windowless control.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Methods
HRESULT SetSiteWindow
Sets the site HWND of the SiteLW object.  This is an alternative to providing the HWND to AllocSiteLW.
HRESULT SetSiteWindowParameters
Sets parameters of the SiteLW site window.
HRESULT SetDefaultPalette
Provides the site window with a default palette, to be used as the palette of the off-screen compositing bitmap if the SSWP_NOCUSTOMPALETTE is specified.
HRESULT GetControlColorSet
Returns a LOGPALETTE containing the colors of the embedded control's preferred palette (if any).
HRESULT SetServiceProvider
Provides the site window with a pointer to an implementation of IServiceProvider that the site should forward calls to IServiceProvider::QueryService to.
HRESULT SetAdvise
Identical to IViewObject::SetAdvise.  IAdviseSink::OnViewChange is called when the palette of the embedded control changes.
HRESULT GetAdvise
Identical to IViewObject::GetAdvise.  See SetAdvise.
HRESULT NewControl
Creates an instance of a control and embeds the control in the SiteLW control.
HRESULT CloseControl
Disconnects the loaded control (if any) from the site and releases it.
HRESULT ControlIsLoaded
Returns S_OK if there is control loaded, S_FALSE otherwise.
HRESULT ControlQueryInterface
Returns an AddRefd pointer to a specific interface on the loaded control (if any).
HRESULT SetDesignMode
Put the SiteLW object into either design mode or run mode.
HRESULT GetDesignMode
Returns S_OK if the site is in design mode, S_FALSE if the site is in run mode.
HRESULT CanShowProperties
Returns S_OK if there is a control loaded and it has one or more property sheets, S_FALSE otherwise.
HRESULT ShowProperties
Show the property sheet for the currently loaded control.
HRESULT ShowContextMenu
Displays the context menu that contains menu items from both the SiteLW object and, optionally, the embedded control.
LRESULT OnSiteWindowResized
Informs the site that the site window has received a WM_SIZE message.
LRESULT OnSiteWindowQueryNewPalette
Informs the site that the site window has received a WM_QUERYNEWPALETTE message.
LRESULT OnSiteWindowPaletteChanged
Informs the site that the site window has received a WM_PALETTECHANGED message.
LRESULT OnSiteWindowPaintRequest
Informs the site that the site window has received a WM_PAINT request.
LRESULT OnSiteWindowMouseMessage
Informs the site that the site window has received a mouse message.
LRESULT OnSiteWindowCursorMessage
Informs the site that the site window has received a WM_CURSOR message.
LRESULT OnSiteWindowKeyboardMessage
Informs the site that the site window has received a keyboard message.
LRESULT OnSiteWindowCommand
Informs the site that the site window has received a WM_COMMAND message.
void OnSiteWindowTick
Tells the site window to tell the loaded control to advance one step in its animation (if applicable).
void OnSiteWindowRewind
Tells the site window to tell the loaded control to rewind its animation (if applicable).
HRESULT OnTranslateAccelerator
Informs the site that the site's container has requested translation of an accelerator.
Comments
The owner of the site window is responsible for forwarding various window messages to the SiteLW object.  See each OnSiteWindowXXX method for more information.
Note that the site window will also receive various following WM_COMMAND commands which need to be interpreted in particular ways. See OnSiteWindowCommand for more information.

ISiteLW::CanShowProperties Method
HRESULT CanShowProperties()
Returns S_OK if there is a control loaded and it has one or more property sheets, S_FALSE otherwise.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Codes
S_OK	The SiteLW object can show a property sheet using ShowProperties.	
S_OK	The SiteLW object cannot currently show a property sheet using ShowProperties.	

ISiteLW::CloseControl Method
HRESULT CloseControl()
Disconnects the loaded control (if any) from the site and releases it.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Codes
S_OK	Success.	

ISiteLW::ControlIsLoaded Method
HRESULT ControlIsLoaded()
Returns S_OK if there is control loaded, S_FALSE otherwise.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Codes
S_OK	A control is loaded.	
S_FALSE	No control is loaded.	

ISiteLW::ControlQueryInterface Method
HRESULT ControlQueryInterface(REFIID riid, LPVOID * ppv)
Returns an AddRefd pointer to a specific interface on the loaded control (if any).
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Codes
S_OK	Success.	
E_FAIL	No control is loaded.	
E_NOINTERFACE	The control doesn't support interface riid.	

Parameters
riid
The requested interface.
ppv
Where to store an AddRefd pointer to interface riid.  NULL is stored in *ppv on error.

ISiteLW::GetAdvise Method
HRESULT GetAdvise(DWORD * pdwAspects, DWORD * pdwAdvf, IAdviseSink * * ppAdvSink)
Identical to IViewObject::GetAdvise.  See SetAdvise.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Parameters
pdwAspects
See IViewObject::GetAdvise.
pdwAdvf
See IViewObject::GetAdvise.
ppAdvSink
See IViewObject::GetAdvise.

ISiteLW::GetControlColorSet Method
HRESULT GetControlColorSet(LOGPALETTE * * pplp)
Returns a LOGPALETTE containing the colors of the embedded control's preferred palette (if any).
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Parameters
pplp
Where to store a pointer to the allocated LOGPALETTE which is allocated by the ISiteLW object and freed by the caller using CoTaskMemFree.  NULL is stored in *pplp on error.

ISiteLW::GetDesignMode Method
HRESULT GetDesignMode()
Returns S_OK if the site is in design mode, S_FALSE if the site is in run mode.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Codes
S_OK	The site is in design mode.	
S_FALSE	The site is in run mode.	

ISiteLW::NewControl Method
HRESULT NewControl(IUnknown * punk, DWORD dwFlags)
Creates an instance of a control and embeds the control in the SiteLW control.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Codes
S_OK	Success.	
E_OUTOFMEMORY	Out of memory.	

Parameters
punk
The control to embed.  This pointer is AddRefd by NewControl.
dwFlags
May contain the following flags:
NC_DONTSETSITE
Don't call IOleObject::SetClientSite on punk (presumably because SetClientSite was already called on punk before punk was depersisted (loaded).

ISiteLW::OnSiteWindowCommand Method
LRESULT OnSiteWindowCommand(UINT uiMsg, WPARAM wParam, LPARAM lParam)
Informs the site that the site window has received a WM_COMMAND message.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Value
Returns the value to return from the message.
Parameters
uiMsg
The message that was received.
wParam
The WPARAM parameter of the message.
lParam
The LPARAM parameter of the message.
Comments
This function should be called when the site window owner receives a WM_COMMAND message that the site window owner doesn't otherwise handle.
Note that the site window will also receive the following WM_COMMAND commands in certain circumstances:
SITELW_ID_NEW
The user chose "New..." from the context menu. The site window should display a dialog box to allow the user to select a new control to create, and then call NewControl.
SITELW_ID_OPEN
The user chose "Open..." from the context menu. The site window should display a dialog box to allow the user to choose a control data file to open, and then call OpenControl.
SITELW_ID_CLOSE
The user chose "Close" from the context menu. The site window should call CloseControl.
SITELW_ID_SAVE
The user chose "Save" from the context menu. The site window should display a dialog box to allow the user to choose a control data file to save to, and then call SaveControl.
SITELW_ID_PROPERTIES
The user chose "Properties..." from the context menu.  The site window should call ShowProperties.

ISiteLW::OnSiteWindowCursorMessage Method
LRESULT OnSiteWindowCursorMessage(UINT uiMsg, WPARAM wParam, LPARAM lParam)
Informs the site that the site window has received a WM_SETCURSOR message.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Value
Returns the value to return from the message.
Parameters
uiMsg
The message that was received.
wParam
The WPARAM parameter of the message.
lParam
The LPARAM parameter of the message.
Comments
This function should be called when the site window owner receives a WM_SETCURSOR message.

ISiteLW::OnSiteWindowKeyboardMessage Method
LRESULT OnSiteWindowKeyboardMessage(UINT uiMsg, WPARAM wParam, LPARAM lParam)
Informs the site that the site window has received a keyboard message.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Value
Returns the value to return from the message.
Parameters
uiMsg
The message that was received.
wParam
The WPARAM parameter of the message.
lParam
The LPARAM parameter of the message.
Comments
This function should be called when the site window owner receives a WM_KEYDOWN, WM_KEYUP, WM_CHAR, WM_DEADCHAR, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_SYSDEADCHAR, WM_IME_xxx, WM_HELP, or WM_CANCELMODE message.

ISiteLW::OnSiteWindowMouseMessage Method
LRESULT OnSiteWindowMouseMessage(UINT uiMsg, WPARAM wParam, LPARAM lParam)
Informs the site that the site window has received a mouse message.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Value
Returns the value to return from the message.
Parameters
uiMsg
The message that was received.
wParam
The WPARAM parameter of the message.
lParam
The LPARAM parameter of the message.
Comments
This function should be called when the site window owner receives a WM_LBUTTONDOWN, WM_RBUTTONDOWN, WM_LBUTTONUP, WM_RBUTTONUP, WM_LBUTTONDBLCLK, WM_RBUTTONDBLCLK, or WM_MOUSEMOVE message.

ISiteLW::OnSiteWindowPaintRequest Method
LRESULT OnSiteWindowPaintRequest(WPARAM wParam)
Informs the site that the site window has received a WM_PAINT request.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Value
Returns the value to return from the message.
Parameters
wParam
The WPARAM parameter of the message.
Comments
This function should be called when the site window owner receives a WM_PAINT message.
Important: when the site window owner receives WM_ERASEBKGND, 0 should be returned (i.e. DefWindowProc should not be called).

ISiteLW::OnSiteWindowPaletteChanged Method
LRESULT OnSiteWindowPaletteChanged(WPARAM wParam)
Informs the site that the site window has received a WM_PALETTECHANGED message.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Value
Returns the value to return from the message.
Parameters
wParam
The WPARAM parameter of the message.
Comments
This function should be called when the site window owner receives a WM_PALETTECHANGED message.

ISiteLW::OnSiteWindowQueryNewPalette Method
LRESULT OnSiteWindowQueryNewPalette()
Informs the site that the site window has received a WM_QUERYNEWPALETTE message.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Value
Returns the value to return from the message.
Comments
This function should be called when the site window owner receives a WM_QUERYNEWPALETTE message.

ISiteLW::OnSiteWindowResized Method
LRESULT OnSiteWindowResized()
Informs the site that the site window has received a WM_SIZE message.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Value
Returns the value to return from the message.
Comments
This function should be called when the site window owner receives a WM_SIZE message.

ISiteLW::OnSiteWindowRewind Method
void OnSiteWindowRewind()
Tells the site window to tell the loaded control to rewind its animation (if applicable).
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP

ISiteLW::OnSiteWindowTick Method
void OnSiteWindowTick()
Tells the site window to tell the loaded control to advance one step in its animation (if applicable).
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP

ISiteLW::OnTranslateAccelerator Method
HRESULT OnTranslateAccelerator(LPMSG lpMsg)
Informs the site that the site's container has requested translation of an accelerator.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Value
Return values are the same as for IOleInPlaceActiveObject::TranslateAccelerator:  S_OK if the accelerator was processed, S_FALSE if not.
Parameters
lpMsg
Pointer to message structure that needs translation.

ISiteLW::SetAdvise Method
HRESULT SetAdvise(DWORD dwAspects, DWORD dwAdvf, IAdviseSink * pAdvSink)
Identical to IViewObject::SetAdvise.  IAdviseSink::OnViewChange is called when the palette of the embedded control changes.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Parameters
dwAspects
See IViewObject::SetAdvise.
dwAdvf
See IViewObject::SetAdvise.
pAdvSink
See IViewObject::SetAdvise.

ISiteLW::SetDefaultPalette Method
HRESULT SetDefaultPalette(HPALETTE hpal)
Provides the site window with a default palette, to be used as the palette of the off-screen compositing bitmap if the SSWP_NOCUSTOMPALETTE is specified.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Codes
S_OK	Success.	

Parameters
hpal
The palette to use as the default palette. SiteLW takes over ownership of this palette and will be responsible for calling DeleteObject on it to free it. hpal can be NULL to specify no default palette.

ISiteLW::SetDesignMode Method
HRESULT SetDesignMode(BOOL f)
Put the SiteLW object into either design mode or run mode.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Codes
S_OK	Success.	
E_OUTOFMEMORY	Out of memory.	

Parameters
f
If TRUE, the SiteLW object is put into design mode. If FALSE, the SiteLW object is put into run mode.

ISiteLW::SetServiceProvider Method
HRESULT SetServiceProvider(IServiceProvider * psp)
Provides the site window with a pointer to an implementation of IServiceProvider that the site should forward calls to IServiceProvider::QueryService to.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Parameters
psp
When the embedded control calls IServiceProvider on the site, the site forwards the calls to psp.  If psp is NULL then calls to IServiceProvider on the site return E_FAIL.
Comments
The caller should call this function with psp==NULL before freeing the site object, to release the reference count to the site.

ISiteLW::SetSiteWindow Method
HRESULT SetSiteWindow(HWND hwnd, DWORD dwFlags)
Sets the site HWND of the SiteLW object.  This is an alternative to providing the HWND to AllocSiteLW.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Codes
S_OK	Success.	

Parameters
hwnd
Window into which the site object will display the loaded control.
dwFlags
Currently unused.  Must be set to zero.

ISiteLW::SetSiteWindowParameters Method
HRESULT SetSiteWindowParameters(DWORD dwFlags, IMKBitmap * pbmBkgnd)
Sets parameters of the SiteLW site window.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Codes
S_OK	Success.	

Parameters
dwFlags
May contain the following flags:
SSWP_OFFSCREEN
The loaded control is drawn into an off-screen bitmap (after filling the bitmap with the background brush) which is then blitted to the screen. This reduces flicker at the cost of speed and temporary memory.
SSWP_HATCHEDBKGND
The background is drawn with a hatched brush.  If this flag is not specified, the background is drawn with the user's window color (COLOR_WINDOW).
SSWP_STRETCHTOWINDOW
The loaded control is drawn large enough to fill the entire site window client area; requests by the control to set its bounding rectangle are denied.  If this flag is not specified, then the control is drawn at its natural size (determined by calling IViewObject2::GetExtent on the control) and IOleInPlaceSite::OnPosRectChange requests are honored.
SSWP_CONTEXTNOFILEIO
The context menu displayed when the user right-clicks does not include file I/O menu items ("Open...", "Save").
SSWP_NOCUSTOMPALETTE
SiteLW will not query the loaded control for a custom palette.  Instead, SiteLW will simply use the container's ambient palette, or the halftone palette if no ambient palette exists.
SSWP_STATICPALETTE
Once the ambient palette has been specified, it will never change for the lifetime of the loaded object.
pbmBkgnd
Background bitmap to display in the site window (behind the loaded control, if any).  If pbmBkgnd is NULL, then the background brush (see SSWP_HATCHEDBKGND) is used instead.

ISiteLW::ShowContextMenu Method
HRESULT ShowContextMenu(POINT pt, BOOL fIncludeEmbeddedControl)
Displays the context menu that contains menu items from both the SiteLW object and, optionally, the embedded control.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Codes
S_OK	Success.	
E_OUTOFMEMORY	Out of memory.	

Parameters
pt
Where to display the context menu (in client coordinates).
fIncludeEmbeddedControl
If TRUE, add menu items from the embedded control to the context menu.  If FALSE, only use menu items for the SiteLW object.

ISiteLW::ShowProperties Method
HRESULT ShowProperties()
Show the property sheet for the currently loaded control.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Return Codes
S_OK	Success.	
E_OUTOFMEMORY	Out of memory.	

ISprite Interface
Provides low-level efficient access to the properties of a Sprite control.
Defined in: C:/DEV/MMCTL21/AUTODOC/SPRITE.D
Methods
HRESULT GetInfo
Retrieves control properties.
HRESULT SetInfo
Sets control properties.
Comments
This interface is defined in "isprite.h".

ISprite::GetInfo Method
HRESULT GetInfo(SpriteBitmapInfo* pBitmapInfo, UINT cbBitmapInfo, SpriteTranslucencyInfo* pTranslucencyInfo, UINT cbTranslucencyInfo, SpriteRotationInfo* pRotationInfo, UINT cbRotationInfo, SpriteQuadrangleInfo* pQuadrangleInfo, UINT cbQuadrangleInfo)
Retrieves control properties.
Defined in: C:/DEV/MMCTL21/AUTODOC/SPRITE.D
Return Codes
S_OK	Success.	
E_INVALIDARG	This object supports an earlier version of the desired structure.	

Parameters
pBitmapInfo
Points to a caller-provided buffer.  Information about the Sprite's bitmap will be stored in this buffer.  If NULL, no bitmap information will be retrieved.
cbBitmapInfo
The size (in bytes) of the structure pointed to by pBitmapInfo (used for version checking).  Ignored if pBitmapInfo is NULL.
pTranslucencyInfo
Points to a caller-provided buffer.  Information about the Sprite's translucency will be stored in this buffer.  If NULL, no translucency information will be retrieved.
cbTranslucencyInfo
The size (in bytes) of the structure pointed to by pTranslucencyInfo (used for version checking).  Ignored if pTranslucencyInfo is NULL.
pRotationInfo
Points to a caller-provided buffer.  Information about the Sprite's rotation will be stored in this buffer.  If NULL, no rotation information will be retrieved.
cbRotationInfo
The size (in bytes) of the structure pointed to by pRotationInfo (used for version checking).  Ignored if pRotationInfo is NULL.
pQuadrangleInfo
Points to a caller-provided buffer into which information about the Sprite's BLT-ing quadrangle will be stored.  If NULL, no information about the Sprite's BLT-ing quadrangle will be retrieved.
cbQuadrangleInfo
The size (in bytes) of the structure pointed to by pQuadrangleInfo (used for version checking).  Ignored if pQuadrangleInfo is NULL.

ISprite::SetInfo Method
HRESULT SetInfo(SpriteBitmapInfo* pBitmapInfo, UINT cbBitmapInfo, IMKBitmap* pMKBitmap, SpriteTranslucencyInfo* pTranslucencyInfo, UINT cbTranslucencyInfo, SpriteRotationInfo* pRotationInfo, UINT cbRotationInfo, SpriteQuadrangleInfo* pQuadrangleInfo, UINT cbQuadrangleInfo)
Sets control properties.
Defined in: C:/DEV/MMCTL21/AUTODOC/SPRITE.D
Return Codes
S_OK	Success.	
E_INVALIDARG	This object supports an earlier version of the provided structure.	

Parameters
pBitmapInfo
Points to a caller-provided buffer containing information about the Sprite's bitmap that is to be stored.  If NULL, the Sprite's bitmap information won't be altered.
cbBitmapInfo
The size (in bytes) of the structure pointed to by pBitmapInfo (used for version checking).  Ignored if pBitmapInfo is NULL.
pMKBitmap
If non-NULL, the Sprite will AddRef and use this bitmap, assuming it is the bitmap referred to in pBitmapInfo.
pTranslucencyInfo
Points to a caller-provided buffer containing information about the Sprite's translucency.  If NULL, the Sprite's translucency characteristics won't be altered.
cbTranslucencyInfo
The size (in bytes) of the structure pointed to by pTranslucencyInfo (used for version checking).  Ignored if pTranslucencyInfo is NULL.
pRotationInfo
Points to a caller-provided buffer containing information about the Sprite's rotation.  If NULL, the Sprite's rotation characteristics won't be altered.
cbRotationInfo
The size (in bytes) of the structure pointed to by pRotationInfo (used for version checking).  Ignored if pRotationInfo is NULL.
pQuadrangleInfo
Points to a caller-provided buffer containing information about the Sprite's BLT-ing quadrangle.  If NULL, Sprite's BLT-ing quadrangle won't be altered.
cbQuadrangleInfo
The size (in bytes) of the structure pointed to by pQuadrangleInfo (used for version checking).  Ignored if pQuadrangleInfo is NULL.

IVariantIO Interface
Allows property name/value pairs to be loaded or saved.  IVariantIO is an alternative to IPropertyBag which allows the caller to implement property-based persistence with less code.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/AVIO.CPP
Methods
HRESULT PersistList
Loads or saves a list of property name/value pairs, specified as a va_list array.
HRESULT Persist
Loads or saves a list of property name/value pairs, specified as a variable-length list of arguments.
HRESULT IsLoading
Return S_OK if the IVariantIO object is being used to load properties, S_FALSE if it is being used to save properties.

IVariantIO::IsLoading Method
HRESULT IsLoading()
Return S_OK if the IVariantIO object is being used to load properties, S_FALSE if it is being used to save
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/AVIO.CPP
Return Codes
S_OK	The IVariantIO object is in loading mode, so Persist and PersistList will copy data from properties to variables.	
S_FALSE	The IVariantIO object is in saving mode, so that Persist and PersistList will copy data from variables to properties.	

IVariantIO::Persist Method
HRESULT Persist(DWORD dwFlags, (varying) (arguments))
Loads or saves a list of property name/value pairs, specified as a variable-length list of arguments.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/AVIO.CPP
Return Codes
S_OK	Success.  At least one of the variables listed in (arguments) was written to, so the control may want to update itself accordingly.	
S_FALSE	None of the variables listed in (arguments) were written to (either because the IVariantIO object is in saving mode or because none of the properties named in (arguments) exist in the IVariantIO object.	
DISP_E_BADVARTYPE	One of the VARTYPE values in (arguments) is invalid.	
DISP_E_TYPEMISMATCH	One of the variables in (arguments) could not be coerced to the type of the corresponding property in the IVariantIO object, or vice versa.	
E_OUTOFMEMORY	Out of memory.	

Parameters
dwFlags
Optional flags.  See IManageVariantIO::SetMode for possible values.
(arguments)
The names, types, and pointers to variables containing the properties to persist.  These must consist of a series of argument triples (sets of 3 arguments) followed by a NULL. In each triplet, the first argument is an LPSTR which contains the name of the property; the second argument is a VARTYPE value that indicates the type of the property; the third argument is a pointer to a variable (typically a member variable of the control's C++ class) that holds the value of the property.  This variable will be read from or written to depending on the mode of the VariantIO object (see IsLoading) -- therefore the variables should contain valid values before Persist is called.  The following VARTYPE values are supported:
VT_INT
The following argument is an int *.
VT_I2
The following argument is a short *.
VT_I4
The following argument is a long *.
VT_BOOL
The following argument is a BOOL * (not a VARIANT_BOOL *).  Note that this behavior differs slightly from the usual definition of VT_BOOL.
VT_BSTR
The following argument is a BSTR *.  If Persist changes the value of this BSTR, the previous BSTR is automatically freed using SysFreeString.
VT_LPSTR
The following argument is an LPSTR that points to a char array capable of holding at least _MAX_PATH characters including the terminating NULL.
VT_UNKNOWN
The following argument is an LPUNKNOWN *.  If Persist changes the value of this LPUNKNOWN, the previous LPUNKNOWN is automatically freed using Release, and the new value is automatically AddRefd.
VT_DISPATCH
The following argument is an LPDISPATCH *.  If Persist changes the value of this LPDISPATCH, the previous LPDISPATCH is automatically freed using Release, and the new value is automatically AddRefd.
VT_VARIANT
The following arguement is a VARIANT *. This allows arbitrary parameters to be passed using this function.  Note that this behavior differs from the usual definition of VT_VARIANT.  If Persist changes the value of this VARIANT, the previous VARIANT value is automatically cleared using VariantClear.
Example
The following example persists two properties (which in BASIC would be a Long and a String, respectively) named "Foo" and "Bar", respectively.
pvio->Persist(0, "Foo", VT_INT, &m_iFoo, "Bar", VT_LPSTR, &m_achBar,
	NULL);

IVariantIO::PersistList Method
HRESULT PersistList(DWORD dwFlags, va_list args)
Loads or saves a list of property name/value pairs, specified as a va_list array.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/AVIO.CPP
Return Codes
S_OK	Success.  At least one of the variables listed in args was written to, so the control may want to update itself accordingly.	
S_FALSE	None of the variables listed in args were written to (either because the IVariantIO object is in saving mode or because none of the properties named in args exist in the IVariantIO object).	
DISP_E_BADVARTYPE	One of the VARTYPE values in args is invalid.	
DISP_E_TYPEMISMATCH	One of the variables in args could not be coerced to the type of the corresponding property in the IVariantIO object, or vice versa.	
E_OUTOFMEMORY	Out of memory.	

Parameters
dwFlags
Optional flags.  See IManageVariantIO::SetMode for possible values.
args
The arguments to pass.  See Persist for information about the organization of these arguments.

Line Object
Description
A lightweight windowless ActiveX control which displays as a single line segment of adjustable width and 24-bpp color.
Defined in: C:/DEV/MMCTL21/AUTODOC/LINE.D
Properties
Long BorderColor
The color of the line, expressed as a standard 24-bit RGB value.
Long BorderWidth
The width of the line, in pixels.  This value is between 1 and 4 inclusive; if BorderWidth is set to a number outside this range it is changed to 1 or 4, whichever is closer.
Long X1
The x-coordinate of the head end of the line.
Long Y1
The y-coordinate of the head end of the line.
Long X2
The x-coordinate of the tail end of the line.
Long Y2
The y-coordinate of the tail end of the line.
Comments
For all users:
—	X1, Y1, X2, and Y2 are measured in pixels relative to the origin of the container.
—	This control cannot be directly embedded in IE3, since IE3 does not support windowless controls.  Instead, embed the HostLW control in IE3, and then embed this control into the HostLW control.
—	This control is packaged in both design-time and run-time versions. The design time version allows the control to be dragged at either end (to move an endpoint) or in the middle (to move the entire line).  The line draws its own grab handles and provides cursor-change feedback.  A property page is provided for editing all properties.  A "Straighten" verb (typically accessed via the right mouse) is provided to make the line horizontal or vertical.
The run-time version drops editing features (most notably the property page) in order to reduce code size.
—	The class ID of the design-time version of this control is "BA6B5D20-8614-11CF-B8ED-0020AF344E0A".
—	The class ID of the run-time version of this control is "TBD".
For C++ users:
—	The class ID of this control is defined as CLSID_CLineOC in "LineOC.h".
—	The ProgID of this control is "Line.Line.1".
—	This control implements the following interfaces:
—	IUnknown: A delegating IUnknown that supports aggregation
—	ILineOC: Provides low-level efficient access to the properties of a Line control.  See that interface for more information.
—	IViewObjectEx subset (based on IViewObject and IViewObject2): Used to display the object. DVASPECT_CONTENT is the only supported aspect.  Freeze, Unfreeze, GetRect, GetViewStatus, QueryHitRect, and GetNaturalExtent are not implemented.
—	IOleObject subset: Used to allow the container to provide the client site pointer, invoke control verbs, and get control state.  Only SetClientSite, DoVerb, EnumVerbs (design time version only), and GetMiscStatus are implemented.
—	IOleInPlaceObjectWindowless subset (based on IOleWindow and IOleInPlaceObject): Used to change control state and pass window messages to the control.  Only UIDeactivate, SetObjectRects, and OnWindowmessage, are implemented.
—	IOleControl subset: Used to inform the control of ambient property changes.  Only OnAmbientPropertyChange is implemented.
—	ISpecifyPropertyPages: Used to retrieve information about the control's property page.  GetPages is implemented only in the design time version.
—	IPersistStreamInit (based on IPersistStream): Used to persist the control's data to/from an IStream. The file format is compatible with past and future versions of this control (i.e. adding and removing properties won't break the control).
—	IPersistPropertyBag: Used to persist the control's data to/from an IPropertyBag.
—	IDispatch:  Provides access to the control's properties. Does not provide type information.
—	This control sources (calls) the following interfaces (if available) on the container-provided site object:
—	IOleClientSite: The client site pointer provided by the container.
—	IOleInPlaceSiteWindowless: Used to request that the control's position be changed, acquire mouse capture, invalidate and update the display of the control, and (at design time only) draw XOR'd image of the control during dragging.
—	IDispatch: Used to access ambient properties (currently DISPID_AMBIENT_USERMODE).
—	IAdviseSink (provided via IViewObject::SetAdvise: Used to advise the container that the palette of the control changed.

LoadFromCSV
HRESULT LoadFromCSV(IOleClientSite * psite, IStream * pstream, LPUNKNOWN punkOuter, DWORD dwClsContext, LPUNKNOWN * ppunk, CLSID * pclsid, DWORD dwFlags) 
Read a CSV (Excel-readable comma-delimited) format stream and create an object that contains the data from that stream.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/LFCSV.CPP
Parameters
psite
The site of the new object.  If psite is not NULL, then IOleObject::SetClientSite(psite) is called on the newly-created object before IPersistPropertyBag::Load is called.
pstream
The stream to read from.
punkOuter
The controlling unknown to use for the new object.
dwClsContext
Specifies the context in which the executable is to be run. The values are taken from the enumeration CLSCTX. A typical value is CLSCTX_INPROC_SERVER.
ppunk
Where to store the pointer to the loaded object. NULL is stored in *ppunk on error.
pclsid
Where to store the class ID of the loaded object. If pclsid is NULL then this information is not returned.
dwFlags
Currently unused.  Must be set to 0.

LoadFromHTML
HRESULT LoadFromHTML(IOleClientSite * psite, IStream * pstream, LPUNKNOWN punkOuter, DWORD dwClsContext, LPUNKNOWN * ppunk, CLSID * pclsid, LPSTR * ppchPage, DWORD dwFlags) 
Reads an HTML format stream and creates an object specified by an <OBJECT> tag in that stream.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/LFHTML.CPP
Parameters
psite
The site of the new object.  If psite is not NULL, then IOleObject::SetClientSite(psite) is called on the newly-created object before IPersistPropertyBag::Load is called.
pstream
The stream to read from.
punkOuter
The controlling unknown to use for the new object.
dwClsContext
Specifies the context in which the executable is to be run. The values are taken from the enumeration CLSCTX. A typical value is CLSCTX_INPROC_SERVER.
ppunk
Where to store the pointer to the loaded object. NULL is stored in *ppunk on error.
pclsid
Where to store the class ID of the loaded object. If pclsid is NULL then this information is not returned.
ppchPage
Where to store a pointer to a null-terminated memory buffer (allocated by LoadFromHTML) into which the HTML file is read.  The caller is responsible for freeing this buffer using CoTaskMemFree.  This buffer may be used in subsequent calls to SaveToHTML to serve as a "template" -- SaveToHTML will write out the same HTML file that was read in (except for the <OBJECT> tag itself).
dwFlags
Currently unused.  Must be set to 0.
Comments
If pstream contains multiple <OBJECT> tags, the following rules are used to determine which <OBJECT> tag is replaced by pppb:
—	If pstream contains a <object> tag with the word "object" spelled in lowercase, the first such tag is used.
—	Otherwise, the first <OBJECT> tag is used; in this case the case of the word "object" does not matter.
So, if you want to allow a specific object in an HTML file to be edited, spell its <object> tag in lowercase and spell other <OBJECT> tags in uppercase (or mixed case).

LoadFromStream
HRESULT LoadFromStream(IOleClientSite * psite, IStream * pstream, LPUNKNOWN punkOuter, DWORD dwClsContext, LPUNKNOWN * ppunk, CLSID * pclsid, DWORD dwFlags) 
Read a stream that contains the class ID and data of an object previously saved using IPersistStream::Save, and create an object that contains the data from the stream.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/LFS.CPP
Parameters
psite
The site of the new object.  If psite is not NULL, then IOleObject::SetClientSite(psite) is called on the newly-created object before IPersistPropertyBag::Load is called.
pstream
The stream to read from.
punkOuter
The controlling unknown to use for the new object.
dwClsContext
Specifies the context in which the executable is to be run. The values are taken from the enumeration CLSCTX. A typical value is CLSCTX_INPROC_SERVER.
ppunk
Where to store the pointer to the loaded object. NULL is stored in *ppunk on error.
pclsid
Where to store the class ID of the loaded object. If pclsid is NULL then this information is not returned.
dwFlags
Currently unused.  Must be set to 0.

LoadPropertyBagFromCSV
HRESULT LoadPropertyBagFromCSV(IStream * pstream, int cch, IPropertyBag * ppb, DWORD dwFlags) 
Load properties that are stored in an IStream in CSV (Excel-readable comma-delimited) format into a given IPropertyBag object.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/LPBFCSV.CPP
Parameters
pstream
The stream to read from.
cch
The number of bytes to read in pstream.  If cch is -1, then pstream is read to its end.
ppb
The property bag to write to.
dwFlags
Currently unused.  Must be set to 0.
Comments
Note that this function does not (cannot, in fact) empty ppb prior to loading property name/value pairs from pstream.
Return Codes
S_OK	Success.	
E_FAIL	I/O error.	

LoadPropertyBagFromHTML
HRESULT LoadPropertyBagFromHTML(IStream * pstream, int cch, IPropertyBag * ppb, LPSTR * ppchPage, DWORD dwFlags) 
Load properties that are stored in a <OBJECT> tag in an IStream in HTML format into a given IPropertyBag object.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/LPBFHTML.CPP
Parameters
pstream
The stream to read from.
cch
The number of bytes to read in pstream.  If cch is -1, then pstream is read to its end.
ppb
The property bag to write to.
ppchPage
Where to store a pointer to a null-terminated memory buffer (allocated by this function) into which the HTML file is read.  The caller is responsible for freeing this buffer using CoTaskMemFree.  See LoadFromHTML for more information about ppchPage.
dwFlags
Currently unused.  Must be set to 0.
Comments
If pstream contains multiple <OBJECT> tags, the same rules specified in LoadFromHTML are used to determine which <OBJECT> tag is replaced by pppb.
Note that this function does not (cannot, in fact) empty ppb prior to loading property name/value pairs from pstream.
Return Codes
S_OK	Success.	
E_FAIL	I/O error.	

LoadPropertyBagFromStream
HRESULT LoadPropertyBagFromStream(IStream * pstream, IPropertyBag * ppb, DWORD dwFlags) 
Load properties that are stored in an IStream (in the simple tagged binary format written by WriteVariantProperty) into an IPropertyBag object.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/LPBFS.CPP
Parameters
pstream
The stream to read from.
ppb
The property bag to write to.
dwFlags
Currently unused.  Must be set to 0.
Comments
Note that this function does not (cannot, in fact) empty ppb prior to loading property name/value pairs from pstream.
Return Codes
S_OK	Success.	
E_FAIL	I/O error.	

MapMRUListToMenu
HRESULT MapMRUListToMenu(HMRULIST hMRUList, HMENU hMenu, UINT cBaseMenuItems, UINT iItemAfterMRUList, UINT iFirstMRUItem, const TCHAR* pszEmptyListMenuItem) 
Maps an MRU list into an application's menu.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/MRU.CPP
Parameters
hMRUList
[in] A handle to a previously opened MRU list.
hMenu
[in] The handle of the menu to modify.  Can't be NULL.
cBaseMenuItems
[in] The size (i.e., number of items) in the menu excluding the MRU list.
iItemAfterMRUList
[in] The relative, 0-based index of the item in the menu immediately following the MRU list.  Typically the index of a separator.
iFirstMRUItem
[in] The absolute resource ID of the first MRU menu item.
pszEmptyListMenuItem
[in] The name of the grayed menu item to insert if the MRU list is empty.  If NULL, "File List" will be used.
Comments
The algorithm is...
—	The menu item at relative offset iItemAfterMRUList - 1 is repeatedly deleted until the number of items in the menu is less than or equal to cBaseMenuItems.
—	If the receiver MRU list is empty, then the pszEmptyListMenuItem is inserted into the menu as a grayed item with ID iFirstMRUItem.
—	Otherwise, all the entries from the MRU list are inserted into the menu before iItemAfterMRUList.  The entries are preceeded by a 1-based index.  The ID of the first MRU item is set to iFirstMRUItem, the second MRU item is iFirstMRUItem+1, etc. ---------------------------------------------------------------------------

Return Codes
S_OK	Success.	
(other)	Failure.	

MsgWndCreate
HWND MsgWndCreate(void) 
Creates the hidden message-passing window (if it doesn't exist). This window is used by MsgWndSendToCallback, MsgWndPostToCallback, and MsgWndTrackPopupMenuEx.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/MSGWND.CPP
Return Value
Returns the handle of the message-passing window.  Returns NULL on error.
Comments
You should call MsgWndCreate in the constructor of your control to ensure that the window gets created on the same thread as the thread which created your control.
You should call MsgWndDestroy in the destructor of your control.

MsgWndDestroy
LRESULT MsgWndDestroy(HWND hwnd, DWORD dwFlags, STDAPI_(void) MsgWndDestroy) 
Destroys a hidden message-passing window that was previously created by calling MsgWndCreate.  Before the window is destroyed, all pending messages are dispatched in it.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/MSGWND.CPP
Parameters
hwnd
The hidden message-passing window which was created by calling MsgWndCreate (usually in the constructor of the control, to ensure that the window is created in the same thread that created the control).
dwFlags
Currently unused.  Must be set to zero.
MsgWndDestroy
MsgWndDestroy is typically called in the destructor of a control.
MsgWndDestroy should only be called in the thread that called MsgWndCreate.

MsgWndPostToCallback
LRESULT MsgWndPostToCallback(HWND hwnd, MsgWndCallback * pproc, UINT uiMsg, LPARAM lParam) 
Posts a message to the control's hidden message-passing window (typically created by calling MsgWndCreate in the control's constructor).  When the window receives the message, it calls a given callback function.  This can be used to safely pass information between threads.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/MSGWND.CPP
Return Value
Returns the value returned by PostMessage (-1 on error).
Parameters
hwnd
The hidden message-passing window which was created by calling MsgWndCreate (usually in the constructor of the control, to ensure that the window is created in the same thread that created the control).
pproc
The callback function that is to receive the message.  This function will be called on whatever thread calls DispatchMessage.  The wParam parameter of this function should be ignored by the callback function.
uiMsg
A message number to pass to pproc.  This is a window message number, so it must be in the range WM_USER through 0x7FFF.
lParam
A parameter to pass to pproc.
Comments
Message uiMsg is posted (via PostMessage) to the hidden message-passing window hwnd.  When the window receives the message, it calls pproc(uiMsg, lParam).
Example
The following example declares a callback function and calls it via MsgWndPostToCallback.  Note that wParam is for internal use by MsgWndPostToCallback and should be ignored by the callback function.
void CALLBACK MyMsgWndCallback(UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
	TRACE("got the callback: uiMsg=%u, lParam=%d\n", uiMsg, lParam);
}

...
MsgWndPostToCallback(MyMsgWndCallback, WM_USER, 42);

MsgWndSendToCallback
LRESULT MsgWndSendToCallback(HWND hwnd, MsgWndCallback * pproc, UINT uiMsg, LPARAM lParam) 
Sends a message to the control's hidden message-passing window (typically created by calling MsgWndCreate in the control's constructor).  When the window receives the message, it calls a given callback function.  This can be used to safely pass information between threads.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/MSGWND.CPP
Return Value
Returns the value returned by SendMessage (-1 on error).
Parameters
hwnd
The hidden message-passing window which was created by calling MsgWndCreate (usually in the constructor of the control, to ensure that the window is created in the same thread that created the control).
pproc
The callback function that is to receive the message.  This function will be called on whatever thread calls DispatchMessage.  The wParam parameter of this function should be ignored by the callback function.
uiMsg
A message number to pass to pproc.  This is a window message number, so it must be in the range WM_USER through 0x7FFF.
lParam
A parameter to pass to pproc.
Comments
Message uiMsg is sended (via SendMessage) to the hidden message-passing window hwnd.  When the window receives the message, it calls pproc(uiMsg, lParam).
Note that the calling thread blocks until the message is processed by the receiving thread.
Example
The following example declares a callback function and calls it via MsgWndSendToCallback.  Note that wParam is for internal use by MsgWndPostToCallback and should be ignored by the callback function.
void CALLBACK MyMsgWndCallback(UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
	TRACE("got the callback: uiMsg=%u, lParam=%d\n", uiMsg, lParam);
}

...
MsgWndSendToCallback(MyMsgWndCallback, WM_USER, 42);

MsgWndSetTimer
LRESULT MsgWndSetTimer(HWND hwnd, MsgWndCallback * pproc, UINT nIDEvent, UINT uElapse, LPARAM lParam) 
Calls SetTimer to cause WM_TIMER messages to be sent to the the control's hidden message-passing window (typically created by calling MsgWndCreate in the control's constructor). When the window receives the message, it calls a given callback function.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/MSGWND.CPP
Return Value
Returns the value returned by SetTimer (0 on error).
Parameters
hwnd
The hidden message-passing window which was created by calling MsgWndCreate (usually in the constructor of the control, to ensure that the window is created in the same thread that created the control).
pproc
The callback function that is called when the timer fires.  This function will be called on whatever thread calls DispatchMessage.  When pproc receives WM_TIMER, wParam is nIDEvent and lParam is the value of lParam passed to MsgWndSetTimer.
nIDEvent
See WM_TIMER.
uElapse
See WM_TIMER.
lParam
A parameter to pass to pproc.
Comments
Note that only one callback function pproc can be used per message-passing HWND.

MsgWndTrackPopupMenuEx
LRESULT MsgWndTrackPopupMenuEx(HWND hwnd, HMENU hmenu, UINT fuFlags, int x, int y, LPTPMPARAMS lptpm, MsgWndCallback * pproc, LPARAM lParam) 
Calls TrackPopupMenuEx to display a popup menu, and directs WM_COMMAND messages to a given callback function.  Can be used by a windowless control to display a popup context menu.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/MSGWND.CPP
Return Value
Returns the value returned by TrackPopupMenuEx (FALSE on error). Returns FALSE if the message window is currently being used for another popup menu.
Parameters
hwnd
The hidden message-passing window which was created by calling MsgWndCreate (usually in the constructor of the control, to ensure that the window is created in the same thread that created the control).
hmenu
See TrackPopupMenuEx.
fuFlags
See TrackPopupMenuEx.
x
See TrackPopupMenuEx.
y
See TrackPopupMenuEx.
lptpm
See TrackPopupMenuEx.
pproc
The callback function that is to receive WM_COMMAND messages.  The wParam parameter of this function is the wParam of the WM_COMMAND message.  The lParam parameter of this function is the lParam of MsgWndTrackPopupMenuEx.
lParam
A parameter to pass to pproc.
Comments
This function calls TrackPopupMenuEx.  Any WM_COMMAND messages from TrackPopupMenuEx are passed to pproc.
The hidden message-passing window is used to receive WM_COMMAND messages; this window is created if it doesn't yet exist.

OCEdit Object
Description
A heavyweight ActiveX control which can be used in a Visual Basic application to implement a simple ActiveX Control editor.
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP
Properties
String OCEdit::AppTitle
Sets or gets the title of the application, as defined by the application, for use in message boxes etc.
String OCEdit::Version
Returns the version of the OCEdit control, as a string. Read-only.
Boolean OCEdit::DesignMode
Sets the OCEdit control to be in either design or run mode, or gets the current mode.
Boolean OCEdit::IsControlLoaded
Returns True if there is a control loaded into the OCEdit control, False otherwise.  Read-only.
Object OCEdit::Control
Returns the loaded control, if any.  (More precisely, this property returns an object (IDispatch) reference to the currently-loaded control.)  This can be used to access the properties and methods of the control.  Read-only.
String OCEdit::ControlType
Returns the name of the class of the loaded control, if any. Read-only.
Boolean OCEdit::IsControlDirty
Returns True if the embedded control has been changed since it was last saved, or False otherwise.  Returns False if no control is loaded.  Read-only.
String OCEdit::ControlFileName
Returns the name of the data file (.htm, .csv, .stm) associated with the current control, if any.  Read-only.
String OCEdit::ControlFileTitle
Returns the title of the data file (.htm, .csv, .stm) associated with the current control, if any.  Read-only.
Boolean OCEdit::CanShowControlProperties
Returns True if OCEdit::ShowControlProperties can be called at this time to display the control's property page(s), False otherwise. Read-only.
Methods
Long OCEdit::NewControl
Closes the currently-loaded control, if any, and creates a new instance of a control which is embedded in the OCEdit control.
Long OCEdit::OpenControl
Closes the currently-loaded control, if any, and loads a new control from a given file (.htm, .csv, or .stm).
Long OCEdit::CloseControl
Closes the currently-loaded control, if any.
Long OCEdit::SaveControl
Saves the currently-loaded control into a given file (.htm, .csv, or .stm).
Long OCEdit::PromptToSaveControl
Prompts the user to save the currently-loaded control (if the control was modified since it was last saved).
Long OCEdit::ShowControlProperties
Displays a property frame containing the property pages of the loaded control.
Comments
OCEdit is designed for use in VB4 (not IE3).  OCEdit can be used to implement, in a Visual Basic application, a simple OLE Control (i.e. ActiveX Control) editor similar to OCTest.
The following events are fired by OCEdit:
—	ControlFileNameChanged: Fired when the OCEdit::ControlFileName and/or OCEdit::ControlFileTitle properties change.  No parameters. Can be used to update application UI (e.g. caption).
—	ControlTypeChanged: Fired when the OCEdit::ControlType property changes.  No parameters.  Can be used to update application UI (e.g. caption).
—	ControlEvent: Fired when the loaded control fires an event. ControlEvent is currently under construction; at the moment the only parameter is a Long which indicates the ID (1, 2, ...) of the event being fired.  Coming soon: event name and parameters.

OCEdit::AppTitle Property
Data Type
String
Description
Sets or gets the title of the application, as defined by the application, for use in message boxes etc.
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP
Comments
The value of the AppTitle property is used whenever OCEdit needs to refer to the name of the application.  For example, when PromptToSaveControl is called, the AppTitle property is used in the title of the message box.

OCEdit::CanShowControlProperties Property
Data Type
Boolean
Description
Returns True if ShowControlProperties can be called at this time to display the control's property page(s), False otherwise. Read-only.
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP

OCEdit::CloseControl Method
Long CloseControl()
Closes the currently-loaded control, if any.
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP
Return Value
Returns a non-negative HRESULT code on success, or a negative HRESULT error code on error.

OCEdit::Control Property
Data Type
Object
Description
Returns the loaded control, if any.  (More precisely, this property returns an object (IDispatch) reference to the currently-loaded control.)  This can be used to access the properties and methods of the control.  Read-only.
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP
Example
The following example sets the BorderWidth property of the control loaded into OCEdit control oced to 1, assuming the loaded control supports the BorderWidth property (e.g. if the loaded control is a Line).
oced.Control.BorderWidth = 1

OCEdit::ControlFileName Property
Data Type
String
Description
Returns the name of the data file (.htm, .csv, .stm) associated with the current control, if any.  Read-only.
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP

OCEdit::ControlFileTitle Property
Data Type
String
Description
Returns the title of the data file (.htm, .csv, .stm) associated with the current control, if any.  Read-only.
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP

OCEdit::ControlType Property
Data Type
String
Description
Returns the name of the class of the loaded control, if any. Read-only.
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP
Example
If oced is an OCEdit control that currently contains a Line control, then the following will set str to "Line".
Dim str As String
str = oced.ControlType

OCEdit::DesignMode Property
Data Type
Boolean
Description
Sets the OCEdit control to be in either design or run mode, or gets the current mode.
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP
Comments
If DesignMode is True, then the OCEdit control is in design mode, which means that editing is enabled.  If DesignMode is False, then OCEdit is in Run mode, which means that editing features are disabled.

OCEdit::Flags Property
Data Type
Long
Description
Sets or gets the current OCEdit flags.
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP
Comments
The flag values are the same as those described in ISiteLW::SetSiteWindowParameters.

OCEdit::IsControlDirty Property
Data Type
Boolean
Description
Returns True if the embedded control has been changed since it was last saved, or False otherwise.  Returns False if no control is loaded.  Read-only.
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP

OCEdit::IsControlLoaded Property
Data Type
Object
Description
Returns True if there is a control loaded into the OCEdit control, False otherwise.  Read-only.
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP

OCEdit::NewControl Method
Long NewControl(String Type)
Closes the currently-loaded control, if any, and creates a new instance of a control which is embedded in the OCEdit control.
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP
Return Value
Returns 1 if the user presses the Cancel button (if prompted). Otherwise returns a nonnegative HRESULT value on success, or a negative HRESULT on error.
Parameters
Type
The type of control to create.  This is either a class ID in braces (e.g. "{4E1F2E00-BD85-11CF-B705-00AA00BF27FD}") or a ProgID (e.g. "HostLW.HostLW.1").  Alternatively, Type may be "" to prompt the user for a control to load.
Example
This example loads a HostLW control into the OCEdit control named oced.
Dim hr As Long
hr = oced.NewControl("HostLW.HostLW.1")

OCEdit::OpenControl Method
Long OpenControl(String FileName)
Closes the currently-loaded control, if any, and loads a new control from a given file (.htm, .csv, or .stm).
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP
Return Value
Returns 1 if the user presses the Cancel button (if prompted). Otherwise returns a nonnegative HRESULT value on success, or a negative HRESULT on error.
Parameters
FileName
The name of the file to load, or "" to prompt for the name of a file to load.
Example
This example loads "c:\foo.htm" into the OCEdit control named oced.
Dim hr As Long
hr = oced.OpenControl("c:\foo.htm")

OCEdit::PromptToSaveControl Method
Long PromptToSaveControl()
Prompts the user to save the currently-loaded control (if the control was modified since it was last saved).
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP
Return Value
Returns 1 if the user presses the Cancel button.  Returns another nonnegative HRESULT success code if the loaded control didn't need saving, or if it did need saving but was successfully saved.  Returns a negative HRESULT on error.

OCEdit::SaveControl Method
Long SaveControl(String FileName)
Saves the currently-loaded control into a given file (.htm, .csv, or .stm).
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP
Return Value
Returns 1 if the user presses the Cancel button (if prompted). Otherwise returns a nonnegative HRESULT value on success, or a negative HRESULT on error.
Parameters
FileName
The name of the file to save to, or "" to prompt for the name of a file to save to.
Example
This example saves the control loaded into the OCEdit named oced into "c:\foo.htm".
Dim hr As Long
hr = oced.SaveControl("c:\foo.htm")

OCEdit::ShowControlProperties Method
Long ShowControlProperties()
Displays a property frame containing the property pages of the loaded control.
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP
Return Value
Returns a non-negative HRESULT code on success, or a negative HRESULT error code on error.

OCEdit::Version Property
Data Type
String
Description
Returns the version of the OCEdit control, as a string. Read-only.
Defined in: C:/DEV/MMCTL21/SRC/OCEDIT/OCEDCTL.CPP
Comments
Example of the value returned by the Version property: "1.00.0042", which indicates that the version of the OCEdit control is build 42 of version 1.0.

OpenMRUList
HRESULT OpenMRUList(int cMaxEntries, HKEY hKey, LPCTSTR pszSubkey, LPCTSTR pszListName) 
Opens a new or existing registry-based MRU list.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/MRU.CPP
Return Value
Returns a handle to the open MRU list if successful.  Returns NULL on failure.
Parameters
cMaxEntries
[in] The maximum number of entries in the list.
hKey
[in] The list will be opened at the registry path, hKey\pszSubkey\pszListName.
pszSubkey
[in] (See hKey.)
pszListName
[in] (See hKey.)
Comments
If the registry key contains more than cMaxEntries, it will be truncated to cMaxEntries. ---------------------------------------------------------------------------

PersistChild
HRESULT PersistChild(IVariantIO * pvio, LPCSTR szCollection, int iChild, LPUNKNOWN punkOuter, DWORD dwClsContext, LPUNKNOWN * ppunk, CLSID * pclsid, BOOL * pfSafeForScripting, BOOL * pfSafeForInitializing, DWORD dwFlags) 
Loads or saves a child of a given container object from/to a given. IVariantIO object.  Used to help implement persistence in control containers.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/PC.CPP
Parameters
pvio
The IVariantIO object to read properties from or write properties to.
szCollection
The name of the collection that the child object belongs to.  See PersistSiteProperties for more information about collections.
iChild
The index (into the collection named by szCollection) of the child object whose site properties are being persisted by this call to PersistSiteProperties.  Conventionally, indices are 1-based (i.e. the first child object in the collection is numbered 1, not 0). See PersistSiteProperties for more information.
punkOuter
The controlling unknown to use for the new child object, if the child object is loaded (i.e. if pvio is in loading mode and if a child object is successfully loaded).
dwClsContext
Specifies the context in which the executable is to be run. The values are taken from the enumeration CLSCTX. A typical value is CLSCTX_INPROC_SERVER.  This parameter is ignored unless if pvio is in loading mode and a child object is successfully loaded.
ppunk
A pointer to an LPUNKNOWN variable that currently contains (if pvio is in saving mode) or into which will be stored (if pvio is in loading mode) the pointer to the child control.
pclsid
Where to store the class ID of the child object, if pvio is in loading mode.  If pclsid is NULL then this information is not returned.  If pvio is in saving mode and pclsid is not NULL, then on entry *pclsid is assumed to contain the class ID of the child object (useful if the child object does not implement IPersist); if not specified, the class ID of the child is obtained by calling IPersist on the child.
pfSafeForScripting
If non-NULL, *pfSafeForScripting is set to TRUE or FALSE depending on whether the control is safe-for-scripting.
pfSafeForInitializing
If non-NULL, *pfSafeForInitializing is set to TRUE or FALSE depending on whether the control is safe-for-initializing.
dwFlags
Currently unused.  Must be set to 0.
Example
See PersistSiteProperties for an example of how PersistChild is used.

Return Codes
S_OK	Success.	
S_FALSE	pvio is in loading mode, and collection szCollection does not contain a child numbered iChild.  (This typically tells the container that it can stop trying to load children.)	

PersistSiteProperties
HRESULT PersistSiteProperties(IVariantIO * pvio, LPCSTR szCollection, int iChild, DWORD dwFlags, (varying) (arguments), HRESULT __cdecl PersistSiteProperties) 
Loads or saves a list of property name/value pairs associated with the site of the child of a given object from/to a given IVariantIO object.  Used to help implement persistence in control containers.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/PSP.CPP
Parameters
pvio
The IVariantIO object to read properties from or write properties to.
szCollection
The name of the collection that the child object belongs to.  The parent object may contain one or more collections of children; when children are accessed via IDispatch, they are conventionally addressed by indexing into the property array named by this index.  For example, if the parent contains a collection named "Mailboxes" (that contains a collection of child "Mailbox" objects), a VB script writer might access the first child in the collection using code like "parent.Mailboxes(1).NumLetters".  See Comments for more information.
iChild
The index (into the collection named by szCollection of the child object whose site properties are being persisted by this call to PersistSiteProperties.  Conventionally, indices are 1-based (i.e. the first child object in the collection is numbered 1, not 0).
dwFlags
Currently unused.  Must be set to 0.
(arguments)
The names, types, and pointers to variables containing the properties to persist.  These must consist of a series of argument triples (sets of 3 arguments) followed by a NULL. See IVariantIO::Persist for more information about the format of (arguments).
PersistSiteProperties
The site of a child object is the object maintained by the container that's associated with that specific child.  The site may have its own properties, logically associated with the child's properties by the user (or script writer), but implemented separatedly.  For example, the site may maintain a "Visible" property indicating whether or not the child is visible.
Note that PropertyHelper does not automatically implement IDispatch access to collections, but PersistSiteProperties will name the site properties according to a similer naming convention: e.g. if "NumLetters" is a site property of a "Mailbox" object, PersistSiteProperties saves the property under the name "Mailboxes(1).NumLetters".
Example
The following example persists two site properties (which in BASIC would be a Long and a String, respectively) named "Foo" and "Bar", respectively.  These site properties belong to the first child of the collection named "Controls".
PersistSiteProperties(pvio, "Controls", 1, 0,
	"Foo", VT_INT, &m_iFoo, "Bar", VT_LPSTR, &m_achBar, NULL);

The following example shows how a container control might implement IPersistVariantIO::DoPersist, assuming the container maintains an array m_apunkChild containing m_cChild IUnknown pointers that each point to a child object.  The array m_afVisible contains one BOOL value for each child object containing the value of the site property "Visible" for that child.  (Both arrays are 1-based, which means the zeroeth element is not used and the array has an extra element allocated at the end.)
STDMETHODIMP CMyControl::DoPersist(IVariantIO* pvio, DWORD dwFlags)
{
	// persist the container's own properties, "BackColor" and
	// "Rectangular"
	HRESULT hr;
	if (FAILED(hr = pvio->Persist(0,
			"BackColor", VT_INT, &m_rgb,
			"Rectangular", VT_BOOL, &m_fRect,
			NULL)))
		return hr;
	if (hr == S_OK)
		...one or more properties changed, so repaint etc. container...

	// loop once for each child object in collection "Controls"
	// (which is the container's only collection in this example);
	// if <pvio> is in loading mode, this loops once for each child
	// object whose data is stored in <pvio>
	for (iChild = 1;
		 (iChild <= m_cChild) || (IsLoading(pvio) == S_OK)
		 iChild++)
	{
		// persist the site properties of child number <iChild>
		if (FAILED(hr = PersistSiteProperties(pvio, "Controls", iChild,
				0, "Visible", VT_BOOL, m_afVisible + iChild, NULL)))
			return hr;
		if (hr == S_OK)
			...site property changed, so repaint etc. child...

		// persist the child: in saving mode this writes the
		// properties of the child to <pvio>; in loading mode this
		// loads the child control whose data is in <pvio> and
		// stores its IUnknown pointer in m_punkChild[iChild]
		if (FAILED(hr = PersistChild(pvio, "Controls", iChild, NULL,
				CLSCTX_INPROC_SERVER, m_apunkChild + iChild, NULL, 0)))
			return hr;
		if (hr == S_FALSE)
		{
			// we're in loading mode, but we finished loading the
			// last control in the "Controls" collection, so quit
			break;
		}
	}

	// clear the dirty bit if requested
	if (dwFlags & PVIO_CLEARDIRTY)
		m_fDirty = FALSE;

	return S_OK;
}

Return Codes
S_OK	Success.  At least one of the variables listed in (arguments) was written to, so the control may want to update itself accordingly.	
S_FALSE	None of the variables listed in (arguments) were written to (either because the IVariantIO object is in saving mode or because none of the properties named in (arguments) exist in the IVariantIO object.	
DISP_E_BADVARTYPE	One of the VARTYPE values in (arguments) is invalid.	
DISP_E_TYPEMISMATCH	One of the variables in (arguments) could not be coerced to the type of the corresponding property in the IVariantIO object, or vice versa.	
E_OUTOFMEMORY	Out of memory.	

PersistVariantIO
HRESULT PersistVariantIO(DWORD dwFlags, (varying) (arguments)) 
Loads or saves a list of property name/value pairs, specified as a variable-length list of arguments that's formatted in the same way as IVariantIO::Persist, to/from an IPropertyBag object.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/PVIO.CPP
Parameters
dwFlags
May contain the same flags passed to IManageVariantIO::SetMode (e.g. VIO_ISLOADING).
(arguments)
The names, types, and pointers to variables containing the properties to persist.  These must consist of a series of argument triples (sets of 3 arguments) followed by a NULL. See IVariantIO::Persist for information about the format of these arguments.
Return Codes
S_OK	Success.  At least one of the variables listed in (arguments) was written to, so the control may want to update itself accordingly.	
S_FALSE	None of the variables listed in (arguments) were written to (either because the IVariantIO object is in saving mode or because none of the properties named in (arguments) exist in the IVariantIO object.	
DISP_E_BADVARTYPE	One of the VARTYPE values in (arguments) is invalid.	
DISP_E_TYPEMISMATCH	One of the variables in (arguments) could not be coerced to the type of the corresponding property in the IVariantIO object, or vice versa.	
E_OUTOFMEMORY	Out of memory.	

PersistVariantIOList
HRESULT PersistVariantIOList(DWORD dwFlags, va_list args) 
Loads or saves a list of property name/value pairs, specified as a va_list array that's formatted in the same way as IVariantIO::Persist, to/from an IPropertyBag object.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/PVIOL.CPP
Parameters
dwFlags
May contain the same flags passed to IManageVariantIO::SetMode (e.g. VIO_ISLOADING).
args
The arguments to pass.  See IVariantIO::Persist for information about the organization of these arguments.
Return Codes
S_OK	Success.  At least one of the variables listed in args was written to, so the control may want to update itself accordingly.	
S_FALSE	None of the variables listed in args were written to (either because the IVariantIO object is in saving mode or because none of the properties named in args exist in the IVariantIO object).	
DISP_E_BADVARTYPE	One of the VARTYPE values in args is invalid.	
DISP_E_TYPEMISMATCH	One of the variables in args could not be coerced to the type of the corresponding property in the IVariantIO object, or vice versa.	
E_OUTOFMEMORY	Out of memory.	

PickClass
HRESULT PickClass(HINSTANCE hInstance, UINT residDialogTitle, UINT cCategories, const CATID[] rgCategories, CLSID* pclsid) 
Displays a modal "class picker" dialog which lists all the registered classes which support a given set of component categories and lets the user choose one, returning its CLSID.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/PICKCLS.CPP
Parameters
hInstance
[in] The handle of the instance which owns residDialogTitle. May be NULL only if residDialogTitle is 0.
residDialogTitle
[in] The ID of a string resource to be used as the the dialog box's title.  If 0, the default title, "Insert Object", is displayed.
cCategories
[in] The number of categories in rgCategories.  Must be non-zero.
rgCategories
[in] An array of cCategories component category IDs.  The dialog will display the friendly names of all registered classes which implement all of the categories.  May not be NULL.
pclsid
[out] If the function is successful, pclsid is set to the class ID of the selected class.  On entry, pclsid may not be NULL.
Comments
To make use of this function, you must include ochelp.rc into your project\'s resource file.  To do this from within Developer Studio, select the menu item, View | "Resource Includes", and add #include "..\ocmisc\ocmisc.rc" to the "Compile-time directives". (The path may be different depending on where your project is located relative to ocmisc.)
This functions makes the following assumptions about the state of the system registry:
—	A registered class might have one or more keys of the form: HKEY_CLASSES_ROOT\CLSID\{clsid}\Implemented Categories\{catid}. If a class has this key it signifies that the class with CLSID {clsid} implements the component category with CATID {catid}.
—	Such a class will also have a key: HKEY_CLASSES_ROOT\CLSID\{clsid}\ProgID, the value of which is the class' programmatic identifier.  There will also be a key: HKEY_CLASSES_ROOT\{progid} matching the class' ProgID, the value of which is the "friendly name" for the class.
—	Each class that implements all the rgCategories must also have a ProgID and a friendly name or else it will not be displayed in the class picker dialog.
Example
Here's a typical usage scenario:
const int c_cCategories = 3;
CLSID clsid;
HRESULT hResult;
LPUNKNOWN pUnknown;
CATID rgCategories[c_cCategories];
rgCategories[0] = CATID_Insertable;
rgCategories[1] = CATID_Control;
rgCategories[2] = CATID_MMControl;

if (SUCCEEDED(PickClass(hInstance,
						IDS_CLASS_PICKER_TITLE,
						c_cCategories,
						rgCategories,
						&clsid)))
{
	hResult = CoCreateInstance(clsid,
							   NULL,
							   CLSCTX_INPROC_SERVER,
							   IID_IUnknown,
							   (void**)pUnknown);
	if (SUCCEEDED(hResult))
	{
		//...
	}
}
---------------------------------------------------------------------------

Return Codes
S_OK	Success.  pclsid is set to the selected class ID.	
(other)	Failure.  A variety of failures are possible: the user did not select a class, no registered classes implemented all specified categories, out of memory, etc.	

PixelsToHIMETRIC
void PixelsToHIMETRIC(int cx, int cy, SIZE * psize) 
Converts a width and height from pixels (on the default monitor) to HIMETRIC units.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/HIMETRIC.CPP
Parameters
cx
The input width in pixels.
cy
The input height in pixels.
psize
The output size in HIMETRIC units.

PrintableANSIToUNICODE
int PrintableANSIToUNICODE(LPWSTR pwchDst, LPCSTR pchSrc, int cwchDstMax, LPCSTR * ppchSrcEnd, DWORD dwFlags) 
Converts a printable ANSI string to UNICODE.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/PATU.CPP
Return Value
If the function succeeds, and cwchDstMax is nonzero, the return value is the number of wide characters (including the terminating null wide character) written to the buffer pointed to by pwchDst.  If the function succeeds, and cwchDstMax is zero, the return value is the required size, in wide characters, for a buffer that can receive the translated string.  If the function fails, the return value is 0.
Parameters
pwchDst
The buffer that will hold the output UNICODE string.
pchSrc
The input ANSI string.
cwchDstMax
The capacity of pwchDst (in wide characters).
ppchSrcEnd
Where to store a pointer to the first character past the end of the printable ANSI string in pchSrc.  This character will be either a a carriage return, a line feed, a terminating null character, or one of the delimiter characters (see dwFlags).  If ppchSrcEnd is NULL, then this information is not returned.
dwFlags
May contain the following flags:
PA_CSV
The string being read is a CSV (comma-separated variable) token.  The only delimiter character is ",".
PA_HTML
The string being read is an HTML token.  The delimiter characters are "=", " ", tab, "<", and ">".
Comments
See UNICODEToPrintableANSI for a definition of "printable ANSI string".  PrintableANSIToUNICODE reads a single string starting at location pchSrc, performing decoding as needed (e.g. ignoring surrounding quotation marks, un-doubling doubled quotation and percent characters, and converting hexadecimal escape sequences to binary values); the resulting string (which may contain embedded null characters) is stored in pwchDst.

PropertyBagCompactor Object
Description
Implements an IPropertyBag that reads and writes its data in a more compact way in a second IPropertyBag by "folding" multiple properties with the same period-terminated prefix (e.g. "Foo.X = 42, Foo.Y = 'Hello'") into a single property (e.g. "Foo = 'X=42,Y=Hello'").
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/APBC.CPP
Supported Interfaces
IPropertyBag
The interface to use to access the uncompacted properties.  When writing into this property bag, write a property with name and value equal to NULL in order to "flush" the compacted property bag (i.e. complete writing its contents).
Comments
Use AllocPropertyBagCompactor to create a PropertyBagCompactor object.

PropertyBagOnStream Object
Description
Implements IPropertyBag whose properties are contained in a given IStream.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/APBOS.CPP
Supported Interfaces
IPropertyBag
The interface to use to access the properties stored in the given IStream.
Comments
Use AllocPropertyBagOnStream to create a PropertyBagOnStream object.
See VariantPropertyHeader for a description of the format of the data in the IStream.

PropertyBagOnVariantProperty Object
Description
Implements IPropertyBag whose only property is contained in a given VariantProperty.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/APBOVP.CPP
Supported Interfaces
IPropertyBag
The interface to use to access the single property stored in the given VariantProperty.
Comments
Use AllocPropertyBagOnVariantProperty to create a PropertyBagOnVariantProperty object.

PropertyHelper Object
Description
Provides an implementation of Persist, IPersistPropertyBag, IPersistStream, IPersistStreamInit, and a simplified implementation of IDispatch, for any object which implements IPersistVariantIO.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/APH.CPP
Supported Interfaces
IPersistPropertyBag
Loads or saves properties from/to a given IPropertyBag object.  Used to provide a textual representation of the data of the object that implements IPersistVariantIO.
IPersistStream
Loads or saves the data of the object that implements IPersistVariantIO as a stream of bytes.
IPersistStreamInit
Like IPersistStream, but with an extra method that allows the object to be created in a "newly initialized" state.
IDispatch
Provides script engines etc. access to the properties exposed by the IPersistVariantIO.  This IDispatch implementation isn't particularly fast, but it's an inexpensive way for a control to provide a rudimentary IDispatch implementation.
Comments
Use AllocPropertyHelper to create a PropertyHelper object.

PropPageHelper Object
Description
Implements IPropertyPage.  Designed to be aggregated by an object that wants to provide a specific propery page implementation.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/PROPHELP.CPP
Supported Interfaces
IPropertyPage
Standard OLE property page implementation.  The information about the property page is maintained in a PropPageHelperInfo structure that's allocated by the aggregator and shared with PropPageHelper.
Comments
See AllocPropPageHelper for more information.

ReadHTMLTagToVariantIO
HRESULT ReadHTMLTagToVariantIO(LPSTR * ppchTag, IManageVariantIO * * ppmvio, DWORD dwFlags) 
Reads an HTML tag from a memory buffer and returns an VariantIO object that contains the contents of that tag.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/RHTMLTAG.CPP
Parameters
ppchTag
Points to a variable to read the HTML tag from. On entry, *ppchTag should point to the "<" character that starts the tag.  On exit, *ppchTag will point to the character after the ">" character that ends the tag.  (Or, *ppchTag will point to a null character if a null is encountered before the closing ">" character.)
ppmvio
Where to store a pointer to the allocated VariantIO object.  NULL is stored in *ppmvio on error.
dwFlags
Currently unused.  Must be set to 0.

ReadHTMLToken
HRESULT ReadHTMLToken(LPCSTR pchSrc, LPCSTR * ppchSrcEnd, BSTR * pbstr) 
Reads an HTML token (word, quoted string, etc.) from an ANSI buffer and returns it as a BSTR.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/RHTMLTOK.CPP
Parameters
pchSrc
The input ANSI string.
ppchSrcEnd
Where to store a pointer to the first character past the end of the printable ANSI string in pchSrc.  If ppchSrcEnd is NULL, then this information is not returned.
pbstr
Where to store a pointer to the allocated string containing the token's value.  The string is allocated by this function, but must be freed by the caller using SysFreeString.
Comments
An HTML token is defined as a sequence of nonblank characters not including "=", ">", or white space (except that the token may be surrounded by double quotation marks).

ReadStreamToMemory
HRESULT ReadStreamToMemory(IStream * pstream, int cch, char * * ppchBuf) 
Read bytes from a stream into memory (which is allocated by this function).  Reads either a given number of bytes or until the end of the stream.  The returned block of memory is null-terminated.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/RSTM.CPP
Parameters
pstream
The stream to read from.
cch
The number of bytes to read in pstream.  If cch is -1, then pstream is read to its end.
ppchBuf
Where to store a pointer to the returned block of memory.  NULL is stored in *ppchBuf on error.

ReadVariantProperty
HRESULT ReadVariantProperty(IStream * pstream, VariantProperty * pvp, DWORD dwFlags) 
Reads a VariantProperty from an IStream in a simple tagged binary format.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/RVP.CPP
Parameters
pstream
The stream to read from.
pvp
Where to store the property name/value pair that's read in.  Any unknown records in pstream are automatically skipped.
dwFlags
Currently unused.  Must be set to 0.
Comments
See VariantPropertyHeader for a description of the format of the data read from pstream by this function.
Return Codes
S_OK	Success.	
S_FALSE	The end-of-stream marker was read in.  (This is the data that's written using WriteVariantProperty with NULL pvp.)	

ReadVariantPropertyFromCSV
HRESULT ReadVariantPropertyFromCSV(LPCSTR pch, VariantProperty * pvp, LPCSTR * ppchEnd, DWORD dwFlags) 
Reads a VariantProperty that's stored in CSV (Excel-readable comma-delimited) format in a memory buffer.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/RVPFCSV.CPP
Parameters
pch
The buffer to read from.
pvp
Where to store the property name/value pair. *pvp need not be initialized on entry.
ppchEnd
Where to store the pointer to the end of the line (that begins with pch).  On exit, *ppchEnd will point to the character past the carriage return and/or line feed, to the beginning of the next line (or the terminating null).  If ppchEnd is NULL then this information is not returned.
dwFlags
Currently unused.  Must be set to 0.

RegDeleteTree
LONG RegDeleteTree(HKEY hParentKey, LPCTSTR szKeyName) 
Delete a registry key and all its subkeys (i.e., its "tree").
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/REG.CPP
Parameters
hParentKey
[in] The parent key of the the key to delete.  May not be NULL.
szKeyName
[in] The name of the key at the top of the tree to delete.  May not be NULL.  Assumed to be a subkey of hParentKey.
Comments
This function is almost identical to the Win32 API, RegDeleteKey.  However, RegDeleteKey only deletes the key and its subkeys under Win95, not WinNT. ---------------------------------------------------------------------------
Return Codes
ERROR_SUCCESS	Success.	
ERROR_CANTOPEN	Failure.  The key hParentKey\szKeyName couldn't be opened (probably because it doesn't exist).	
(other)	Failure.  An error occurred while deleting keys.	

RegisterControls
HRESULT RegisterControls(ICatRegister* pCatReg, ControlInfo * pctlinfo, DWORD dwAction) 
Registers or unregisters one or more controls.  Helps implement DllRegisterServer and DllUnregisterServer.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/REG.CPP
Parameters
pCatReg
A component category registration manager.  Used to register or unregister the various component categories specified for the control via pctlinfo.  Can't be NULL.
pctlinfo
Information about the control that's being registered or unregistered.  See ControlInfo for more information.
dwAction
May be one of the following:
RC_REGISTER
Registers the control.
RC_UNREGISTER
Unregisters the control.
Comments
You can register more than one control by making a linked list out of your ControlInfo structures -- set each pNext field to the next structure, and set the last pNext to NULL.
All controls which are registered by this function are registered as "safe for scripting" and "safe for initializing".
Example
The following example shows how to implement DllRegisterServer and DllUnregisterServer using RegisterControls.
STDAPI DllRegisterServer(void)
{
	return RegisterControls(&g_ctlinfo, RC_REGISTER);
}

STDAPI DllUnregisterServer(void)
{
	return RegisterControls(&g_ctlinfo, RC_UNREGISTER);
}

Return Codes
S_OK	Success.	
E_FAIL	The operation failed.	

RemoveAllMRUListEntries
HRESULT RemoveAllMRUListEntries(HMRULIST hMRUList) 
Removes all the entries in an MRU list.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/MRU.CPP
Parameters
hMRUList
[in] A handle to a previously opened MRU list.
Comments
Removes all the registry entries.  Automatically calls ResetMRUList. ---------------------------------------------------------------------------
Return Codes
S_OK	Success.	
(other)	Failure.	

RemoveIthMRUListEntry
HRESULT RemoveIthMRUListEntry(HMRULIST hMRUList, int iEntry) 
Removes an MRU list entry by index.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/MRU.CPP
Parameters
hMRUList
[in] A handle to a previously opened MRU list.
iEntry
The 0-based index of the entry to remove.
Return Codes
S_OK	Success.	
(other)	Failure. ---------------------------------------------------------------------------	

RemoveMRUListEntry
HRESULT RemoveMRUListEntry(HMRULIST hMRUList, const TCHAR* szEntry) 
Removes an MRU list entry by name.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/MRU.CPP
Parameters
hMRUList
[in] A handle to a previously opened MRU list.
szEntry
The name of the entry to remove.  If NULL, nothing happens.
Return Codes
S_OK	Success.	
(other)	Failure. ---------------------------------------------------------------------------	

ResetMRUList
HRESULT ResetMRUList(HMRULIST hMRUList) 
Resets an MRU list so that the next call to GetNextMRUListEntry will retrieve the first entry.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/MRU.CPP
Parameters
hMRUList
[in] A handle to a previously opened MRU list.
Return Codes
S_OK	Success. ---------------------------------------------------------------------------	

SaveToCSV
HRESULT SaveToCSV(IStream * pstream, CLSID * pclsid, IPersistPropertyBag * pppb, DWORD dwFlags) 
Save an object that supports IPersistPropertyBag to an IStream in CSV (Excel-readable comma-delimited) format. Can also be used to save just a class ID to a stream (which is useful for saving an object that doesn't support any persistence interface).
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/STCSV.CPP
Parameters
pstream
The stream to write to.
pclsid
The class ID to save to the stream. If pclsid is NULL then the class ID is obtained from pppb (by calling IPerist::GetClassID, assuming pppb is not also NULL).
pppb
The object to save.  If pppb is NULL, then only the class ID *pclsid (if pclsid is not NULL) is saved to the stream.
dwFlags
Currently unused.  Must be set to 0.

SaveToHTML
HRESULT SaveToHTML(IStream * pstream, CLSID * pclsid, IPersistPropertyBag * pppb, LPCSTR szPage, DWORD dwFlags) 
Saves an object that supports IPersistPropertyBag to an IStream in HTML format.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/STHTML.CPP
Parameters
pstream
The stream to write to.
pclsid
The class ID to save to the stream. If pclsid is NULL then the class ID is obtained from pppb (by calling IPerist::GetClassID, assuming pppb is not also NULL).
pppb
The object to save.  If pppb is NULL, then only the class ID *pclsid (if pclsid is not NULL)
szPage
An HTML file (perhaps returned by a previous call to LoadFromHTML) to use as a "template".  The HTML file that is written to pstream is the same as this file, except that the <OBJECT> tag is replaced by the object specified by pppb.
dwFlags
Currently unused.  Must be set to 0.
Comments
If szPage contains multiple <OBJECT> tags, the same rules specified in LoadFromHTML are used to determine which <OBJECT> tag is replaced by pppb.

SaveToStream
HRESULT SaveToStream(IStream * pstream, CLSID * pclsid, IPersistStream * pps, DWORD dwFlags) 
Save an object that supports IPersistStream to an IStream in a simple binary tagged file format. Can also be used to save just a class ID to a stream (which is useful for saving an object that doesn't support any persistence interface).
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/STS.CPP
Parameters
pstream
The stream to write to.
pclsid
The class ID to save to the stream. If pclsid is NULL then the class ID is obtained from pps (by calling IPerist::GetClassID, assuming pps is not also NULL).
pps
The object to save.  If pps is NULL, then only the class ID *pclsid (if pclsid is not NULL) is saved to the stream.
dwFlags
Currently unused.  Must be set to 0.

SaveVariantPropertiesToCSV
HRESULT SaveVariantPropertiesToCSV(IStream * pstream, IEnumVariantProperty * pevp, DWORD dwFlags) 
Save an IEnumVariantProperty object to an IStream in CSV (Excel-readable comma-delimited) format.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/SVPTCSV.CPP
Parameters
pstream
The stream to write to.
pevp
The property bag to save.
dwFlags
Currently unused.  Must be set to 0.
Return Codes
S_OK	Success.	
E_FAIL	I/O error.	

SaveVariantPropertiesToHTML
HRESULT SaveVariantPropertiesToHTML(IStream * pstream, IEnumVariantProperty * pevp, LPCSTR szPage, DWORD dwFlags) 
Saves an IEnumVariantProperty object to an IStream in HTML format.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/SVPTHTML.CPP
Parameters
pstream
The stream to write to.
pevp
The property bag to save.
szPage
An HTML file (perhaps returned by a previous call to LoadFromHTML) to use as a "template".  See SaveToHTML for more information about this parameter.
dwFlags
Currently unused.  Must be set to 0.
Return Codes
S_OK	Success.	
E_FAIL	I/O error.	

SetMRUListMaxEntries
HRESULT SetMRUListMaxEntries(HMRULIST hMRUList, int cMaxEntries) 
Sets the maximum number of entries in an MRU list, possibly truncating the list.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/MRU.CPP
Parameters
hMRUList
[in] A handle to a previously opened MRU list.
cMaxEntries
[in] The maximum number of entries allowed in the list.  Must be greater than 0 and less than 999.
Comments
If cMaxEntries is less than the number of entries currently in the list, any excess entries will be removed from the list. ---------------------------------------------------------------------------
Return Codes
S_OK	Success.	

SiteLW Object
Description
Implements ISiteLW, which implements an ActiveX windowed control that hosts an ActiveX lightweight windowless control.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/ASLW.CPP
Supported Interfaces
ISiteLW
Provides functions to manipulate the site object.
Comments
Use AllocSiteLW to create a SiteLW object.

SiteWL Object
Description
For each embedded control, the Stage control maintains a SiteWL object ("Site WindowLess" that provides additional properties and methods for the embedded control.  SiteWL is not directly accessible. SiteWL should not be confused with SiteLW.
Defined in: C:/DEV/MMCTL21/AUTODOC/SITEWL.D
Properties
int Width
Width of the control.
int Height
Height of the control.
int Left
X offset of the top left corner of the control from the top left corner of the Stage.
int Top
Y offset of the top left corner of the control from the top left corner of the Stage.
int Z
Z order of the control.  Higher Zs are further toward the back.  Z can be negative.
BOOL Visible
Whether the control is visible.
LPSTR Name
Name of the control.  New controls are automatically assigned unique names.  The current limit on name length is 31 characters, not including a terminating NULL.
BSTR Tag
Control tag.  The tag can be used to store user data.
int Cursor
ID of the cursor that is shown when the mouse is over the object.  The ID can be any of the OCR_* values in winuser.h.
Comments
For all users:
—	SiteWL currently supports many other animation-related properties and methods for demonstration purposes only. The functionality provided by these properties will eventually be moved to a separate control.  If you wish to use these properties before then, please see the demos in the mmctl\demo directory or contact MikeVK.

Sprite Object
Description
A lightweight windowless ActiveX control which displays a bitmap.  The bitmap may contain multiple "frames", in which case the Sprite can "animate" by cycling between its frames.
The Sprite may be transparent, translucent, or entirely opaque.  If translucent, the Sprite translucency can also be made to cycle as the Sprite steps from frame to frame.
The Sprite can also be made to rotate.  If a Sprite is set to rotate, only the first frame of its bitmap is displayed.
Defined in: C:/DEV/MMCTL21/AUTODOC/SPRITE.D
Properties
Integer NumFrames
The total number of frames in the bitmap. Must be at least 1.
Integer FramesAcross
The number of frames in each row of bitmap frames. Must be at least 1.
Integer FramesDown
The number of frames in each row of bitmap frames. Must be at least 1.
String BitmapPath
The file system path to the bitmap file. May be absolute or relative.
Boolean NotTransparent
Whether or not the Sprite is transparent.
True
The Sprite has no transparent sections.
False
The Sprite is transparent in those areas where it is colored with its 0th palette entry.
Integer InitTranslucency
The initial translucency value.  Must be between SPRITE_MIN_TRANS (transparent) and SPRITE_MAX_TRANS (opaque), and between MinTranslucency and MaxTranslucency.
Integer MinTranslucency
The minimum translucency value.  Must be between SPRITE_MIN_TRANS (transparent) and SPRITE_MAX_TRANS (opaque).
Integer MaxTranslucency
The maximum translucency value.  Must be between SPRITE_MIN_TRANS (transparent) and SPRITE_MAX_TRANS (opaque).
Integer TranslucencyStep
The change in translucency which occurs with every call to the Sprite's IAnimate::Tick method.  Must be between SPRITE_MIN_TRANSSTEP (slowest) and SPRITE_MAX_TRANSSTEP (fastest).
Integer TranslucencyBoundaryAction
What happens after the Sprite's translucency hits MinTranslucency or MaxTranslucency.  See SPRITE_BOUNDARYACTION for possible values.
Integer InitTranslucencyDelay
The delay in Sprite translucency stepping that occurs when the Sprite first appears. Measured in terms of the number of calls to the Sprite's IAnimate::Tick method. Must be between SPRITE_MIN_TRANSDELAY (no delay) and SPRITE_MAX_TRANSDELAY (longest delay).
Integer TranslucencyDelayAtMin
The delay in Sprite translucency stepping that occurs when the Sprite hits its minimum translucency.  Measured in terms of the number of calls to the Sprite's IAnimate::Tick method.  Must be between SPRITE_MIN_TRANSDELAY (no delay) and SPRITE_MAX_TRANSDELAY (longest delay).
Integer TranslucencyDelayAtMax
The delay in Sprite translucency stepping that occurs when the Sprite hits its maximum translucency.  Measured in terms of the number of calls to the Sprite's IAnimate::Tick method.  Must be between SPRITE_MIN_TRANSDELAY (no delay) and SPRITE_MAX_TRANSDELAY (longest delay).
Integer RotationType
How the Sprite will rotate when animated.  See SPRITE_ROTATION_TYPE for possible values.
Integer InitRotation
The Sprite's initial rotation.  Ignored if RotationType is SPRITE_ROT_NONE.  Must be between SPRITE_MIN_ROT and SPRITE_MAX_ROT.
Integer MinRotation
The Sprite's minimum rotation.  Ignored if RotationType is SPRITE_ROT_NONE.  Must be between SPRITE_MIN_ROT and SPRITE_MAX_ROT.
Integer MaxRotation
The Sprite's maximum rotation.  Ignored if RotationType is SPRITE_ROT_NONE.  Must be between SPRITE_MIN_ROT and SPRITE_MAX_ROT.
Integer RotationStep
The change in rotation which occurs with every call to the Sprite's IAnimate::Tick method.  Must be between SPRITE_MIN_ROTSTEP (slowest) and SPRITE_MAX_ROTSTEP (fastest).
Integer RotationBoundaryAction
What happens after the Sprite's rotation hits MinRotation or MaxRotation.  See SPRITE_BOUNDARYACTION for possible values.
Integer InitRotationDelay
The delay in Sprite rotation stepping that occurs when the Sprite first appears. Measured in terms of the number of calls to the Sprite's IAnimate::Tick method. Must be between SPRITE_MIN_ROTDELAY (no delay) and SPRITE_MAX_ROTSDELAY (longest delay).
Integer RotationDelayAtMin
The delay in Sprite rotation stepping that occurs when the Sprite hits its minimum rotation.  Measured in terms of the number of calls to the Sprite's IAnimate::Tick method.  Must be between SPRITE_MIN_ROTDELAY (no delay) and SPRITE_MAX_ROTSDELAY (longest delay).
Integer RotationDelayAtMax
The delay in Sprite rotation stepping that occurs when the Sprite hits its maximum rotation.  Measured in terms of the number of calls to the Sprite's IAnimate::Tick method.  Must be between SPRITE_MIN_ROTDELAY (no delay) and SPRITE_MAX_ROTSDELAY (longest delay).
Integer X1
The x-coordinate of the first vertex of an arbitrary quadrangle in which to draw the Sprite.  If any of the coordinates in the four quadrangle vertices (X1,Y1), (X2,Y2), (X3,Y3), or (X4,Y4) is non-zero, the Sprite will be drawn using quadrangle BLT-ing, ignoring any translucency or rotation settings.
Integer Y1
The y-coordinate of the first vertex of an arbitrary quadrangle in which to draw the Sprite.  See X1 for more information.
Integer X2
The x-coordinate of the second vertex of an arbitrary quadrangle in which to draw the Sprite.  See X1 for more information.
Integer Y2
The y-coordinate of the second vertex of an arbitrary quadrangle in which to draw the Sprite.  See X1 for more information.
Integer X3
The x-coordinate of the third vertex of an arbitrary quadrangle in which to draw the Sprite.  See X1 for more information.
Integer Y3
The y-coordinate of the third vertex of an arbitrary quadrangle in which to draw the Sprite.  See X1 for more information.
Integer X4
The x-coordinate of the fourth vertex of an arbitrary quadrangle in which to draw the Sprite.  See X1 for more information.
Integer Y4
The y-coordinate of the fourth vertex of an arbitrary quadrangle in which to draw the Sprite.  See X1 for more information.
Methods
 SizeToContent
Set the Sprite's bounding rectangle to the same size as any frame in the Sprite's underlying bitmap.
Comments
For all users:
—	This control cannot be directly embedded in IE3, since IE3 does not support windowless controls.  Instead, embed the HostLW control in IE3, and then embed this control into the HostLW control.
—	This control is packaged in both design-time and run-time versions. The design time version provides a property page for editing all the control's properties.
The run-time version eliminates the property pages (in order to reduce code size).
—	The class ID of the design-time version of this control is "40DA82E1-70FE-11CF-92F8-00AA00613BF1".
—	The class ID of the run-time version of this control is "TBD (currently the same as the design-time version)".
For C++ users:
—	The class ID of this control is defined as CLSID_CSpriteControl in "csprite.h".
—	The ProgID of this control is "Sprite.Sprite.3".
—	This control implements the following interfaces:
—	IUnknown: A delegating IUnknown that supports aggregation
—	ISprite: Provides low-level efficient access to the properties of a Sprite control.  See that interface for more information.
—	IViewObjectEx subset (based on IViewObject and IViewObject2): Used to display the object. DVASPECT_CONTENT is the only supported aspect.  Freeze, Unfreeze, GetRect, GetViewStatus, QueryHitRect, and GetNaturalExtent are not implemented.
—	IOleObject subset: Used to allow the container to provide the client site pointer, invoke control verbs, and get control state.  Only SetClientSite, DoVerb, EnumVerbs (design time version only), and GetMiscStatus are implemented.
—	IOleInPlaceObjectWindowless subset (based on IOleWindow and IOleInPlaceObject): Used to change control state and pass window messages to the control.  Only UIDeactivate, SetObjectRects, and OnWindowMessage are implemented.
—	IOleControl subset: Used to inform the control of ambient property changes.  Only OnAmbientPropertyChange is implemented.
—	ISpecifyPropertyPages: Used to retrieve information about the control's property page.  GetPages is implemented only in the design time version.
—	IPersistStreamInit (based on IPersistStream): Used to persist the control's data to/from an IStream. The file format is compatible with past and future versions of this control (i.e. adding and removing properties won't break the control).
—	IPersistPropertyBag: Used to persist the control's data to/from an IPropertyBag.
—	IAnimate: Used to control which frame of the bitmap is displayed.
—	ISprite: Provides a vtable mechanism for getting and setting Sprite properties.
—	IPersistVariantIO: Used to persist Sprite properties and to get and set persistable properties via OLE automation.
—	IServiceProvider: Used to pass service requests (via QueryService to Sprite's client site.
—	IOleCommandTarget: Used to stop the Sprite if it is in the middle of loading.
—	IDispatch: Used to implement non-persistable properties and methods.
—	This control sources (calls) the following interfaces (if available) on the container-provided site object:
—	IOleClientSite: The client site pointer provided by the container.
—	IOleInPlaceSiteWindowless: Used to request that the control's position be changed, acquire mouse capture, invalidate and update the display of the control, and (at design time only) draw XOR'd image of the control during dragging.
—	IDispatch: Used to access ambient properties (currently DISPID_AMBIENT_USERMODE).
—	IAdviseSink (provided via IViewObject::SetAdvise: Used to advise the container that the palette of the control changed.

Stage Object
Description
A lightweight windowless ActiveX control which is itself a container for lightweight windowless controls.
Defined in: C:/DEV/MMCTL21/AUTODOC/STAGE.D
Properties
Boolean Transparent
True if the stage is transparent (i.e. you can see through it to any controls or background underneath), False if the stage is opaque (in which case the color is BackColor). This doesn't affect the controls within the stage.
Long BorderColor
The background color of the stage, expressed as a standard 24-bit RGB value.  BorderColor is ignored if Transparent is True.
Long Count
The number of "Players" (controls) contained in the Stage.  Read-only.
Comments
For all users:
—	The controls contained within the Stage are accessible via OLE Automation.  See the "For VBS Users" section for details.
—	Currently Stage provides animation functionality for demonstration purposes only
—	This control cannot be directly embedded in IE3, since IE3 does not support windowless controls.  Instead, embed the HostLW control in IE3, and then embed this control into the HostLW control.
—	Stage is packaged in both design-time and run-time versions. The design time version allows controls to be embedded in Stage using the right-click context menu.  Various property pages are provided for editing most properties, including "site" properties which are implemented by Stage but maintained separately by SiteWL for each embedded control.
—	To change the background color while authoring, select the control and press "c".
—	Stage fires an event to the container whenever a contained control is clicked.  The event parameters include object-relative X and Y coordinates of the click location.  See the notify.htm sample in the mmctl\demo directory for details.  Stage also supports MouseEnter, MouseLeave, MouseUp, and MouseDown events. See input.htm for examples.
—	Stage also supports Tick and EdgeAction events; see notify.htm, and note that the way these events are supported may change.
The run-time version drops editing features (most notably the property page) in order to reduce code size.
—	The class ID of the design-time version of this control is "2E0E7F00-6F81-11CF-AB13-00AA00A437B1".
—	The class ID of the run-time version of this control is "TBD" (currently the same as the design-time version).
For VBS users:
—	Use the Players method to access a control by name; for example, "Stage1.Players("Sprite 2").
—	Use the Count property with the PlayerNum method to loop through all the controls in a Stage.  For an example, see vbstest.htm in the MM Controls demo directory. If you want to change the Z order of all controls, use a variation on that method:  Loop through the controls and assign each one to an object variable (probably in an array), and then loop through the array and set Z.
—	The numerical arguments to the PlayerNum method refer to Stage's own internal numbering of the controls.  This numbering may not be the same as the numbering you see in the HTML file when Stage writes out the properties of its embedded controls -- for example, "Players(1).Name=Tiny".  In this example, do not expect that you can use "PlayerNum(1)" to refer to the control named "Tiny". When you want to refer to a particular control, use the Players method with the control name, e.g. "Stage1.Players("Tiny").
—	You can use identical names at different levels of the containment hierarchy and distinguish them by providing a complete "path" to the name. For example, if you have one Stage nested inside another inside another, and all are named "Stage1", you can access the innermost one as "Stage1.Players("Stage 1").Players.("Stage 1"). If a name at a lower level of the hierarchy is unambiguous, you can access it directly from the top level.  For example, if a deeply nested control named "Banner Text" is uniquely named, you can access it as Stage1.Players("Banner Text").
For C++ users:
—	The class ID of this control is defined as CLSID_CStageOC in "Stage.h".
—	The ProgID of this control is "Stage.Stage.1".
—	This control implements the following interfaces:
—	IUnknown: A delegating IUnknown that supports aggregation
—	IStage: Provides low-level efficient access to the properties of a Stage control.  See that interface for more information.  [TBD]
—	IViewObjectEx subset (based on IViewObject and IViewObject2): Used to display the object. DVASPECT_CONTENT is the only supported aspect.  Freeze, Unfreeze, GetRect, GetViewStatus, QueryHitRect, and GetNaturalExtent are not implemented.
—	IOleObject subset: Used to allow the container to provide the client site pointer, invoke control verbs, and get control state.  Only SetClientSite, DoVerb, EnumVerbs (design time version only), and GetMiscStatus are implemented.
—	IOleInPlaceObjectWindowless subset (based on IOleWindow and IOleInPlaceObject): Used to change control state and pass window messages to the control.  Only UIDeactivate, SetObjectRects, and OnWindowmessage, are implemented.
—	IOleControl subset: Used to inform the control of ambient property changes.  Only OnAmbientPropertyChange is implemented.
—	ISpecifyPropertyPages: Used to retrieve information about the control's property page.  GetPages is implemented only in the design time version.
—	IPersistStreamInit (based on IPersistStream): Used to persist the control's data to/from an IStream. The file format is compatible with past and future versions of this control (i.e. adding and removing properties won't break the control).
—	IPersistPropertyBag: Used to persist the control's data to/from an IPropertyBag.
—	IDispatch:  Provides access to the control's properties. Does not provide type information.
—	This control sources (calls) the following interfaces (if available) on the container-provided site object:
—	IOleClientSite: The client site pointer provided by the container.
—	IOleInPlaceSiteWindowless: Used to request that the control's position be changed, acquire mouse capture, invalidate and update the display of the control, and (at design time only) draw XOR'd image of the control during dragging.
—	IDispatch: Used to access ambient properties (currently DISPID_AMBIENT_USERMODE).
—	IAdviseSink (provided via IViewObject::SetAdvise: Used to advise the container that the palette of the control changed.

TaskMemAlloc
LPVOID TaskMemAlloc(ULONG cb) 
Allocates memory using the task memory allocator (see CoGetMalloc). This is simply a macro that calls HelpMemAlloc with specific flags.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/HELPMEM.CPP
Return Value
Returns a pointer to the allocated block of memory.  Returns NULL on error.
Parameters
cb
The number of bytes of memory to allocate.

TaskMemFree
void TaskMemFree(LPVOID pv) 
Frees a block of memory previously allocated using TaskMemAlloc. This is simply a macro that calls HelpMemFree with specific flags.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/HELPMEM.CPP
Parameters
pv
A pointer to the block of memory to allocate.

TCHARFromGUID
TCHAR* TCHARFromGUID(REFGUID guid, TCHAR* pszGUID, int cchMaxGUIDLen) 
Converts a GUID to a TCHAR-based string representation.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/GUID2TCH.CPP
Return Value
Returns an alias to pszGUID.
Parameters
guid
[in] The GUID to convert.
pszGUID
[out] The string form of the guid.  Can't be NULL.
cchMaxGUIDLen
[in] szGUID is, on entry, assumed to point to a buffer of at least cchMaxGUIDLen characters in length.  Must be greater at least 39.
Comments
Unlike StringFromGUID2 which always returns an OLECHAR form of the GUID string, this function returns a wide or single-byte form of the string depending on the build environment.
See Also
CLSIDFromTCHAR ---------------------------------------------------------------------------

TextFX Object
Description
A lightweight windowless ActiveX control that displays and animates text.
Defined in: C:/DEV/MMCTL21/AUTODOC/TEXTFX.D
Properties
LPSTR Text
Text displayed by the control.
COLORREF TextColor
Text color.
COLORREF BackColor
Background color.  Ignored if BackTransparent is TRUE.
BOOL BackTransparent
Whether background is transparent.
int BorderWidth
Border width.
int Angle
Angle (in degrees) at which the text is drawn.
DWORD FXFlags
Flags that determine what effects are used to display the text.  The only flag currently supported is FX_USEGUIDES. However, other effects such as rotation are available via other properties such as Angle.
(various) Font...
See Win32 doc for LOGFONT:  all LOGFONT fields are available as properties where "lf" is replaced by "Font" (e.g. FontHeight, FontFaceName, and so on).
int Guide...
(Guide[Top | Bot][X | Y][1 | 2 | 3 | 4]Now; for example, GuideBotY2Now).  Control points for Bezier guidelines that determine where text is drawn, if FX_USEGUIDES is set in FXFlags.  For example, GuideTopX1Now is the X coordinate of one endpoint of the top guideline.  The first and fourth points on each guideline are endpoints, and the second and third points are control points of the Bezier curve that defines the guideline.
Comments
For all users:
—	To change the text color while authoring, select the control and press "c" (or use the Font dialog available on the context menu).  To change the background color, select the control and press "C".
—	TextFX currently supports many other animation-related properties for demonstration purposes only.  The functionality provided by these properties will eventually be moved to a separate control.  If you wish to use these properties before then, please see the demos in the mmctl\demo directory or contact MikeVK.
For C++ users:
—	The class ID of this control is defined as CLSID_CTextFXOC in "textfx.h".
—	The ProgID of this control is "TextFX.TextFX.1".
—	This control implements the following interfaces:
—	IUnknown: A delegating IUnknown that supports aggregation
—	ITextFX: Provides low-level efficient access to the properties of a TextFX control.  See that interface for more information.  [TBD]
—	IViewObjectEx subset (based on IViewObject and IViewObject2): Used to display the object. DVASPECT_CONTENT is the only supported aspect.  Freeze, Unfreeze, GetRect, GetViewStatus, QueryHitRect, and GetNaturalExtent are not implemented.
—	IOleObject subset: Used to allow the container to provide the client site pointer, invoke control verbs, and get control state.  Only SetClientSite, DoVerb, EnumVerbs (design time version only), and GetMiscStatus are implemented.
—	IOleInPlaceObjectWindowless subset (based on IOleWindow and IOleInPlaceObject): Used to change control state and pass window messages to the control.  Only UIDeactivate, SetObjectRects, and OnWindowmessage, are implemented.
—	IOleControl subset: Used to inform the control of ambient property changes.  Only OnAmbientPropertyChange is implemented.
—	ISpecifyPropertyPages: Used to retrieve information about the control's property page.  GetPages is implemented only in the design time version.
—	IPersistStreamInit (based on IPersistStream): Used to persist the control's data to/from an IStream. The file format is compatible with past and future versions of this control (i.e. adding and removing properties won't break the control).
—	IPersistPropertyBag: Used to persist the control's data to/from an IPropertyBag.
—	IDispatch:  Provides access to the control's properties. Does not provide type information.
—	This control sources (calls) the following interfaces (if available) on the container-provided site object:
—	IOleClientSite: The client site pointer provided by the container.
—	IOleInPlaceSiteWindowless: Used to request that the control's position be changed, acquire mouse capture, invalidate and update the display of the control, and (at design time only) draw XOR'd image of the control during dragging.
—	IDispatch: Used to access ambient properties (currently DISPID_AMBIENT_USERMODE).
—	IAdviseSink (provided via IViewObject::SetAdvise: Used to advise the container that the palette of the control changed.

UNICODEConcat
void UNICODEConcat(wchar_t * wpchDst, const wchar_t * wpchSrc, int wcchDstMax) 
Concatenates one UNICODE string to another.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/UCAT.CPP
Parameters
wpchDst
Where to copy wpchSrc to.
wpchSrc
String to copy.
wcchDstMax
Capacity of wpchDst (in wide characters). If wcchDstMax is less than or equal to zero, this function does nothing.
Comments
Provided wcchDstMax greater than zero, wpchDst is always null-terminated.

UNICODECopy
void UNICODECopy(wchar_t * wpchDst, const wchar_t * wpchSrc, int wcchDstMax) 
Copies one UNICODE string to another.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/UCOPY.CPP
Parameters
wpchDst
Where to copy wpchSrc to.
wpchSrc
String to copy.
wcchDstMax
Capacity of wpchDst (in wide characters). If wcchDstMax is less than or equal to zero, this function does nothing.
Comments
Provided wcchDstMax greater than zero, wpchDst is always null-terminated.

UNICODEToANSI
int UNICODEToANSI(LPSTR pchDst, LPCWSTR pwchSrc, int cchDstMax) 
Converts a UNICODE string to ANSI.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/UNICODE.CPP
Parameters
pchDst
The buffer that will hold the output ANSI string.
pwchSrc
The input UNICODE string.
cchDstMax
The capacity of pchDst (in characters).

UNICODEToPrintableANSI
int UNICODEToPrintableANSI(LPSTR pchDst, LPCWSTR pwchSrc, int cchDstMax, int cchSrc, DWORD dwFlags) 
Converts a UNICODE string to a printable ANSI string.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/UTPA.CPP
Return Value
If the function succeeds, and cchDstMax is nonzero, the return value is the number of characters (including the terminating null) written to the buffer pointed to by pchDst.  If the function succeeds, and cchDstMax is zero, the return value is the required size, in bytes, for a buffer that can receive the translated string. If the function fails, the return value is 0.
Parameters
pchDst
The buffer that will hold the output ANSI string. pchDst should be NULL if cchDstMax is zero.
pwchSrc
The input UNICODE string.  If cchSrc is specified (i.e. is not -1), then pwchSrc may contain embedded null characters (which are each written out as "%00").
cchDstMax
The capacity of pchDst (in characters).
cchSrc
The length of pwchSrc (in wide characters). If cchSrc is -1, then pwchSrc is assumed to be null-terminated and the length is calculated automatically.
dwFlags
May contain the following flags.  Only one of PA_CSV or PA_HTML may be specified.
PA_CSV
The string being written is a CSV (comma-separated variable) token.
PA_HTML
The string being written is an HTML token.
Comments
The printable ANSI string stored in pchDst is compatible with the CSV (Excel-readable comma-delimited) format, i.e. the output string may be used as a field in a CSV file.  The output string is the same as the input string (converted to ANSI), but with the following processing applied:
—	If the string contains a double quotation mark '"', then the string is surrounded in double quotation marks. If PA_HTML is specified, then the string is quoted if it is empty (i.e. "") or contains any characters other than a-z, A-Z, 0-9, or dash "-" or underscore "_".  If PA_CSV is specified, then the string is quoted if it contains a comma ",".
—	Any double quotation mark '"', percent '%', or pipe '|' characters in the string are doubled (e.g. "%" becomes "%%").  Exception: '%' or '|' characters at the end of the string are not doubled.
—	Any nonprintable ANSI characters (in the range 0-255) are represented in hexadecimal with a percent character prefix (e.g. %07 represents character 7).  The hexadecimal number must contain exactly two digits.
—	Any nonprintable UNICODE characters (in the range 256-65535) are represented in hexadecimal with a pipe character prefix (e.g. |0123 represents character 0x123).  The hexadecimal number must contain exactly four digits.

UninitHelpAdvise
void UninitHelpAdvise(HelpAdviseInfo * pha) 
Peforms final cleanup of a HelpAdviseInfo structure, including releasing the IAdviseSink pointer if necessary.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/ADVISE.CPP
Parameters
pha
Caller-allocated structure that was previously initialized using InitHelpAdvise.
Comments
You must call InitHelpAdvise before calling HelpSetAdvise and HelpGetAdvise, and UninitHelpAdvise when the object that contains the HelpAdviseInfo structure is deleted.

VariantFromString
HRESULT VariantFromString(VARIANT * pvarDst, LPCTSTR szSrc) 
Initializes a VARIANT to contain the copy of an LPCTSTR string.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/DISPHELP.CPP
Parameters
pvarDst
A caller-supplied VARIANT structure to initialize.  The initial contents of pvarDst are ignored; the caller does not need to call VariantInit before calling VariantFromString.  Both pvarDst->vt and pvarDst->bstrVal are initialized by this function.
szSrc
The string to copy.  Can't be NULL.
Return Codes
S_OK	Success.	
E_OUTOFMEMORY	Out of memory.	

VariantIO Object
Description
Provides a property bag implementation which supports IPropertyBag as well as IVariantIO, IManageVariantIO, and IEnumVariantProperty.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/AVIO.CPP
Supported Interfaces
IPropertyBag
Allows properties to be read from and written to the VariantIO object.
IVariantIO
An alternative to IPropertyBag which allows the caller to implement property-based persistence with less code.
IManageVariantIO
Based on IVariantIO.  Allows the caller to control how the methods of IVariantIO operate (e.g. whether the IVariantIO is in loading mode or saving mode).
IEnumVariantProperty
Allows the caller to enumerate the properties that are currently in the VariantIO object.  Note that VariantIO does not implement IEnumVariantProperty::Clone.
Comments
Use AllocVariantIO to create a VariantIO object.

VariantIOOnPropertyBag Object
Description
Provides an implementation of IVariantIO (and IManageVariantIO) that operates on a given IPropertyBag.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/AVIOOPB.CPP
Supported Interfaces
IVariantIO
An alternative to IPropertyBag which allows the caller to implement property-based persistence with less code.
IManageVariantIO
Based on IVariantIO.  Allows the caller to control how the methods of IVariantIO operate (e.g. whether the IVariantIO is in loading mode or saving mode).  Note that VariantIOOnPropertyBag does not implement IManageVariantIO::DeleteAllProperties.
IPropertyBag
Provides access to the same IPropertyBag object that was given to AllocVariantIOOnPropertyBag as the IPropertyBag to operate on.
Comments
Use AllocVariantIOOnPropertyBag to create a VariantIOOnPropertyBag object.

VariantIOToMapDISPID Object
Description
Provides an implementation of IVariantIO which is used to map a property name to a DISPID (property number) or vice versa.  Can also be used to get or set the value of that property.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/AVIOTMD.CPP
Supported Interfaces
IVariantIO
Typically used as a parameter to IPersistVariantIO::DoPersist.
Comments
Use AllocVariantIOToMapDISPID to create a VariantIOToMapDISPID object.

VariantPropertyClear
void VariantPropertyClear(VariantProperty * pvp) 
Frees data maintained in a VariantProperty structure.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/VPC.CPP
Parameters
pvp
The structure to clear.
Comments
This function calls SysFreeString on pvp->bstrPropName and VariantClear on pvp->varValue.
Unlike VariantPropertyInit, this function does assume that pvp was correctly initialized before this function was called.

VariantPropertyInit
void VariantPropertyInit(VariantProperty * pvp) 
Initializes a VariantProperty structure.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/VPI.CPP
Parameters
pvp
The structure to initialize.
Comments
Unlike VariantPropertyClear, this function does not assume that pvp contained valid data on entry.

VariantTypeNameToNumber
VARTYPE VariantTypeNameToNumber(char * sz) 
Converts a VARTYPE string name to a VARTYPE number.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/VTNAME.CPP
Return Value
Returns the VARTYPE value identified by string name sz. On error, 0 (VT_EMPTY) is returned.
Parameters
sz
The VARTYPE string name.  The case of sz doesn't matter.
Comments
sz should contain the same string as the VT_ identifier name, but without the "VT_" (e.g. "I2" should stored in sz to indicate the type VT_I2).  If sz starts with a '#' character, then the following number is interpreted as a VARTYPE value.

VariantTypeNumberToName
void VariantTypeNumberToName(VARTYPE vt, char * pch) 
Converts a VARTYPE value to a string name that can serve as the name of the type.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/VTNUM.CPP
Parameters
vt
The type number to convert.
pch
A buffer to store the string name in.  This buffer should be large enough to hold _MAX_PATH characters.
Comments
If vt isn't a known type, then "#vt" (e.g "#42") is stored in pch.  Otherwise, what's stored in pch is the same as the VT_ identifier name, but without the "VT_" (e.g. "I2" is stored in pch if vt is VT_I2).

WriteHTMLTagFromVariantIO
HRESULT WriteHTMLTagFromVariantIO(IStream * pstream, IEnumVariantProperty * pevp, DWORD dwFlags) 
Writes an HTML tag whose attributes are stored in an VariantIO object to an IStream.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/WHTMLTAG.CPP
Parameters
pstream
The stream to write to.
pevp
An interface on the VariantIO object containing the attribute name/value pairs.  The tag name should be stored in pevp as the "_tag" property.
dwFlags
Currently unused.  Must be set to 0.

WriteHTMLToken
HRESULT WriteHTMLToken(IStream * pstream, LPLOLESTR wsz) 
Writes an HTML token (given as an LPOLESTR) to an IStream in ANSI format.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/WHTMLTOK.CPP
Parameters
pstream
The stream to write to.
wsz
The token to write.

WriteVariantProperty
HRESULT WriteVariantProperty(IStream * pstream, VariantProperty * pvp, DWORD dwFlags) 
Writes a VariantProperty to an IStream in a simple tagged binary format.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/WVP.CPP
Parameters
pstream
The stream to write to.
pvp
The property name/value pair to write. If pvp is NULL, then this function writes a VariantPropertyHeader containing iType==-1 and cbData==0 to mark the end of the stream.
dwFlags
Currently unused.  Must be set to 0.
Comments
See VariantPropertyHeader for a description of the format of the data written to pstream by this function.

WriteVariantPropertyToCSV
HRESULT WriteVariantPropertyToCSV(IStream * pstream, VariantProperty * pvp, DWORD dwFlags) 
Writes a VariantProperty to an IStream in CSV (Excel-readable comma-delimited) format.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/WVPTCSV.CPP
Parameters
pstream
The stream to write to.
pvp
The property name/value pair to write.
dwFlags
Currently unused.  Must be set to 0.
Comments
*pvp is written as a single line of text in the following format:
name,type,value
...where name is the property name, type is the type (a string returned by VariantTypeNumberToName), and value is the value (coerced to a string by VariantChangeType). Each of these three strings is processed by UNICODEToPrintableANSI before being written out.

WriteVariantPropertyToHTML
HRESULT WriteVariantPropertyToHTML(IStream * pstream, VariantProperty * pvp, DWORD dwFlags) 
Writes a VariantProperty to an IStream in HTML format as a "<PARAM>" tag.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/WVPTHTML.CPP
Parameters
pstream
The stream to write to.
pvp
The property name/value pair to write.
dwFlags
Currently unused.  Must be set to 0.
Comments
*pvp is written as a single line of text in the following format:
<PARAM name=name value=value>
...where name is the property name and value is the value (coerced to a string by VariantChangeType). Each of these three strings is processed by UNICODEToPrintableANSI before being written out.

ControlInfo Structure
typedef struct {
	UINT cbSize;
	LPCTSTR tszProgID;
	LPCTSTR tszFriendlyName;
	const CLSID * pclsid;
	HMODULE hmodDLL;
	LPCTSTR tszVersion;
	int iToolboxBitmapID;
	DWORD dwMiscStatusDefault;
	DWORD dwMiscStatusContent;
	GUID * pguidTypeLib;
	DWORD dwTypeLibFlags;
	AllocOCProc * pallocproc;
	ULONG * pcLock;
	DWORD dwFlags;
	ControlInfo* pNext;
	UINT uiVerbStrID;
} ControlInfo;

Contains information used by RegisterControls to register and unregister a control.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/REG.CPP
Members
cbSize
The size of this structure (used for version control).  Must be set to sizeof(ControlInfo).
tszProgID
The ProgID of the object, e.g. "MYCTLLIB.TinyCtl.1".
tszFriendlyName
The human-readable name of the object (at most 40 characters or so), e.g. "My Control".
pclsid
Points to the class ID of the object.
hmodDLL
The module handle of the DLL implementing the object.
tszVersion
The version number of the object, e.g. "1.0".
iToolboxBitmapID
The resource ID of the toolbox bitmap of the object, if the object is a control.  The resource must be located in the same DLL specified by tszDLLPath and/or hmodDLL. If iToolboxBitmapID is -1, it is ignored.
dwMiscStatusDefault
The MiscStatus bits (OLEMISC_XXX) to use for all display apsects except DVASPECT_CONTENT.  Typically 0.
dwMiscStatusContent
The MiscStatus bits (OLEMISC_XXX) to use for display aspect DVASPECT_CONTENT.  See the example below.
pguidTypeLib
The object's type library GUID, or NULL if the object doesn't have a type library.
dwTypeLibFlags
Type library flags.  I don't know what these are yet (they're registered as TypeLib\{guid}<version>\Flags), but 0 and 2 seem to be common values.  Ignored if pguidTypeLib is NULL.
pallocproc
Function which can allocate an instance of the OLE control and return an AddRef'd IUnknown pointer to it.
pcLock
Points to a DLL lock count variable defined as a global variable in your DLL.  This global variable maintains a count of locks used by IClassFactory::LockServer.  To increment or decrement this lock count, use InterlockedIncrement and InterlockedDecrement instead of modifying it directly.  This will ensure that access to the lock count is synchronized between your control's server and the OCHelp-supplied class factory.
dwFlags
Zero or more of the following:
CI_INSERTABLE
Marks the COM object as "Insertable".  Probably should not be used for ActiveX controls.
CI_CONTROL
Marks the COM object as a "Control".  Probably should not be used for ActiveX controls.
CI_MMCONTROL
Marks the COM object as a "Multimedia Control".
CI_SAFEFORSCRIPTING
Marks the COM object as "safe-for-scripting" meaning that the object promises that, no matter how malicious a script is, the object's automation model does not allow any harm to the user, either in the form of data corruption or security leaks. If a control is not "safe-for-scripting", the user will receive a warning dialog whenever the control is inserted on an untrusted page in Internet Explorer (IE), asking whether the object should be visible from scripts. (This is only at medium security level, at high security, the object is never visible to scripts, and at low, always visible.)  If a control, C1, can potentially contain another control, C2, which might be unsafe, then C1 should probably not declare itself "safe-for-scripting".
CI_SAFEFORINITIALIZING
Marks the COM object as "safe-for-initializing" meaning that it guarantees to do nothing bad regardless of the data with which it is initialized.  From IE, the user will be given a warning dialog (described above) if an untrusted page attempts to initialize a control that is not "safe-for-initializing".
CI_NOAPARTMENTTHREADING
By default, RegisterControls will register a control as "apartment-aware".  If this flag is set, the control will *not* be registered as apartment-aware.
pNext
A pointer to a ControlInfo struct for the next control that RegisterControls should register.  Use this field to chain together a linked-list of all the controls that RegisterControls should register.  pNext should set to NULL for the last ControlInfo struct in the list.
uiVerbStrID
A string resource ID.  The string is a definition of an OLE verb applicable to the control.  The string is assumed to have the following format:
<verb_number>=<name>, <menu_flags>, <verb_flags>
See help on IOleObject::EnumVerbs for a description of each field. RegisterControls will call LoadString to read all the consecutively-numbered string resources beginning with uiVerbStrID until either LoadString fails (i.e., the resource doesn't exist) or an empty string is returned.  RegisterControls will register/unregister each verb string it reads.
Comments
This structure is used by RegisterControls and HelpCreateClassObject.
Important: The objects pointed to by pointer fields of ControlInfo must be defined statically in the DLL, since functions that use ControlInfo holds onto this pointer.  This can be accomplished by making ControlInfo and all the data it points to be global variables/literals in your DLL.

HostLWOCInfo Structure
typedef struct {
	DWORD dwFlags;
} HostLWOCInfo;

Contains information about a HostLW control.
Defined in: C:/DEV/MMCTL21/AUTODOC/HOSTLW.D
Members
dwFlags
Flags that modify the behavior of the control. These are the same SSWP_ flags specified in ISiteLW::SetSiteWindowParameters.
Comments
See IHostLWOC::GetInfo and IHostLWOC::SetInfo for more information.
This structure is defined in "HostLWOC.h".

LineOCInfo Structure
typedef struct {
	int iWidth;
	COLORREF rgb;
	POINT2 pt2;
} LineOCInfo;

Contains information about a Line control.
Defined in: C:/DEV/MMCTL21/AUTODOC/LINE.D
Members
iWidth
The line's width (in pixels).
rgb
The line's color.  This must be an RGB color, created using the RGB macro.
pt2
The line's position.
Comments
See ILineOC::GetInfo and ILineOC::SetInfo for more information.
This structure is defined in "LineOC.h".

POINT2 Structure
typedef struct {
	POINT apt[2];
} POINT2;

An array of two POINT values, used to represent a geometrical element such as a line segment.
Defined in: C:/DEV/MMCTL21/AUTODOC/LINE.D
Members
apt[2]
The two endpoints.
Comments
This structure is used by LineOCInfo, for example.

PropPageHelperInfo Structure
typedef struct {
	int idDialog;
	int idTitle;
	HINSTANCE hinst;
	PropPageHelperProc pproc;
	IID iid;
	DWORD dwUser;
	IPropertyPageSite * psite;
	LPUNKNOWN * ppunk;
	int cpunk;
	HWND hwnd;
	BOOL fDirty;
	BOOL fLockDirty;
} PropPageHelperInfo;

Maintains information describing a property page.  Used by PropPageHelper, but allocated by the object that aggregates PropPageHelper.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/PROPHELP.CPP
Members
idDialog
ID of propery page dialog resource.
idTitle
ID of a string resource containing the page's title (used on the page tab).
hinst
The instance of the DLL that contains the resources specified by idDialog and idTitle.
pproc
A callback function that receives property page window messages.  pproc is similar to a DLGPROC but has extra parameters: a pointer to this structure, and a pointer to an HRESULT to be used when responding to the following special messages:
WM_PPH_APPLY
pproc should apply any property page changes to the objects ppunk that the property page is operating on.  This is the same as IPropertyPage::Apply.
WM_PPH_HELP
Identical to IPropertyPage::Help. The WPARAM parameter of pproc contains the LPCOLESTR argument of IPropertyPage::Help.
WM_PPH_TRANSLATEACCELERATOR
Identical to IPropertyPage::TranslateAccelerator. The WPARAM parameter of pproc contains the LPMSG argument of IPropertyPage::TranslateAccelerator.
iid
The interface that will be used to communicate with objects that the property page will operate upon.
dwUser
Arbitrary information stored by the caller of AllocPropPageHelper.
psite
The frame's page site object.
ppunk
An array of cpunk pointers to the objects that this property page will operate upon.  The interface ID of each element of ppunk is actually iid.  If cpunk==0, then presumably none of the objects that the property page was requested to operate upon supports the interface iid.
cpunk
The number of elements in ppunk.
hwnd
The property page window.
fDirty
TRUE if changes to the property page have not yet been applied to the objects in ppunk, FALSE otherwise.  (If TRUE, the Apply button should be visible.)
fLockDirty
If TRUE, fDirty should not be changed. fLockDirty is TRUE during initialization of the property page (during which time it's inappropriate to be telling the property page that it's dirty).
Comments
See AllocPropPageHelper for more information.

SPRITE_BOUNDARYACTION
enum SPRITE_BOUNDARYACTION {
	SPRITE_BOUNDARYACTION_BOUNCE,
	SPRITE_BOUNDARYACTION_WRAP,
	SPRITE_BOUNDARYACTION_STICK
};

What to do when a Sprite's time-varying parameter (e.g., translucency or rotation) hits a "boundary" (i.e., a minimum or maximum value).
Defined in: C:/DEV/MMCTL21/AUTODOC/SPRITE.D
Members
SPRITE_BOUNDARYACTION_BOUNCE
Reverse direction.  That is, if at the minimum value, begin stepping toward the maximum; if at the maximum, begin stepping toward the minimum. (ordinal 0)
SPRITE_BOUNDARYACTION_WRAP
Wrap around.  That is, if at the minimum value, jump to the maximum; if at the maximum, jump to the minimum. (ordinal 1)
SPRITE_BOUNDARYACTION_STICK
Don't change.  That is, if at the minimum or maximum value, remain stuck at that value. (ordinal 2)

SPRITE_ROT_VALS
enum SPRITE_ROT_VALS {
	SPRITE_MIN_ROT,
	SPRITE_MAX_ROT,
	SPRITE_INIT_ROT,
	SPRITE_MIN_ROTSTEP,
	SPRITE_MAX_ROTSTEP,
	SPRITE_INIT_ROTSTEP,
	SPRITE_MIN_ROTDELAY,
	SPRITE_MAX_ROTDELAY
};

Possible values for the fields of SpriteRotationInfo and the various rotation-related properties of Sprite.  All rotation values are measured in degrees.  For 2D rotation, rotation values increase in the counter-clockwise direction from the positive x-axis.  For 3D rotation, rotation values increase out of the plane of the display and decrease into the plane of the display.
Defined in: C:/DEV/MMCTL21/AUTODOC/SPRITE.D
Members
SPRITE_MIN_ROT
The mimimum possible rotation (in degrees). (value = -360)
SPRITE_MAX_ROT
The maximum possible rotation (in degress). (value = 360)
SPRITE_INIT_ROT
The default initial rotation (in degrees). (value = 0)
SPRITE_MIN_ROTSTEP
The minimum possible rotation step (in degrees). (value = -360)
SPRITE_MAX_ROTSTEP
The maximum possible rotation step (in degrees). (value = 360)
SPRITE_INIT_ROTSTEP
The default initial rotation step (in degrees). (value = 0)
SPRITE_MIN_ROTDELAY
The minimum possible rotation step delay (in animation ticks). (value = 0)
SPRITE_MAX_ROTDELAY
The maximum possible rotation step delay (in animation ticks). (value = 100)

SPRITE_ROTATION_TYPE
enum SPRITE_ROTATION_TYPE {
	SPRITE_ROT_NONE,
	SPRITE_ROT2D_CENTER,
	SPRITE_ROT2D_TOPLEFT,
	SPRITE_ROT2D_TOPRIGHT,
	SPRITE_ROT2D_BOTTOMRIGHT,
	SPRITE_ROT2D_BOTTOMLEFT,
	SPRITE_ROT2D_TOPMIDPOINT,
	SPRITE_ROT2D_RIGHTMIDPOINT,
	SPRITE_ROT2D_BOTTOMMIDPOINT,
	SPRITE_ROT2D_LEFTMIDPOINT,
	SPRITE_ROT3D_TOPEDGE,
	SPRITE_ROT3D_LEFTEDGE,
	SPRITE_ROT3D_BOTTOMEDGE,
	SPRITE_ROT3D_RIGHTEDGE,
	SPRITE_ROT3D_VERTICALMIDLINE,
	SPRITE_ROT3D_HORIZONTALMIDLINE,
	SPRITE_ROT3D_DIAGONALDOWN,
	SPRITE_ROT3D_DIAGONALUP
};

Possible types of Sprite rotation.  Possible values for Sprite::RotationType and iType.
Defined in: C:/DEV/MMCTL21/AUTODOC/SPRITE.D
Members
SPRITE_ROT_NONE
No rotation. (ordinal 0)
SPRITE_ROT2D_CENTER
2D rotation about the Sprite's center. (ordinal 1)
SPRITE_ROT2D_TOPLEFT
2D rotation about the Sprite's top-left corner. (ordinal 2)
SPRITE_ROT2D_TOPRIGHT
2D rotation about the Sprite's top-right corner. (ordinal 3)
SPRITE_ROT2D_BOTTOMRIGHT
2D rotation about the Sprite's bottom-right corner. (ordinal 4)
SPRITE_ROT2D_BOTTOMLEFT
2D rotation about the Sprite's bottom-left corner. (ordinal 5)
SPRITE_ROT2D_TOPMIDPOINT
2D rotation about the midpoint of the Sprite's top edge. (ordinal 6)
SPRITE_ROT2D_RIGHTMIDPOINT
2D rotation about the midpoint the Sprite's right edge. (ordinal 7)
SPRITE_ROT2D_BOTTOMMIDPOINT
2D rotation about the midpoint of the Sprite's bottom edge. (ordinal 8)
SPRITE_ROT2D_LEFTMIDPOINT
2D rotation about the midpoint of the Sprite's left edge. (ordinal 9)
SPRITE_ROT3D_TOPEDGE
Pseudo-3D rotation into or out of the plane of the display using the Sprite's top edge as the axis of rotation.  (ordinal 10)
SPRITE_ROT3D_LEFTEDGE
Pseudo-3D rotation into or out of the plane of the display using the Sprite's left edge as the axis of rotation.  (ordinal 11)
SPRITE_ROT3D_BOTTOMEDGE
Pseudo-3D rotation into or out of the plane of the display using the Sprite's bottom edge as the axis of rotation.  (ordinal 12)
SPRITE_ROT3D_RIGHTEDGE
Pseudo-3D rotation into or out of the plane of the display using the Sprite's right edge as the axis of rotation.  (ordinal 13)
SPRITE_ROT3D_VERTICALMIDLINE
Pseudo-3D rotation into or out of the plane of the display using the Sprite's vertical midline as the axis of rotation. (ordinal 14)
SPRITE_ROT3D_HORIZONTALMIDLINE
Pseudo-3D rotation into or out of the plane of the display using the Sprite's horizontal midline as the axis of rotation. (ordinal 15)
SPRITE_ROT3D_DIAGONALDOWN
Pseudo-3D rotation into or out of the plane of the display using the diagonal from the Sprite's top-left to bottom-right corners as the axis of rotation.  Note: This rotation type is not currently implemented. (ordinal 16)
SPRITE_ROT3D_DIAGONALUP
Pseudo-3D rotation into or out of the plane of the display using the diagonal from the Sprite's bottom-left to top-right corners as the axis of rotation.  Note: This rotation type is not currently implemented. (ordinal 17)

SPRITE_TRANS_VALS
enum SPRITE_TRANS_VALS {
	SPRITE_MIN_TRANS,
	SPRITE_MAX_TRANS,
	SPRITE_MIN_TRANSSTEP,
	SPRITE_MAX_TRANSSTEP,
	SPRITE_MIN_TRANSDELAY,
	SPRITE_MAX_TRANSDELAY
};

Possible values for the fields of SpriteTranslucencyInfo and the various translucency-related properties of Sprite.
Defined in: C:/DEV/MMCTL21/AUTODOC/SPRITE.D
Members
SPRITE_MIN_TRANS
The minimum possible opacity (i.e., completely translucent). (value = 0)
SPRITE_MAX_TRANS
The maximum possible opacity (i.e., completely opaque). (value = 255)
SPRITE_MIN_TRANSSTEP
The minimum possible translucency step. (value = -255)
SPRITE_MAX_TRANSSTEP
The maximum possible translucency step. (value = 255)
SPRITE_MIN_TRANSDELAY
The minimum possible translucency step delay (in animation ticks). (value = 0)
SPRITE_MAX_TRANSDELAY
The maximum possible translucency step delay (in animation ticks). (value = 100)

SpriteBitmapInfo Structure
typedef struct {
	TCHAR[MAX_PATH + 1] szBitmapPath;
	int cFramesTotal;
	int cFramesAcross;
	int cFramesDown;
} SpriteBitmapInfo;

Contains about the bitmap associated with a Sprite control.
Defined in: C:/DEV/MMCTL21/AUTODOC/SPRITE.D
Members
szBitmapPath
The file system path to the Sprite's bitmap file; if szBitmapPath[0] is '\0', the Sprite isn't currently associated with a bitmap.
cFramesTotal
The total number of frames in the bitmap; less than cFramesAcross * cFramesDown if some frames in the last row are unused.
cFramesAcross
The number of frames running across the bitmap (i.e., #columns); less than cFrames / cFramesDown if some frames in the last row are unused.
cFramesDown
The number of frames running down the bitmap (i.e., #rows); less than cFrames / cFramesAcross if some frames in the last row are unused.
Comments
See ISprite::GetInfo and ISprite::SetInfo for more information.
This structure is defined in "isprite.h".

SpriteQuadrangleInfo Structure
typedef struct {
	POINT vertex[4];
	LONG coord[8];
} SpriteQuadrangleInfo;

Information about a Sprite control's BLT-ing quadrangle.  Note: this data structure is implemented as a union.  Therefore, the coordinates of the quadrangle may be accessed as four vertices or as eight individual x- and y-coordinates, whichever is most convenient.
Defined in: C:/DEV/MMCTL21/AUTODOC/SPRITE.D
Members
vertex[4]
The four vertices of the quadrangle in the order (x1,y1), (x2,y2), (x3,y3), and (x4,y4).
coord[8]
The eight coordinates of the vertex in the order x1, y1, x2, y2, x3, y3, x4, y4.

SpriteRotationInfo Structure
typedef struct {
	int iType;
	int iNow;
	int iMin;
	int iMax;
	int iSpeed;
	int iDelayNow;
	int iDelayAtMin;
	int iDelayAtMax;
	SPRITE_BOUNDARYACTION edgeAction;
} SpriteRotationInfo;

Contains rotation information about a Sprite control.
Defined in: C:/DEV/MMCTL21/AUTODOC/SPRITE.D
Members
iType
The rotation type.  See SPRITE_ROTATION_TYPE for possible values.
iNow
The initial rotation value. Must be between SPRITE_MIN_ROT and SPRITE_MAX_ROT, and between iMin and iMax.
iMin
The minimum rotation value. Must be between SPRITE_MIN_ROT and SPRITE_MAX_ROT.
iMax
The minimum rotation value. Must be between SPRITE_MIN_ROT and SPRITE_MAX_ROT.
iSpeed
The change in rotation which occurs with every call to the Sprite's IAnimate::Tick method.  Must be between SPRITE_MIN_ROTSTEP (slowest) and SPRITE_MAX_ROTSTEP (fastest).
iDelayNow
The delay in Sprite rotation stepping that occurs when the Sprite first appears. Measured in terms of the number of calls to the Sprite's IAnimate::Tick method. Must be between SPRITE_MIN_ROTDELAY (no delay) and SPRITE_MAX_ROTDELAY (longest delay).
iDelayAtMin
The delay in Sprite rotation stepping that occurs when the Sprite hits its minimum rotation.  Measured in terms of the number of calls to the Sprite's IAnimate::Tick method.  Must be between SPRITE_MIN_ROTDELAY (no delay) and SPRITE_MAX_ROTDELAY (longest delay).
iDelayAtMax
The delay in Sprite rotation stepping that occurs when the Sprite hits its maximum rotation.  Measured in terms of the number of calls to the Sprite's IAnimate::Tick method.  Must be between SPRITE_MIN_ROTDELAY (no delay) and SPRITE_MAX_ROTDELAY (longest delay).
edgeAction
What happens after the rotation hits iMin or iMax.
Comments
See ISprite::GetInfo and ISprite::SetInfo for more information.
This structure is defined in "isprite.h".

SpriteTranslucencyInfo Structure
typedef struct {
	int iNow;
	int iMin;
	int iMax;
	int iSpeed;
	int iDelayNow;
	int iDelayAtMin;
	int iDelayAtMax;
	SPRITE_BOUNDARYACTION edgeAction;
} SpriteTranslucencyInfo;

Contains translucency information about a Sprite control.
Defined in: C:/DEV/MMCTL21/AUTODOC/SPRITE.D
Members
iNow
The initial translucency value.  Must be between SPRITE_MIN_TRANS (transparent) and SPRITE_MAX_TRANS (opaque), and must be between iMin and iMax.
iMin
The minimum translucency value.  Must be between SPRITE_MIN_TRANS (transparent) and SPRITE_MAX_TRANS (opaque).
iMax
The maximum translucency value.  Must be between SPRITE_MIN_TRANS (transparent) and SPRITE_MAX_TRANS (opaque).
iSpeed
The change in translucency which occurs with every call to the Sprite's IAnimate::Tick method.  Must be between SPRITE_MIN_TRANSSTEP (slowest) and SPRITE_MAX_TRANSSTEP (fastest).
iDelayNow
The delay in Sprite translucency stepping that occurs when the Sprite first appears. Measured in terms of the number of calls to the Sprite's IAnimate::Tick method. Must be between SPRITE_MIN_TRANSDELAY (no delay) and SPRITE_MAX_TRANSDELAY (longest delay).
iDelayAtMin
The delay in Sprite translucency stepping that occurs when the Sprite hits its minimum translucency.  Measured in terms of the number of calls to the Sprite's IAnimate::Tick method.  Must be between SPRITE_MIN_TRANSDELAY (no delay) and SPRITE_MAX_TRANSDELAY (longest delay).
iDelayAtMax
The delay in Sprite translucency stepping that occurs when the Sprite hits its maximum translucency.  Measured in terms of the number of calls to the Sprite's IAnimate::Tick method.  Must be between SPRITE_MIN_TRANSDELAY (no delay) and SPRITE_MAX_TRANSDELAY (longest delay).
edgeAction
What happens after the translucency hits iMin or iMax.
Comments
See ISprite::GetInfo and ISprite::SetInfo for more information.
This structure is defined in "isprite.h".

VariantProperty Structure
typedef struct {
	BSTR bstrPropName;
	VARIANT varValue;
} VariantProperty;

Contains the name and value of a property.
Defined in: C:/DEV/MMCTL21/SRC/OCMISC/AVIO.CPP
Members
bstrPropName
The name of the property.
varValue
The value of the property.
Comments
IEnumVariantProperty uses this structure.

VariantPropertyHeader Structure
typedef struct {
	int iType;
	unsigned int cbData;
} VariantPropertyHeader;

The beginning part of a record (in a stream) that contains the serialized data of a VariantProperty.
Defined in: C:/DEV/MMCTL21/SRC/OCHELP/RVP.CPP
Members
iType
The type of the record.  If this value is greater than or equal to zero, then it represents a VARTYPE, and the record represents a property name/value pair, and the type of the value is specified by the VARTYPE.  In this case, the data following the VariantPropertyHeader consists of the property name followed by the property value (coerced to a string value by VariantChangeType); each string is a non-null-terminated Unicode string preceded by an unsigned 32-bit integer count of Unicode characters.  iType is not a known VARTYPE value, then the record should be skipped when read (by skipping the cbData bytes that follow the VariantPropertyHeader rather than generating an error.
cbData
The number of bytes of data that follow this VariantPropertyHeader.  In other words, the total length of the header is cbData + sizeof(VariantPropertyHeader).
Comments
This structure helps define the file format used by WriteVariantProperty and ReadVariantProperty.