I have a legacy application that was built with VC++6.0 that uses an OCX control. I have upgraded the application to build with VS2013. Initially I got it to build and run successfully but when I tried to regenerate the ocx.h and ocx.cpp file using the Class Wizard by
- Right clicking on project in solution explorer
- Selecting Add:Class:MFCClass From ActiveX Control
- [Add] button
- Select OCX from list of registered controls
- Select the interface to copy
- [Finish] button
The generated h and cpp output files are missing all the Attribute methods
// Attributes
public:
// Operations
public:
void ClearTablet()
{ . . .
I also tried giving Class Wizard the OCX file directly instead of using the registry but had the same results. I resorted to manually editing the ocx.h and ocx.cpp file to add the missing attribute methods but don't understand why Class Wizard is not generating them. I thought to go back to the VC++6.0 version to see if it would correctly generate the files but I am unclear how to use 6.0 to generate the ocx.h and ocx.cpp files as the same menu options are not available.
Added 3-5-2018 in response to Hans comment
Here's what one of the missing attributes looked like in the original OCX project
=====FILE:SigPlusCtl.h=========
class CSigPlusCtrl : public COleControl
{
DECLARE_DYNCREATE(CSigPlusCtrl)
DECLARE_INTERFACE_MAP()
. . .
// Dispatch maps
//{{AFX_DISPATCH(CSigPlusCtrl)
afx_msg short GetImageFileFormat();
afx_msg void SetImageFileFormat(short nNewValue);
. . .
=====FILE:SigPlusCtl.cpp=========
// Dispatch map
BEGIN_DISPATCH_MAP(CSigPlusCtrl, COleControl)
//{{AFX_DISPATCH_MAP(CSigPlusCtrl)
DISP_PROPERTY_EX(CSigPlusCtrl, "ImageFileFormat", GetImageFileFormat, SetImageFileFormat, VT_I2)
. . .
=====FILE:SigPlusImage.cpp====
short CSigPlusCtrl::GetImageFileFormat()
{
return ImageFileFormat;
}
void CSigPlusCtrl::SetImageFileFormat( short nNewValue)
{
if ( ( nNewValue >= 0 ) && ( nNewValue <= 11 ) )
{
ImageFileFormat = nNewValue;
}
SetModifiedFlag();
}
. . .
And here's what I had to add to the generated .h and .cpp files in the container project to use this missing attribute. I copied this code from the original OCX .h and .cpp files in the container app before I tried to regenerate them with VS2013. Since I was unable to regenerate these files using VC++6.0 (see my 1st comment below), I don't know if this copied code was originally created by VC++6.0 wizard or the original programmer edited these header files also.
========FILE:sigplus================
// Attributes
public:
short GetImageFileFormat();
void SetImageFileFormat(short);
. . .
========FILE:sigplus.cpp=============
// CSigPlus properties
short CSigPlus::GetImageFileFormat()
{
short result;
GetProperty(0x1, VT_I2, (void*)&result);
return result;
}
void CSigPlus::SetImageFileFormat(short propVal)
{
SetProperty(0x1, VT_I2, propVal);
}
. . .
I don't know if it matters to class wizard but the method locations are somewhat unconventional in that the implementations for the OCX control's methods are scattered across multiple .cpp files instead of all being located in the SigPlusCtl.cpp file
Added 3-20-18
Following the comment by Hans on 3-20 I tried to open the ocx file with Visual Studio 2013 to examine the TYPELIB. But when I expand the TYPELIB folder it only shows me a HEX dump.
Looking at the OCX TypeLib interface using OLE/COM Object Viewer I see the missing properties listed under "Properties" but I don't see explicit declarations of Get and Set methods. For example there is a property ImageFileFormat but not GetImageFileFormat and SetImageFileFormat. There are explicit definitions of these Get/Set methods in the source for the OCX control.
SigPlusCtl.cpp: DISP_PROPERTY_EX(CSigPlusCtrl, "ImageFileFormat", GetImageFileFormat, SetImageFileFormat, VT_I2)
SigPlusCtl.h: afx_msg short GetImageFileFormat();
SigPlusImage.cpp: short CSigPlusCtrl::GetImageFileFormat()
SigPlus.map: 0001:00012ed0 ?GetImageFileFormat@CSigPlusCtrl@@IAEFXZ 10013ed0 f SigPlusImage.obj
Should I expect to see explicit listing in the OLE Viewer for Get and Set methods under methods:?
dispinterface _DSigPlus {
properties:
[id(0x00000001)
]
short ImageFileFormat;
[id(0x00000002)
]
short ImageXSize;
[id(0x00000003)
]
short ImageYSize;
[id(0x00000004)
]
o o o
]
BSTR TabletGraphicFile;
[id(0x00000042)
]
long TabletTimer;
[id(0xfffffe0b), bindable, requestedit
]
OLE_COLOR BackColor;
[id(0xfffffdff), bindable, requestedit
]
OLE_COLOR ForeColor;
methods:
[id(0x00000043)]
void ClearTablet();
[id(0x00000044)]
o o o
Added 3-20-18 17:00PDT
I looked up #import mentioned by @HansPassart in a comment. This Microsoft specific directive appears to be an alternative to using the Class Wizard. I removed the Class Wizard generated files sigplus.h and sigplus.cpp from the project and added
#import "file:SigPlus.tlb"
to the main header file. When compiled the #import directive generates sigplus.TLH and sigplus.TLI (Header and Implementation) files and then includes the sigplus.TLH which then explicitly includes the TLI file. When compiled the #import does generate these two files and then includes the generated "Release/sigplus.tlh". These generated files do contain the missing Get/Set methods however they do not compile. The TLH file uses a different name for the OCX class _DSigPlus and puts it inside a namespace. But even after accounting for those differences the class declaration in the TLH file uses IDispatch as the parent class where Class Wizard used CWnd and when compiled there are the following unresolved pure virtual methods coming from IUnknown which is the parent of IDispatch.
c:\demoocx\DemoOCXDlg.h(24): error C2259: 'SIGPLUSLib::_DSigPlus' : cannot instantiate abstract class
due to following members:
'HRESULT IUnknown::QueryInterface(const IID &,void **)' : is abstract
C:\Program Files (x86)\Windows Kits\8.1\Include\um\unknwnbase.h(114) : see declaration of 'IUnknown::QueryInterface'
'ULONG IUnknown::AddRef(void)' : is abstract
C:\Program Files (x86)\Windows Kits\8.1\Include\um\unknwnbase.h(118) : see declaration of 'IUnknown::AddRef'
'ULONG IUnknown::Release(void)' : is abstract
C:\Program Files (x86)\Windows Kits\8.1\Include\um\unknwnbase.h(120) : see declaration of 'IUnknown::Release'
'HRESULT IDispatch::GetTypeInfoCount(UINT *)' : is abstract
c:\program files (x86)\windows kits\8.1\include\um\oaidl.h(2187) : see declaration of 'IDispatch::GetTypeInfoCount'
'HRESULT IDispatch::GetTypeInfo(UINT,LCID,ITypeInfo **)' : is abstract
c:\program files (x86)\windows kits\8.1\include\um\oaidl.h(2190) : see declaration of 'IDispatch::GetTypeInfo'
'HRESULT IDispatch::GetIDsOfNames(const IID &,LPOLESTR *,UINT,LCID,DISPID *)' : is abstract
c:\program files (x86)\windows kits\8.1\include\um\oaidl.h(2195) : see declaration of 'IDispatch::GetIDsOfNames'
'HRESULT IDispatch::Invoke(DISPID,const IID &,LCID,WORD,DISPPARAMS *,VARIANT *,EXCEPINFO *,UINT *)' : is abstract
c:\program files (x86)\windows kits\8.1\include\um\oaidl.h(2202) : see declaration of 'IDispatch::Invoke'