Problem firing an event from ATL to VB which passes a SAFEARRAY 
Author Message
 Problem firing an event from ATL to VB which passes a SAFEARRAY

I am writing an ATL object (an ActiveX control) which I want to pass a
buffer of bytes (of variable length), to a VB application.  I am using
a SAFEARRAY to do this.  My problem is that although the Event fires,
VB never seems to receive the event.

In my ATL project (using VC6), I declare the callback event in the IDL
file as follows:

dispinterface _ITestSafeArrayEvents
{
    properties:
    methods:
        [id(2), helpstring("method Callback")] HRESULT CallBack ([in]
SAFEARRAY *Array);

Quote:
};

Incidently, I found that if I declare "CallBack ([in] SAFEARRAY
Array)" as suggested by other posters in the past, that the IDL
compiler complains about Array not being an oleautomation type, and VB
refuses to use that as an event.

Having implemented the connection point (using the Dev Studio wizard),
it generates the code below.  My application code generates a
safearray (using code I know works from another project), then calls
Fire_CallBack passing it a pointer to that safearray.  Stepping into
the de{*filter*}, pDispatch->Invoke (...) definately gets called.  However
VB just doesn't receive this event (other events do work OK).

Should I modify my event handler, or have I completed missed
something?

Thanks
Jon

        HRESULT Fire_CallBack(tagSAFEARRAY * Array)
        {
                CComVariant varResult;
                T* pT = static_cast<T*>(this);
                int nConnectionIndex;
                CComVariant* pvars = new CComVariant[1];
                int nConnections = m_vec.GetSize();

                for (nConnectionIndex = 0; nConnectionIndex < nConnections;
nConnectionIndex++)
                {
                        pT->Lock();
                        CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
                        pT->Unlock();
                        IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
                        if (pDispatch != NULL)
                        {
                                VariantClear(&varResult);
                                pvars[0] = Array;
                                DISPPARAMS disp = { pvars, NULL, 1, 0 };
                                pDispatch->Invoke(0x2, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
                        }
                }
                delete[] pvars;
                return varResult.scode;

        }



Mon, 19 Jul 2004 18:41:47 GMT  
 Problem firing an event from ATL to VB which passes a SAFEARRAY
There was a typo in my question... the IDL looks like this:

        dispinterface _ITestSafeArrayEvents
        {
                properties:
                methods:
                [id(2), helpstring("method Callback")] HRESULT CallBack ([in]
SAFEARRAY(BYTE) *D2BMsg);
        };

Quote:

> I am writing an ATL object (an ActiveX control) which I want to pass a
> buffer of bytes (of variable length), to a VB application.  I am using
> a SAFEARRAY to do this.  My problem is that although the Event fires,
> VB never seems to receive the event.

> In my ATL project (using VC6), I declare the callback event in the IDL
> file as follows:

> dispinterface _ITestSafeArrayEvents
> {
>     properties:
>     methods:
>         [id(2), helpstring("method Callback")] HRESULT CallBack ([in]
> SAFEARRAY *Array);
> };

> Incidently, I found that if I declare "CallBack ([in] SAFEARRAY
> Array)" as suggested by other posters in the past, that the IDL
> compiler complains about Array not being an oleautomation type, and VB
> refuses to use that as an event.

> Having implemented the connection point (using the Dev Studio wizard),
> it generates the code below.  My application code generates a
> safearray (using code I know works from another project), then calls
> Fire_CallBack passing it a pointer to that safearray.  Stepping into
> the de{*filter*}, pDispatch->Invoke (...) definately gets called.  However
> VB just doesn't receive this event (other events do work OK).

> Should I modify my event handler, or have I completed missed
> something?

> Thanks
> Jon

