OCX コントロールを使用する VC++6.0 で構築されたレガシー アプリケーションがあります。VS2013 でビルドするようにアプリケーションをアップグレードしました。最初は正常にビルドして実行できましたが、Class Wizard を使用して ocx.h および ocx.cpp ファイルを再生成しようとしたときに、
- ソリューション エクスプローラーでプロジェクトを右クリック
- ActiveX コントロールから Add:Class:MFCClass を選択する
- [追加]ボタン
- 登録済みコントロールのリストから OCX を選択
- コピーするインターフェイスを選択
- [完了]ボタン
生成された h および cpp 出力ファイルにすべての属性メソッドがありません
// Attributes
public:
// Operations
public:
void ClearTablet()
{ . . .
また、レジストリを使用する代わりに Class Wizard に OCX ファイルを直接指定しようとしましたが、結果は同じでした。ocx.h および ocx.cpp ファイルを手動で編集して欠落している属性メソッドを追加しましたが、Class Wizard がそれらを生成しない理由がわかりません。VC++6.0 バージョンに戻って、ファイルが正しく生成されるかどうかを確認しようと考えましたが、同じメニュー オプションが利用できないため、6.0 を使用して ocx.h および ocx.cpp ファイルを生成する方法がわかりません。
Hans のコメントに応えて 2018 年 3 月 5 日を追加
元の OCX プロジェクトで欠落している属性の 1 つを次に示します。
=====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);
. . .
=====ファイル: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 ウィザードによって作成されたものなのか、元のプログラマーがこれらのヘッダー ファイルも編集したのかはわかりません。
========FILE: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 コントロールのメソッドの実装がすべて SigPlusCtl.cpp ファイルに配置されるのではなく、複数の .cpp ファイルに分散されているという点で、やや型破りです。
3-20-18 追加
Hans による 3-20 のコメントに続いて、Visual Studio 2013 で ocx ファイルを開いて TYPELIB を調べようとしました。しかし、TYPELIB フォルダーを展開すると、HEX ダンプしか表示されません。
OLE/COM Object Viewerを使用して 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
メソッドの下の Get メソッドと Set メソッドの明示的なリストが OLE Viewer に表示されることを期待する必要がありますか?
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
18/3/20 17:00PDT 追加
@HansPassart がコメントで言及した#importを調べました。この Microsoft 固有のディレクティブは、クラス ウィザードの使用に代わるものと思われます。クラス ウィザードで生成されたファイル sigplus.h および sigplus.cpp をプロジェクトから削除し、追加しました。
#import "file:SigPlus.tlb"
メインヘッダーファイルに。#importディレクティブをコンパイルすると、sigplus.TLH および sigplus.TLI (ヘッダーと実装) ファイルが生成され、TLI ファイルを明示的にインクルードする sigplus.TLH がインクルードされます。#import をコンパイルすると、これら 2 つのファイルが生成され、生成された「Release/sigplus.tlh」がインクルードされます。これらの生成されたファイルには不足している Get/Set メソッドが含まれていますが、コンパイルされません。TLH ファイルは、OCX クラス _DSigPlus に別の名前を使用し、名前空間内に配置します。しかし、これらの違いを考慮した後でも、TLH ファイル内のクラス宣言は、Class Wizard が CWnd を使用する親クラスとして IDispatch を使用し、コンパイル時に、IDispatch の親である IUnknown からの次の未解決の純粋仮想メソッドがあります。
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'