1

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

  1. Right clicking on project in solution explorer
  2. Selecting Add:Class:MFCClass From ActiveX Control
  3. [Add] button
  4. Select OCX from list of registered controls
  5. Select the interface to copy
  6. [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. enter image description here

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'
JonN
  • 2,498
  • 5
  • 33
  • 49
  • I did find the procedure for creating h and cpp files with VC++6.0 (https://msdn.microsoft.com/en-us/library/aa262306(v=vs.60).aspx) But when I tried it with the OCX it gave the alert "Xyz Control No such interface supported" – JonN Mar 03 '18 at 04:49
  • Hard to guess what you are talking about. Inline IDL attributes where a design mistake in VS2003 that were deprecated again in VS2005. What "attribute methods" did you actually add? Give us an example. – Hans Passant Mar 03 '18 at 08:46
  • @HansPassant To be clear I didn't add any new attributes or methods to the OCX control. I only added the missing declarations to the h and cpp files generated by VS2013 Class Wizard. See added code extracts in edit to original question on 3-5-18. – JonN Mar 05 '18 at 20:32
  • The link in my first comment should have been https://msdn.microsoft.com/en-us/library/aa269050(v=vs.60).aspx – JonN Mar 07 '18 at 01:35
  • So it looks like the basic mishap is that you started with an old copy of the type library. A previous version that did not yet have these new methods. Go back to the control project and build a fresh copy. Use OleView.exe, File > View Typelib and verify that you see these methods in the decompiled interface. – Hans Passant Mar 16 '18 at 06:22
  • I admit ignorance in this area. There is within the OCX project a SigPlus.tlb file in the Release folder along with the SigPlus.ocx file and both were generated by the same build. What I don't understand is the need for a TLB file or how to use it in the container project. I thought the OCX file itself contained all the type info for the control already so I don't understand how the TLB file is to be used either when building the container app or when registering the OCX control? My understanding has been that when I register an OCX that the process of registering also stores the interface. – JonN Mar 19 '18 at 23:57
  • The .tlb file is just a build artifact, it gets embedded into the .ocx file as a resource. Which is how it "contained all the type info". Something you can see in VS by using File > Open > File, select the .ocx file, note the TYPELIB node. The type library tells the client compiler what the types in the library look like, same idea as a .h file. Or in this case the wizard. Using the #import directive in the client code is a good way to take advantage of it, the MFC wizard is wonky and based on the theory that late binding is a good idea. Just a theory. Ensure the type library is good. – Hans Passant Mar 20 '18 at 00:06
  • @HansPassant I've built and rebuilt the OCX and registered it. If that is so how could the container app be getting an old copy of the type library? As I mentioned in the original question I even tried giving the Class Wizard the newly built OCX file directly but with the same results that it fails to generate prototypes for any of the Get/Set property methods. – JonN Mar 20 '18 at 19:40
  • As noted, use Oleview.exe to look at the type library content. Run it from the Visual Studio Developer Command. And the OCX project should have an .idl file, it defines the content of the type library. Things you can look at and compare to know what you should expect the wizard to do. – Hans Passant Mar 20 '18 at 19:47
  • @HansPassant Yes, I used OLE/COM Object Viewer shortly after originally posting the question and did see these missing properties listed under properties but did not see the associated Get/Set methods. See my latest edit to original question dated 3-20-18 for more details. – JonN Mar 20 '18 at 21:09
  • @HansPassant When I open the .tlb file with Visual Studio 2013 and open the SigPlusLib folder I see all the methods and the properties including ImageFileFormat but I do not see the Get/Set methods IE: GetImageFileFormat() and SetImageFileFormat() – JonN Mar 20 '18 at 23:56
  • @HansPassant I also tried #import as alternative to Class Wizard but it doesn't compile. See original post EDIT 3-20-18 17:00PDT – JonN Mar 21 '18 at 00:37
  • Bounty expired but still looking for solution. – JonN Mar 27 '18 at 20:37

0 Answers0