>    HRESULT Fire_CallBack(tagSAFEARRAY * Array)
>    {
>            CComVariant varResult;
>            T* pT = static_cast<T*>(this);
>            int nConnectionIndex;
>            CComVariant* pvars = new CComVariant[1];
>            int nConnections = m_vec.GetSize();

>            for (nConnectionIndex = 0; nConnectionIndex < nConnections;
> nConnectionIndex++)
>            {
>                    pT->Lock();
>                    CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
>                    pT->Unlock();
>                    IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
>                    if (pDispatch != NULL)
>                    {
>                            VariantClear(&varResult);
>                            pvars[0] = Array;
>                            DISPPARAMS disp = { pvars, NULL, 1, 0 };
>                            pDispatch->Invoke(0x2, IID_NULL, LOCALE_USER_DEFAULT,
> DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
>                    }
>            }
>            delete[] pvars;
>            return varResult.scode;

>    }



Mon, 19 Jul 2004 21:35:34 GMT  
 Problem firing an event from ATL to VB which passes a SAFEARRAY
This is not going to work, because the wizard does not support
references. You'll have to set up the VARIANT as a reference
manually:

Quote:
> > pvars[0] = Array;

becomes

  V_VT(pvars) = VT_BYREF | VT_ARRAY | VT_<arrayelemtype>;
  V_ARRAYREF(pvars) = Array;

Change the array to have double indirection in the method too:

HRESULT Fire_CallBack(SAFEARRAY **Array)

Also, get in the habit of specifying void in dispinterfaces:

[id(2), helpstring("method Callback")]
void CallBack ([in] SAFEARRAY(BYTE) *D2BMsg);

--
=====================================
Alexander Nickolov
Microsoft MVP [VC], MCSD

MVP VC FAQ: http://www.*-*-*.com/
=====================================

Quote:

> There was a typo in my question... the IDL looks like this:

> dispinterface _ITestSafeArrayEvents
> {
> properties:
> methods:
> [id(2), helpstring("method Callback")] HRESULT CallBack ([in]
> SAFEARRAY(BYTE) *D2BMsg);
> };


> > I am writing an ATL object (an ActiveX control) which I want to pass a
> > buffer of bytes (of variable length), to a VB application.  I am using
> > a SAFEARRAY to do this.  My problem is that although the Event fires,
> > VB never seems to receive the event.

> > In my ATL project (using VC6), I declare the callback event in the IDL
> > file as follows:

> > dispinterface _ITestSafeArrayEvents
> > {
> >     properties:
> >     methods:
> >         [id(2), helpstring("method Callback")] HRESULT CallBack ([in]
> > SAFEARRAY *Array);
> > };

> > Incidently, I found that if I declare "CallBack ([in] SAFEARRAY
> > Array)" as suggested by other posters in the past, that the IDL
> > compiler complains about Array not being an oleautomation type, and VB
> > refuses to use that as an event.

> > Having implemented the connection point (using the Dev Studio wizard),
> > it generates the code below.  My application code generates a
> > safearray (using code I know works from another project), then calls
> > Fire_CallBack passing it a pointer to that safearray.  Stepping into
> > the de{*filter*}, pDispatch->Invoke (...) definately gets called.  However
> > VB just doesn't receive this event (other events do work OK).

> > Should I modify my event handler, or have I completed missed
> > something?

> > Thanks
> > Jon

> > HRESULT Fire_CallBack(tagSAFEARRAY * Array)
> > {
> > CComVariant varResult;
> > T* pT = static_cast<T*>(this);
> > int nConnectionIndex;
> > CComVariant* pvars = new CComVariant[1];
> > int nConnections = m_vec.GetSize();

> > for (nConnectionIndex = 0; nConnectionIndex < nConnections;
> > nConnectionIndex++)
> > {
> > pT->Lock();
> > CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
> > pT->Unlock();
> > IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
> > if (pDispatch != NULL)
> > {
> > VariantClear(&varResult);
> > pvars[0] = Array;
> > DISPPARAMS disp = { pvars, NULL, 1, 0 };
> > pDispatch->Invoke(0x2, IID_NULL, LOCALE_USER_DEFAULT,
> > DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
> > }
> > }
> > delete[] pvars;
> > return varResult.scode;

> > }



Tue, 20 Jul 2004 04:37:54 GMT  
 Problem firing an event from ATL to VB which passes a SAFEARRAY
for me best way is to you VARIANT wich will contain SAFEARRAY
HRESULT Fire_CallBack(VARIANT Array)

michail

This is not going to work, because the wizard does not support
references. You'll have to set up the VARIANT as a reference
manually:

Quote:
> > pvars[0] = Array;

becomes

  V_VT(pvars) = VT_BYREF | VT_ARRAY | VT_<arrayelemtype>;
  V_ARRAYREF(pvars) = Array;

Change the array to have double indirection in the method too:

HRESULT Fire_CallBack(SAFEARRAY **Array)

Also, get in the habit of specifying void in dispinterfaces:

[id(2), helpstring("method Callback")]
void CallBack ([in] SAFEARRAY(BYTE) *D2BMsg);

--
=====================================
Alexander Nickolov
Microsoft MVP [VC], MCSD

MVP VC FAQ: http://www.*-*-*.com/
=====================================


Quote:
> There was a typo in my question... the IDL looks like this:

> dispinterface _ITestSafeArrayEvents
> {
> properties:
> methods:
> [id(2), helpstring("method Callback")] HRESULT CallBack ([in]
> SAFEARRAY(BYTE) *D2BMsg);
> };




Quote:
> > I am writing an ATL object (an ActiveX control) which I want to pass a
> > buffer of bytes (of variable length), to a VB application.  I am using
> > a SAFEARRAY to do this.  My problem is that although the Event fires,
> > VB never seems to receive the event.

> > In my ATL project (using VC6), I declare the callback event in the IDL
> > file as follows:

> > dispinterface _ITestSafeArrayEvents
> > {
> >     properties:
> >     methods:
> >         [id(2), helpstring("method Callback")] HRESULT CallBack ([in]
> > SAFEARRAY *Array);
> > };

> > Incidently, I found that if I declare "CallBack ([in] SAFEARRAY
> > Array)" as suggested by other posters in the past, that the IDL
> > compiler complains about Array not being an oleautomation type, and VB
> > refuses to use that as an event.

