SAMPLE: Using VBX Controls in a "Non-MFC" Application
ID: Q118494
|
The information in this article applies to:
-
The Microsoft Foundation Classes (MFC), included with:
-
Microsoft Visual C++ for Windows, 16-bit edition, versions 1.0, 1.5
SUMMARY
Occasionally, you may want to have the capability of using VBX controls in
an application that has been written in straight C instead of C++ or that
was not written to use the entire Microsoft Foundation Classes framework.
Although the support for VBX controls is available only to a Microsoft
Foundation Classes application, it is possible to create a minimal
Foundation Classes application which provides the ability to use VBX
controls.
The following sample, VBXC, demonstrates a technique for creating a minimal
MFC application which enables VBX support. The "minimal MFC application"
here is a C++ based module that uses the MFC CWinApp class and that can be
linked with a C based application to provide support for VBX controls.
MORE INFORMATION
The following file is available for download from the Microsoft Software
Library:
VBXC.EXE
For more information about downloading files from the Microsoft Software
Library, please see the following article in the Microsoft Knowledge Base:
Q119591 How to Obtain Microsoft Support Files from Online Services
Any application which uses VBX controls will have to be a Microsoft
Foundation Classes application. This simply means that it must have a
CWinApp object. This article shows you how to create this CWinApp object,
and provides the code necessary to support use of VBX controls. One of the
consequences of including a CWinApp object is that you are automatically
using the Foundation-provided WinMain function and the message loop
contained within the CWinApp::Run() function. However, you must have a
CWinApp object to use VBX controls in your application.
NOTE: Be aware that this is not intended as a replacement for knowledge of
the Microsoft Foundation Classes. You will be linking with and calling into
the MFC library functions, and you should be aware of how this will affect
your program.
The idea is to create a CWinApp object which initializes the VBX support
and then calls the underlying code in your application (i.e. it uses your
application's WinMain). After creating a module which contains such an
object, you can link with this module to obtain rudimentary support for VBX
controls. You can then enhance the module as necessary to obtain further
VBX capabilities. This article outlines the header and implementation files
for a module which will give you this capability.
Following is the general implementation of the module that is referred to
in this article as USEVBX:
//////////////////////////////////////////////////
// FILE USEVBX.H
//
#ifdef __cplusplus // two underscores
extern "C" {
#endif
void InitializeVBX(HWND hDlg,LPCSTR lpszResourceName);
#ifdef __cplusplus
}
#endif
//
// EOF - USEVBX.H
///////////////////////////////////////////////////
//////////////////////////////////////////////////
// FILE USEVBX.CPP
//
#include <afxwin.h>
#include <afxext.h>
#include "usevbx.h"
// Prototype the application's _WinMain
extern "C"
int PASCAL _WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow);
class CVBXApp : public CWinApp
{
public:
virtual BOOL InitInstance();
virtual int Run();
};
BOOL CVBXApp::InitInstance()
{
EnableVBX();
return CWinApp::InitInstance();
}
int CVBXApp::Run()
{
// Call the main application's WinMain.
return _WinMain(m_hInstance,m_hPrevInstance,
m_lpCmdLine,m_nCmdShow);
}
void InitializeVBX(HWND hDlg,LPCSTR lpszResourceName)
{
CWnd wndDlg;
wndDlg.Attach(hDlg);
wndDlg.ExecuteDlgInit(lpszResourceName);
wndDlg.Detach();
}
CVBXApp theVBXApp;
//
// EOF - USEVBX.CPP
////////////////////////////////////////////////////////
Once you have created the USEVBX.CPP source module, integrate it into your
project in the following manner:
- Select Project/Edit and add the file USEVBX.CPP to your project.
- Link in the appropriate MFC libraries. (e.g. MAFXCWD, LAFXCWD). You can
do this by just selecting Options/Project, and checking the "Use
Microsoft Foundation Classes" option, or you can explicitly put the
library file name in your link options under Options/Project/
Linker/Libraries. For more information on library naming conventions,
see Appendix B of the "Class Library User's Guide".
- Rename your current application's WinMain function to _WinMain.
- For any dialog box which contains VBX controls, add a handler for
WM_INITDIALOG which first calls InitializeVBX(hDlg,lpszResourceName).
This will initialize the VBX controls with the properties you specify in
App Studio. You should also include the USEVBX.H header file in any
module which calls this function.
The InitializeVBX function first creates a CWnd object and attaches it to
your dialog box window so that it can perform the VBX initialization. It
then calls the function ExecuteDlgInit which performs ComboBox and VBX
initialization. After that it must detach the CWnd object so that the
dialog box window is not destroyed when the CWnd object is deleted (the
CWnd object is defined as a local so it will be deleted as soon as we exit
the function).
This will enable VBX support in your application. You will probably want to
be able to use App Studio to put VBXs on your dialog templates. You can't
do this with a non-Microsoft Foundation Classes resource file so you must
convert your current RC file. There is an article which discusses how to
perform this conversion. The article is available in the Microsoft
Knowledge Base and can be found by querying on the following words:
converting rc file symbol directives
The article is Q99391, titled: "Converting an RC File to Use
Microsoft Foundation Classes".
Once you have a resource script which is compatible with the Microsoft
Foundation Classes you can use App Studio to put VBX controls on your
dialog templates. You can also use App Studio to set initial properties for
the controls, but for the initialization to be performed you must make the
call to InitializeVBX in the WM_INITDIALOG processing of your dialog box.
To access the properties of the VBX you will have to create a C interface
which implements the functionality contained in the CVBControl class. This
can be done as needed. NOTE: The example VBXC implements most of these
functions but the sample is for demonstration purposes only, and does not
include instructions on how to re-implement the entire CVBControl class.
For example, here is how you might add the capability to use the
SetNumProperty and GetNumProperty functions:
- Insert these prototypes directly after the InitializeVBX function in the
header file USEVBX.H:
// The last parameter in CVBControl::GetNumProperty has a
// default of 0 in C++ but the default of 0 must be supplied
// by the caller in C because default parameters are not
// allowed.
LONG GetNumProperty(HWND hVBX,LPCSTR lpszPropName,int index);
BOOL SetNumProperty(HWND hVBX,LPCSTR lpszPropName,
LONG lValue,int index);
- Now implement the functions in the file USEVBX.CPP:
LONG GetNumProperty(HWND hVBX,LPCSTR lpszPropName,int index)
{
CVBControl *pVBCtrl = (CVBControl *)CWnd::FromHandle(hVBX);
ASSERT(pVBCtrl->IsKindOf(RUNTIME_CLASS(CVBControl)));
return pVBCtrl->GetNumProperty(lpszPropName,index);
}
BOOL SetNumProperty(HWND hVBX,LPCSTR lpszPropName,
LONG lValue,int index)
{
CVBControl *pVBCtrl = (CVBControl *)CWnd::FromHandle(hVBX);
ASSERT(pVBCtrl->IsKindOf(RUNTIME_CLASS(CVBControl)));
return pVBCtrl->SetNumProperty(lpszPropName,lValue,index);
}
- To call these functions, you can simply use the Windows API function
GetDlgItem to get the handle to the VBX window and pass it to the
property function. e.g.
// Toggle the TabStop property
LONG l;
HWND hwndVBX;
hwndVBX = GetDlgItem(hDlg,IDC_VBX1);
l = GetNumProperty(hwndVBX,"TabStop",0);
SetNumProperty(hwndVBX,"TabStop",!l,0);
NOTE: There is an assertion which verifies that the CWnd object retrieved
is actually a CVBControl object. This might at first appear erroneous
because the function call CWnd::FromHandle could return a temporary object
which would simply be a CWnd, not a CVBControl. Considering that the
calling application is not likely to be creating CVBControl objects itself,
it seems that this function call would always return a temporary CWnd
object, and the assertion would fail.
However, VBX controls are a special case. MFC implements VBX controls by
always creating a permanent CVBControl object for every VBX control
created. These objects are attached to the window of the VBX and are
automatically deleted when the parent window of the VBX is destroyed.
Since there is a permanent CVBControl object attached to every VBX control
which has been successfully created, the call to CWnd::FromHandle will
always return the permanent CVBControl object. If it does not return the
permanent handle, an assertion should be flagged.
An example of when you would get an assertion failure would be if the
IDC_VBX1 identifier used above was actually the ID of a non-VBX control. In
this case, there would be no CVBControl object attached and the ASSERT
above would flag that.
NOTE: You can use this method to safely add VBX controls to a Windows
application written in C. You should not, however, use this method to add
other MFC classes to such an application. To do so would circumvent the MFC
framework and cause the following problems:
- You are not using the framework's message loop. This means that none of
the command routing or pre-translation of messages will occur.
- You are not calling the framework's idle processing. The biggest problem
with this is that if you begin to use functions from the MFC libraries
which create temporary objects (either directly or indirectly), those
objects will never be deleted and you will have memory leaks.
If you would like to gain more of the functionality that the Microsoft
Foundation Classes can provide in your application, then you should begin
by doing a full conversion of your application to an MFC application. Refer
to the "Class Library User's Guide" and the "Class Library Reference" for
more information on how to convert your application to MFC.
Additional query words:
Keywords : kbcode kb16bitonly kbMFC kbVBX kbVC kbVC100 kbVC150
Version : 1.00 1.50
Platform : WINDOWS
Issue type : kbinfo
Last Reviewed: July 28, 1999