CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8
  1. #1
    Join Date
    Aug 2006
    Posts
    134

    Going around in circles building ActiveX control

    Greetings!

    I am trying to create an ActiveX control that will contain a third-party ActiveX control and will be compatible with an application written in C++ using Visual Studio 2008.

    If I create an MFC ActiveX control, I get no drawing surface for the control. In a similar project I did a couple of years ago using VC++ 6, I created a dialog in the control project, dropped the third-party control onto that, and then in the control's OnCreate event handler, I created the dialog box, fitted it to the control's window, and drew it. This seems like a really strange way of doing things, although it worked nicely. From what I see in VS2008, that approach is still possible.

    But why can't I get a surface to drop controls on?

    I tried creating an ATL project, and then adding an ATL control to the project. This seemed to work nicely at first. I specified that the new control would be a composite control (an option not available in the MFC version of this), and I got a drawing surface. I dropped my third-party control onto it. But then I tried to add a variable to reference that control. First I had to add a class, and I had to pick a base class. How do I know what base class to use? I used CDialog because that was what I did in the VC6 project, and because the Automation radio button was enabled with it. But when I clicked on my third-party control and clicked Add Variable, the Control Variable checkbox was disabled and all I could add was plain objects like ints and doubles. I tried creating a new control and dropped a plaiin ordinary button onto it, and I couldn't create a member variable for it either!

    What am I doing wrong?

    Thank you very much!

    RobR

  2. #2
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Going around in circles building ActiveX control

    What am I doing wrong?
    You're trying to think of MFC and ATL as something alike, and trying to extend your experience from one library to other one. This is where you're completely wrong. They (MFC and ATL) are not the same, and implement absolutely different approaches to dealing with windowed controls. Besides (and this seems kinda natural to me), a wizard for some library may not implement something you accustomed to with another library.
    Best regards,
    Igor

  3. #3
    Join Date
    Aug 2006
    Posts
    134

    Re: Going around in circles building ActiveX control

    Igor,

    Thank you very much for your reply, but it really does not help.

    I need to know how to build an ActiveX control that embeds another ActiveX control in C++ without using the Common Language Runtime using Visual Studio 2008. I do not really care if I use MFC or ATL. I just need step-by-step directions in one or the other.

    Actually, my requirement is even simpler than that. I need to use an ActiveX control on some visible element in C++, without CLR and written using Visual Studio 2008. The control can be embedded in another control, it can be in a class derived from CDialog, or it can be in a class derived from CFormView. Actually, the CFormView-derived class is preferred. What is happening is that the automatically generated class for the control uses IDispatch interfaces, while the 50 classes generated to support the class use concrete interfaces. So, the Ixxx classes referenced by the main control class do not exist and the project does not build.

    Thanks again!

    RobR

  4. #4
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Going around in circles building ActiveX control

    Well, one possible solution already was described by you: you create a borderless dialog which is going to be a child window covering all the MFC ActiveX window. The said dialog is going to play the role of a "surface to drop controls on". In MFC CDialog implements support for embedded activex controls (you may think of it as something similar to ATL composite control). You can drop your controls onto the dialog at design time (in resource editor). The only thing required at runtime is dialog creation along with making sure the dialog fits in ActriveX window sizes.

    Does this outline suffice your needs, or you really need a step-by-step instruction?
    Best regards,
    Igor

  5. #5
    Join Date
    Aug 2006
    Posts
    134

    Re: Going around in circles building ActiveX control

    Thank you for listening, Igor. My problem happens before I try to add my form to my application. The problem is that I cannot get Visual Studio to generate wrapper classes for an ActiveX control in a way that will compile and will expose the complete set of methods I need to work with the control.

    Here is a detailed explanation of what I have been trying to do, and the results I have seen. I hope you will have the patience to read it, because it's going to be long.

    The control I am trying to use is named ActiveGanttVC, and it represents a Gantt chart, which has tasks, time blocks, dependencies, and so on.

    In Visual C++ 6, I create a dialog, add the ActiveX control to it, call up the ClassWizard, select the Member Variables tab, and add a control variable for the ActiveGanttVC object. VC++6 first tells me I need to create a class for the dialog, and I have it do that. Then it tells me that classes for the ActiveX control have not been added to the project. I let it do that. It adds over 50 classes. Now the member variable is added to my dialog class, and all of the interfaces of the control have wrapper classes and I can work with the control as desired:
    Code:
    void CSOChartForm::DoSomething()
    {
    	CclsTasks tasks = m_gantt.GetTasks();
    }
    In Visual Studio 2008, I try to do the same thing. I create a dialog-based MFC application, add an ActiveGanttVC control to the dialog, right-click on the control, select Add Class to create a class for the dialog, and then right-click on the control and select Add Variable. I get no warning about building classes for the control's interfaces. I click OK. Only two files are generated, activeganttvcctl1.cpp and activeganttvcctl1.h. I try to build the project. I get over 100 errors. The first one happens in activeganttvcctl1.h, at this code:
    Code:
    IclsTasks * GetTasks()
    {
    	IclsTasks * result;
    	GetProperty(0x1, VT_DISPATCH, (void*)&result);
    	return result;
    }
    No file has been generated that contains a definition for IclsTasks.

    So I try a different tactic. I create a new dialog-based FC application project. This time, before adding the ActiveX control, I try creating classes for it myself. I right-click on the project in Solution Explorer, select Add, select Class, and choose the MFC Add Class From ActiveX Control template. I choose to add a class from the registry, and I select the ActiveGanttVC control. There is only one interface listed, _DActiveGanttVC. So, I select that one and click OK. Again, I get only two files, CDActiveGanttVC.cpp and .h. This time the program compiles, but the generated files have none of the classes or interfaces I need to actually use the control. There is no CclsTasks class, for example.

    So, back to the drawing board. A third project. This time, instead of adding the class from the registry, I select the File option and choose the ocx file. Now I get the expected long list of interfaces. I select all of them, except for _DActiveGanttVCEvents, for which VS2008 complains that it can't find the coclass. I think I can live without events, since this control will be used only for display. (But maybe not -- I'll probably need the Activate event, for example. But that doesn't matter now.) The project builds, but the main class contains a small set of rudimentary functions that do not expose what I need to use the control:
    (bodies of inline-defined functions snipped)
    Code:
    class CDActiveGanttVC : public CWnd
    {
    protected:
    	DECLARE_DYNCREATE(CDActiveGanttVC)
    public:
    	CLSID const& GetClsid()
    	virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle,
    						const RECT& rect, CWnd* pParentWnd, UINT nID, 
    						CCreateContext* pContext = NULL)
        BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, 
    				UINT nID, CFile* pPersist = NULL, BOOL bStorage = FALSE,
    				BSTR bstrLicKey = NULL)
    
    // Attributes
    public:
    
    // Operations
    public:
    
    	void Redraw()
    	BOOL InConflict(DATE StartDate, DATE EndDate, LPCTSTR RowKey, long Layer)
    	void CancelUIOperations()
    	void ResetRows()
    	void ClearSelections()
    	void ReadXML(LPCTSTR Path)
    	void WriteXML(LPCTSTR Path)
    	void SaveToBMP(LPCTSTR Path)
    	void Clear()
    	CString GetXML()
    	void SetXML(LPCTSTR sXML)
    	void AboutBox()
    };
    There is no function for getting the list of tasks, for example.

    For the fourth project, I dropped the ActiveGanttVC control on the dialog before creating the class for it. The same thing happened as with the previous project. I did notice one strange thing. The dialog class I created was Cz4Dialog. But after adding the control to my project, I found that the declaration of the control wasn't in Cz4Dialog.h. Instead, it was in Cz4Dlg.h, which I had never asked to be created. The same thing had happened with project 3, but I just thought I had typed Dlg instead of Dialog. But this time I was careful to type "Dialog".

    Project 5 is identical to project 3, except that I selected the ActiveGanttVC.tlb file instead of the ActiveGanttVC.ocx file. Everything else, including the result, was identical.

    For project 6, I chose the MFC Add Class From Typelib template. This time, when I select the ActiveGanttVC control from the registry, I get the complete set of interfaces. And, when I click the >> button, all of them are represented in the classes list. There's no problem with the _DActiveGanttVCEvents interface. And it looks as though the CDActiveGanttVC.h file contains definitions for all of the methods I need to work with the control. I thought for a moment that was going to work. No such luck. First, the _Font.h file contains two copies of itself. Something wrote into that file, and then wrote the same thing into the file again. But after removing the second half of that file, I'm back to the IclsTasks problem. I've got a whole bunch of classes, include CclsTasks, but I've got the main wrapper class for the control defining a method named GetTasks that returns a pointer to in IclsTasks object, which is not defined.


    At this point, I've run out of choices. I hope that I've made my problem clear. I need to get Visual Studio 2008 to generate wrapper classes for an ActiveX control, but I have found no way to generate a complete set that will compile and expose all of the methods I need to work with the control.

    Thank you very much for taking the time to wade through all of this.

    RobR

  6. #6
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Going around in circles building ActiveX control

    Okay, at last I got your problem. As for me, I usually use "MFC class from TypeLibrary" or #import directive approaches. Both these worked really fine for me in my projects.

    Unfortunately, I rarely use VS2008, so have no experience with that kind of issues. BTW, are you sure you have all the VS service packs applied? And looked through MS knowledge base?
    Last edited by Igor Vartanov; March 8th, 2011 at 12:12 PM.
    Best regards,
    Igor

  7. #7
    Join Date
    Aug 2006
    Posts
    134

    Re: Going around in circles building ActiveX control

    Thanks for taking the time to read that, Igor. What compiler do you usually use?

    I'll see if I can find examples elsewhere in our application of the use of #import. The link you provided discussed how to put #import into your code, but I didn't see how to associate an object of the type generated as a result of #import with the control dropped onto the dialog.

    RobR

  8. #8
    Join Date
    Aug 2006
    Posts
    134

    Smile Re: Going around in circles building ActiveX control

    By George, I think I've got it!

    The first key was the realization that IclsTasks, one of the undefined classes in the main wrapper class's header file, was only used as a pointer. So I didn't need to know where its definition is. All I needed to do was to forward declare it, and all other undeclared classes in that header file. And in the other main header file. Yes, there's two of them, and I don't know why. When the class is first imported from the type library, one of the generated files is CDActiveGanttVC.h. And then when I drop the ActiveX control onto my dialog, a file named activeganttvcctl1.h is generated. It is very similar (maybe even identical) to CDActiveGanttVC.h.

    The next key was the realization that every generated wrapper class had a constructor that takes an LPDISPATCH pointer. So all I had to do was use those pointers to create wrapper objects, and everything works.

    There is one other anomaly. One of the generated classes, _Font.h, contains two copies of the same code. So, of course, when it is used, the compiler flags the second copy as a redefinition of the class.

    RobR

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured