We help IT Professionals succeed at work.

We've partnered with Certified Experts, Carl Webster and Richard Faulkner, to bring you two Citrix podcasts. Learn about 2020 trends and get answers to your biggest Citrix questions!Listen Now

x

How to create ActiveX control supporting Automation

Medium Priority
789 Views
Last Modified: 2013-11-20
Hi,
      I have created a basic ActiveX control using MSVC++ 5.0 Control Wizard. I added one arbitrary method, and compiled it.  
      When I use the control in VB 5.0, it works as long as I place the control on the form and access its method that way. But if I use automation, such as in the following VB code,

Dim obj as Object
set obj = CreateObject("MyControl.mycontrol.1")
obj.MyMethod  ,

I get the error:

Run-time error -2147418113 (8000ffff)
Method 'MyMethod' of object '_DMyControl' failed.

(The error number is S_UNEXPECTED in VC++, and it occurs because the m_bInitialized member variable is false in the instance of COleControl - I tried the equivalent of "CreateObject" in VC++ and the I got the same error)

There must be something simple that I am missing out on...I thank you in advance for any help.

..............................Lee

(FYI, the CreateObject statement seems to function properly, as I do get a pointer to my control when debugging)

PS: Instead of trying to instantiate the other object using "CreateObject" (or the equivalent set of C++ functions), can one get a pointer to an ActiveX control from within another ActiveX control given that they both reside in the same container???
Comment
Watch Question

Author

Commented:
Edited text of question

Author

Commented:
Adjusted points to 200

Author

Commented:
Edited text of question

Commented:
Can you show your VC++ container code ?

Author

Commented:
Hi Gelbert,
   Sorry, I guess I was not clear enough. The container is a VB form (although I should not depend on one specific container, of course). If you mean my VC++ code which instantiates the ActiveX control - it performs the same function as CreateObject(), but here it is anyway...

        // Set GUID
      long a = 1163048501;  
      short b = 13338;            
      short c = 4561;      
      unsigned char d[8] = {150,34,0,0,192,52,105,210};

      GUID g;
      g.Data1 = a;
      g.Data2 = b;
      g.Data3 = c;
      for (int i =0; i<=7; i++)
            g.Data4[i] = d[i];      

      if (int r = OleInitialize(NULL) != S_OK)
            TRACE("OleInitialize() failed!\n");

      REFCLSID CLSID_CMyObject = g;

      HRESULT hresult;
      IUnknown FAR* punk;
      IDispatch FAR* pdisp = (IDispatch FAR*)NULL;

      LPCTSTR methodName = "putNoText";

      USES_CONVERSION;

      LPCOLESTR lpOleStr = T2COLE(methodName);

      DISPID dispid;
      DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};

      hresult = CoCreateInstance(CLSID_CMyObject, NULL, CLSCTX_INPROC_SERVER, //CLSCTX_SERVER,
                        IID_IUnknown, (void FAR* FAR*)&punk);

      if (hresult != S_OK)
            TRACE("CoCreateInstance failed!\n");

      hresult = punk->QueryInterface(IID_IDispatch,
                  (void FAR* FAR*)&pdisp);
      if (hresult != S_OK)
            TRACE("QueryInterface (IDispatch) failed!\n");

      IUnknown FAR* punknown = (IUnknown FAR*)NULL;
      LPDWORD lpdwRegister = (LPDWORD)malloc(64);
      hresult = punk->QueryInterface(IID_IUnknown,
                  (void FAR* FAR*)&punknown);

      if (hresult != S_OK)
            TRACE("QueryInterface (IUnknown) failed!\n");

      hresult = CoRegisterClassObject(CLSID_CMyObject, punknown, CLSCTX_INPROC_SERVER,
                        REGCLS_MULTIPLEUSE, lpdwRegister);

      if (hresult != S_OK)
            TRACE("CoRegisterClassObject() failed!\n");

      unsigned long FAR* pdwRegister = (unsigned long FAR*)malloc(64);
      hresult = RegisterActiveObject(punknown, CLSID_CMyObject, ACTIVEOBJECT_STRONG,
            pdwRegister);

      if (hresult != S_OK)
            TRACE("RegisterActiveObject() failed!\n");

      hresult = pdisp->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpOleStr, 1,
                        LOCALE_USER_DEFAULT, &dispid);

      if (hresult != S_OK)
            TRACE("GetIDsOfNames failed!\n");

      hresult = pdisp->Invoke(
            dispid,
            IID_NULL,
            LOCALE_USER_DEFAULT,
            DISPATCH_METHOD,
            &dispparamsNoArgs, NULL, NULL, NULL);

        // This is where the failure occurs - all other functions
        // complete successfully
      if (hresult != S_OK)
            TRACE("Invoke failed!\n");


Commented:
When you use CoCreateInstance() ask for IClassFactory insterface and use it ot call IClassFactory::CreateInstance() to create instance of object

Author

Commented:
Didn't work.....
Let me make my question simpler...

1) I created an ActiveX control using VC++ 5.0 control wizard.
2) I added 1 method called "Method"

3) I created another ActiveX control using VC++ 5.0 control wizard.
4) In the second control, I am trying to invoke the method on the first control.

I have failed to do this so far, and have tried everything I could think of.  If you have any idea (or source code example) please let me know. Thanks.

P.S. I am using VB as the form on which the second control is placed.

Author

Commented:
hint: the CoCreateInstance and CreateInstance functions create an UNINITIALIZED (what does that mean?) object. The error I am getting is within the COleControl class, where the variable m_bInitialized = FALSE when it should be true. Is there someway to "initialize" an ole object that I do not know about???
Commented:
You have to load control state to initialized m_bInitialized property to TRUE by calling COleControl::Load() which is wrapper around IPersistXXX::Load() function (IPersistStorage, IPersistFile,....)

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts

Author

Commented:
I already checked that option, but I do not have a pointer to the control, but merely a pointer to its interfaces. Anyway, like I said before, my C++ code is the equivalent to the Visual Basic "CreateObject" function, and that did not work.  I think I have figured out the problem - it is that the new (VC++ 5.0) activeX wizard creates more lightweight controls than (VC++ 4) and as such have left out certain interfaces such as some automation ones, and so I need to add them manually. Thanks for the help anyway...I'll give u the points for good effort.
Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.