> > Having implemented the connection point (using the Dev Studio wizard),
> > it generates the code below.  My application code generates a
> > safearray (using code I know works from another project), then calls
> > Fire_CallBack passing it a pointer to that safearray.  Stepping into
> > the de{*filter*}, pDispatch->Invoke (...) definately gets called.  However
> > VB just doesn't receive this event (other events do work OK).

> > Should I modify my event handler, or have I completed missed
> > something?

> > Thanks
> > Jon

> > HRESULT Fire_CallBack(tagSAFEARRAY * Array)
> > {
> > CComVariant varResult;
> > T* pT = static_cast<T*>(this);
> > int nConnectionIndex;
> > CComVariant* pvars = new CComVariant[1];
> > int nConnections = m_vec.GetSize();

> > for (nConnectionIndex = 0; nConnectionIndex < nConnections;
> > nConnectionIndex++)
> > {
> > pT->Lock();
> > CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
> > pT->Unlock();
> > IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
> > if (pDispatch != NULL)
> > {
> > VariantClear(&varResult);
> > pvars[0] = Array;
> > DISPPARAMS disp = { pvars, NULL, 1, 0 };
> > pDispatch->Invoke(0x2, IID_NULL, LOCALE_USER_DEFAULT,
> > DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
> > }
> > }
> > delete[] pvars;
> > return varResult.scode;

> > }



Tue, 20 Jul 2004 07:09:35 GMT  
 Problem firing an event from ATL to VB which passes a SAFEARRAY
You may have to do this in the following way.

HRESULT  Fire_CallBack(VARIANT *pv)
 {  
SAFEARRAY *sa;  
sa = SafeArrayCreate(...);  

VARIANT v;  
VariantInit(&v);
 v.vt = VT_ARRAY | VT_UI1;  
v.pparray = &sa;  
*pv = v;

Quote:
}

The following article has relevant information.

How To Pass Binary Data Between an ActiveX Control and VB    
ID: Q154172

Deba Sarma[MSFT]

This posting is provided AS IS with no warranties, and confers no rights.



Tue, 27 Jul 2004 02:24:29 GMT  
 Problem firing an event from ATL to VB which passes a SAFEARRAY
That's nonsense. As soon as the function returns, sa goes out of scope,
so the pointer you stuff into VARIANT becomes invalid. Also, if you
assign to pparray, the type should be VT_UI1 | VT_ARRAY | VT_BYREF. If
you specify the type as VT_UI1 | VT_ARRAY, you should put SAFEARRAY*
pointer into parray.
--
With best wishes,
    Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken


Quote:
> You may have to do this in the following way.

> HRESULT  Fire_CallBack(VARIANT *pv)
>  {
> SAFEARRAY *sa;
> sa = SafeArrayCreate(...);

> VARIANT v;
> VariantInit(&v);
>  v.vt = VT_ARRAY | VT_UI1;
> v.pparray = &sa;
> *pv = v;
> }

> The following article has relevant information.

> How To Pass Binary Data Between an ActiveX Control and VB
> ID: Q154172

> Deba Sarma[MSFT]

> This posting is provided AS IS with no warranties, and confers no
rights.



Tue, 27 Jul 2004 02:37:17 GMT  
 Problem firing an event from ATL to VB which passes a SAFEARRAY
On Thu, 7 Feb 2002 13:37:17 -0500, "Igor Tandetnik"

Quote:

>That's nonsense. As soon as the function returns, sa goes out of scope,
>so the pointer you stuff into VARIANT becomes invalid. Also, if you

I'd disagree - sa is a pointer.  The SAFEARRAY created will not go out
of scope, even when sa is abandoned.

I've done it this way myself, and never had any kind of problem..

I'm more worried about using the VARIANT v - surely the parameter pv
can be used more easily?  v seems surplus to requirements to me...
now that WILL go out of scope.

Course if anyone knows different...

James



Tue, 27 Jul 2004 03:18:42 GMT  
 Problem firing an event from ATL to VB which passes a SAFEARRAY
I usually do it this way:

V_VT(pv) = VT_ARRAY | VT_UI1;
V_ARRAY(pv) = sa;

or

V_VT(&v) = VT_ARRAY | VT_UI1;
V_ARRAY(&v) = sa;
VariantInit(pv);
*pv = v;

--
Jack


Quote:
> On Thu, 7 Feb 2002 13:37:17 -0500, "Igor Tandetnik"

> >That's nonsense. As soon as the function returns, sa goes out of scope,
> >so the pointer you stuff into VARIANT becomes invalid. Also, if you

> I'd disagree - sa is a pointer.  The SAFEARRAY created will not go out
> of scope, even when sa is abandoned.

> I've done it this way myself, and never had any kind of problem..

> I'm more worried about using the VARIANT v - surely the parameter pv
> can be used more easily?  v seems surplus to requirements to me...
> now that WILL go out of scope.

> Course if anyone knows different...

> James



Tue, 27 Jul 2004 03:37:47 GMT  
 Problem firing an event from ATL to VB which passes a SAFEARRAY


Quote:
> On Thu, 7 Feb 2002 13:37:17 -0500, "Igor Tandetnik"

> >That's nonsense. As soon as the function returns, sa goes out of
scope,
> >so the pointer you stuff into VARIANT becomes invalid. Also, if you

> I'd disagree - sa is a pointer.  The SAFEARRAY created will not go out
> of scope, even when sa is abandoned.

Yeah, but the code stuffs pointer to a pointer into the VARIANT (note
pparray = &sa). The intermediate pointer is a local variable that goes
out of scope, after which a) VARIANT holds a dangling SAFEARRAY**
pointer and b) there's no way to access original SAFEARRAY* to free it,
thus we have a memory leak. Note also the inconsistency between what is
put into variant and what type it is given.

