我有一个使用 OCX 控件的 VC++6.0 构建的遗留应用程序。我已升级应用程序以使用 VS2013 构建。最初我让它构建并成功运行,但是当我尝试使用类向导重新生成 ocx.h 和 ocx.cpp 文件时
- 在解决方案资源管理器中右键单击项目
- 从 ActiveX 控件中选择 Add:Class:MFCClass
- [添加] 按钮
- 从注册控件列表中选择 OCX
- 选择要复制的接口
- [完成]按钮
生成的 h 和 cpp 输出文件缺少所有 Attribute 方法
// Attributes
public:
// Operations
public:
void ClearTablet()
{ . . .
我还尝试直接为 Class Wizard 提供 OCX 文件,而不是使用注册表,但结果相同。我求助于手动编辑 ocx.h 和 ocx.cpp 文件来添加缺少的属性方法,但不明白为什么类向导不生成它们。我想回到 VC++6.0 版本,看看它是否能正确生成文件,但我不清楚如何使用 6.0 来生成 ocx.h 和 ocx.cpp 文件,因为相同的菜单选项不可用。
添加 3-5-2018 以回应 Hans 评论
这是原始 OCX 项目中缺少的属性之一
=====文件: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);
. . .
=====文件:SigPlusCtl.cpp=========
// Dispatch map
BEGIN_DISPATCH_MAP(CSigPlusCtrl, COleControl)
//{{AFX_DISPATCH_MAP(CSigPlusCtrl)
DISP_PROPERTY_EX(CSigPlusCtrl, "ImageFileFormat", GetImageFileFormat, SetImageFileFormat, VT_I2)
. . .
=====文件:SigPlusImage.cpp====
short CSigPlusCtrl::GetImageFileFormat()
{
return ImageFileFormat;
}
void CSigPlusCtrl::SetImageFileFormat( short nNewValue)
{
if ( ( nNewValue >= 0 ) && ( nNewValue <= 11 ) )
{
ImageFileFormat = nNewValue;
}
SetModifiedFlag();
}
. . .
这是我必须添加到容器项目中生成的 .h 和 .cpp 文件中以使用此缺失属性的内容。在尝试使用 VS2013 重新生成它们之前,我从容器应用程序中的原始 OCX .h 和 .cpp 文件中复制了此代码。由于我无法使用 VC++6.0 重新生成这些文件(请参阅下面的第一条评论),我不知道这个复制的代码是否最初是由 VC++6.0 向导创建的,或者原始程序员也编辑了这些头文件。
========文件:sigplus=================
// Attributes
public:
short GetImageFileFormat();
void SetImageFileFormat(short);
. . .
========文件: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);
}
. . .
我不知道类向导是否重要,但方法位置有点不合常规,因为 OCX 控件方法的实现分散在多个 .cpp 文件中,而不是全部位于 SigPlusCtl.cpp 文件中
2018 年 3 月 20 日添加
根据 Hans 在 3-20 上的评论,我尝试使用 Visual Studio 2013 打开 ocx 文件以检查 TYPELIB。但是当我展开 TYPELIB 文件夹时,它只显示了一个 HEX 转储。
查看使用OLE/COM 对象查看器的 OCX TypeLib 界面,我看到“属性”下列出了缺少的属性,但我没有看到 Get 和 Set 方法的明确声明。例如,有一个属性ImageFileFormat但没有GetImageFileFormat和SetImageFileFormat。在 OCX 控件的源代码中有这些 Get/Set 方法的明确定义。
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
我是否应该期望在 OLE 查看器中看到明确列出方法下的 Get 和 Set方法:?
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
添加 3-20-18 17:00 PDT
我在评论中查找了@HansPassart 提到的#import 。此 Microsoft 特定指令似乎是使用类向导的替代方法。我从项目中删除了类向导生成的文件 sigplus.h 和 sigplus.cpp 并添加了
#import "file:SigPlus.tlb"
到主头文件。编译后,#import指令会生成 sigplus.TLH 和 sigplus.TLI(头文件和实现)文件,然后包含 sigplus.TLH,然后显式包含 TLI 文件。编译时,#import 会生成这两个文件,然后包含生成的“Release/sigplus.tlh”。这些生成的文件确实包含缺少的 Get/Set 方法,但它们无法编译。TLH 文件为 OCX 类 _DSigPlus 使用不同的名称,并将其放在命名空间中。但即使在考虑了这些差异之后,TLH 文件中的类声明使用 IDispatch 作为类向导使用 CWnd 的父类,并且在编译时有以下未解析的纯虚方法来自 IUnknown,它是 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'