Quote:
> I've done it this way myself, and never had any kind of problem..

You very likely did something different. The code as written has
absolutely no chance of working.

Quote:
> I'm more worried about using the VARIANT v - surely the parameter pv
> can be used more easily?  v seems surplus to requirements to me...
> now that WILL go out of scope.

When one structure is assigned to another (as in *pv = v) the compiler
performs bitwise copy. So *pv will be set up exactly as v. Not terribly
efficient, but kosher.
--
With best wishes,
    Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken



Tue, 27 Jul 2004 03:42:22 GMT  
 
 [ 9 post ] 

 Relevant Pages 

1. Problem with VB clients accessing SAFEARRAY passed from my ATL server

2. URGENT : Passing SAFEARRAY of UDT from ATL DLL to VB

3. Passing a 2D SafeArray from VB client to ATL COM component

4. Fast OLE event firing, VB got problems :(

5. ATL COM Component firing events into VBScript event sink

6. ATL DLL event sink with a VB ActiveX DLL event source

7. creating a sink in VC to handle events fired by VB Com Object

8. Fire events to VB

9. Fire events to VB client

10. How to catch events fired by VB-written ActiveX DLL in VC++ client

11. firing events from a worker thread to VB and MFC clients

12. Firing Events from VC to VB

 

 
Powered by phpBB® Forum Software