Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

ATL generated code for IDispatch Invoke method is incorrect

81 views
Skip to first unread message

Edwin Schild

unread,
Jan 17, 2002, 7:28:08 AM1/17/02
to
Ok I have reported a problem about 2 days ago. I have moved all the
attributed interface definitions into 1 single include file. Now VB6 doesn't
crash anymore. However when I expanded the objects in the watch window, I
got incorrect values or unknown stuff for several properties. When running
the VB6 code I didn't see these incorrect results.
Looking in the VS.NET debugger I found out that the get_MainFrames method
was called twice when viewing the properties and the get_Name was never
called. So I set a breakpoint in the get_MainFrames to see where the calls
came from using the call stack. The call stack showed me that the first call
used dispIdMember 1 and the second call used dispIDMember 0. Both calls
resulted however in the get_MainFrames function. Since this is incorrect I
decided to look into the disassembly to see where it comes from. Then I
remembered that there is an option to generate an output file which shows
the generated code. The code of the interface is shown below.

First of all note that there is a fall through at the end of the case 0
block. This is no problem if at least one of the sub blocks is executed.
Second note that the first if (wFlags & 1) test in the case 0 block is
repeated in the matching else statement. So if the first if fails, the else
block also fails.
Also note that wFlags is the action that should be taken is either
DISPATCH_PROPERTYGET = 2 or DISPATCH_PROPERTYPUT = 4 so the test ALWAYS
fails.

#injected_line 49 "d:\\project\\plaza\\engine3\\ctrlmainframe.h"
virtual HRESULT STDMETHODCALLTYPE ICtrlMainFrame::Invoke(
/* [in] */ DISPID dispIdMember,
/* [in] */ REFIID riid,
/* [in] */ LCID lcid,
/* [in] */ WORD wFlags,
/* [out][in] */ DISPPARAMS *pDispParams,
/* [out] */ VARIANT *pVarResult,
/* [out] */ EXCEPINFO *pExcepInfo,
/* [out] */ UINT *puArgErr)
{
(void) riid;
(void) dispIdMember;
(void) lcid;
(void) wFlags;
(void) pExcepInfo;
(void) puArgErr;
HRESULT hr = S_OK;
if (pDispParams == 0)
{
return DISP_E_BADVARTYPE;
}
if (pDispParams->cArgs > 1)
{
return DISP_E_BADPARAMCOUNT;
}
if (pVarResult != 0)
{
VariantInit(pVarResult);
}
VARIANT* rgpVars[1];
UINT index = 0;
for (; index < pDispParams->cArgs; ++index)
{
rgpVars[index] = &pDispParams->rgvarg[index];
}
VARIANT* v;
switch (dispIdMember)
{
case 0:
{
if (wFlags & 1) // !!!!!! This test always fails because
DISPATCH_PROPERTYGET = 2, DISPATCH_PROPERTYPUT = 4
{
if (pDispParams->cArgs != 0)
{
return DISP_E_BADPARAMCOUNT;
}
BSTR i1;
hr = ((::ICtrlMainFrame*) this)->get_Name(&i1);
if (pVarResult != 0) the
{
V_VT(pVarResult) = VT_BSTR;
V_BSTR(pVarResult) = (BSTR) i1;
}
break;
}
else
if (wFlags & 1) // !!!!!! This is the same test as above so it
also fails
{
if (pDispParams->cArgs != 1)
{
return DISP_E_BADPARAMCOUNT;
}
v = rgpVars[0];
if (v->vt != VT_BSTR && FAILED(__VariantChangeType(v, v,
VT_BSTR)))
{
if (puArgErr != 0)
{
*puArgErr = 0;
}
return DISP_E_TYPEMISMATCH;
}
BSTR i1 = (BSTR) V_BSTR(v);
hr = ((::ICtrlMainFrame*) this)->put_Name(i1);
break;
}
} // !!!!!! There is no break here (doesn't have to be if the above
code was correct)
case 1:
{
if (pDispParams->cArgs != 0) {
return DISP_E_BADPARAMCOUNT;
}
IDispatch* i1;
hr = ((::ICtrlMainFrame*) this)->get_MainFrames(&i1);
if (pVarResult != 0) {
V_VT(pVarResult) = VT_DISPATCH;
V_DISPATCH(pVarResult) = (IDispatch*) i1;
}
break;
}
case 2:
{
if (pDispParams->cArgs != 0) {
return DISP_E_BADPARAMCOUNT;
}
ICtrlRecorders* i1;
hr = ((::ICtrlMainFrame*) this)->get_Recorders(&i1);
if (pVarResult != 0) {
V_VT(pVarResult) = VT_DISPATCH;
V_DISPATCH(pVarResult) = (IDispatch*) i1;
}
break;
}
case 3:
{
if (pDispParams->cArgs != 0) {
return DISP_E_BADPARAMCOUNT;
}
IDispatch* i1;
hr = ((::ICtrlMainFrame*) this)->get_AcquisitionSystem(&i1);
if (pVarResult != 0) {
V_VT(pVarResult) = VT_DISPATCH;
V_DISPATCH(pVarResult) = (IDispatch*) i1;
}
break;
}
case 5:
{
if (wFlags & 1) {
if (pDispParams->cArgs != 0) {
return DISP_E_BADPARAMCOUNT;
}
double i1;
hr = ((::ICtrlMainFrame*) this)->get_Time(&i1);
if (pVarResult != 0) {
V_VT(pVarResult) = VT_R8;
V_R8(pVarResult) = i1;
}
break;
}
else
if (wFlags & 1) {
if (pDispParams->cArgs != 1) {
return DISP_E_BADPARAMCOUNT;
}
v = rgpVars[0];
if (v->vt != VT_R8 && FAILED(__VariantChangeType(v, v, VT_R8))) {
if (puArgErr != 0) {
*puArgErr = 0;
}
return DISP_E_TYPEMISMATCH;
}
double i1 = V_R8(v);
hr = ((::ICtrlMainFrame*) this)->put_Time(i1);
break;
}
}
default:
return DISP_E_MEMBERNOTFOUND;
}
return hr;
}


Edwin Schild
Nicolet Technologies B.V.

Liu

unread,
Jan 18, 2002, 9:16:24 PM1/18/02
to
Hi Edwin,

Could you please give me the definition of your objects and methods? It
would be great if you can give me a simple repro case.

Thanks

Liu

"Edwin Schild" <edwin....@nicolet.shhhh.nl> wrote in message
news:#GK4tJ1nBHA.2564@tkmsftngp04...

Liu [MSFT]

unread,
Jan 22, 2002, 8:47:04 PM1/22/02
to
Hi Edwin,

Thanks for your repro case.
It looks like we have a problem with PCH and attributed dispatch interface.
However, a simple workaround can be done by not using PCH or removing your
interface declaration out of PCH.

//Liu


"Edwin Schild" <edwin....@nicolet.shhhh.nl> wrote in message

news:#AAARfloBHA.2084@tkmsftngp04...
> Hi Liu,
>
> Attached is my complete project also with the generated mgr files. In the
> file CtrlMainFrame.mgr.h you can see that the case 0 in the Invoke method
is
> incorrect.
>
> Edwin
>
>
> "Liu" <lxi...@microsoft.com> wrote in message
> news:OG9JN9IoBHA.2564@tkmsftngp04...

Edwin Schild

unread,
Jan 23, 2002, 6:25:08 AM1/23/02
to
Hi Liu,

Thanks for the reply. I fixed the problem by using the IDispatchImpl
template in my class definitions.
I have tested it by removing the file from the PCH and that solves the
problem I had with the incorrect property values. I have also been looking
into the crash I had in VB6. When I use the interface definitions in the
class include files instead of the single include file, the code generated
to get an interface sometimes changes from returning an IDispatch interface
to returning an IUnknown interface (see code below). I don't know how VB6
handles it but when an IUnknown is returned it should do a QueryInterface to
get the IDispatch interface. I have tested the code using a VC program which
does a IDispatch QI on the CtrlAcquisitionSystem and then calls the Invoke
method to get the CtrlMainFrames object. The resulting interface is then
QI'ed for IDispatch and then I have no problems. If I just cast the
resulting IUnknown to a IDispacth* then I have a problem in my program. So
it looks like VB6 watch window does the same but I cannot imagine such a
stupid bug in VB6.

Edwin

Example of output in the MGR files.
ICtrlMainFrames* i1;

hr = ((::ICtrlAcquisitionSystem*) this)->get_MainFrames(&i1);

if (pVarResult != 0) {

V_VT(pVarResult) = VT_DISPATCH;

V_DISPATCH(pVarResult) = (IDispatch*) i1;

}

changed to

ICtrlMainFrames* i1;

hr = ((::ICtrlAcquisitionSystem*) this)->get_MainFrames(&i1);

if (pVarResult != 0) {

V_VT(pVarResult) = VT_UNKNOWN;

V_UNKNOWN(pVarResult) = (IUnknown*) i1;

}

"Liu [MSFT]" <lxi...@microsoft.com> wrote in message
news:ebFuc$6oBHA.1804@tkmsftngp02...

Liu [MSFT]

unread,
Jan 25, 2002, 1:11:43 AM1/25/02
to
Edwin,

When you include the interface definition into the class definition header,
I believe you have to use forward declarations.
However, when a forward declaration of an interface is used in another class
definition header, the attributes for this forward declared interface must
be included. Otherwise, compiler couldn't collect enough information to
generate accurate injected code.
Could you please check your code and see if your forward declaration is
fully attributed and all attributes match the attributes in its own
definition? If compiler still fails to generate the right injected code,
please let me know.

Thanks a lot

//Liu

"Edwin Schild" <edwin....@nicolet.shhhh.nl> wrote in message

news:OJiRNEApBHA.2212@tkmsftngp05...

Edwin Schild

unread,
Jan 25, 2002, 9:31:18 AM1/25/02
to
Hi Liu,

I have copied some of the attributes and now it seems to generate the
correct code.
My first forward declaration looked like:


[object]
__interface IMainFrames;
[idl_quote("interface IMainFrames;")];

Now I changed it to

[object, dual]
__interface IMainFrames;
[idl_quote("interface IMainFrames;")];

and that solves the VT_DISPATCH/VT_UNKNOWN problem. I think that the dual
part is

Is this documented (where can I find it), a bug (which are features people
don't like), or a 'hidden feature'.
Edwin

"Liu [MSFT]" <lxi...@microsoft.com> wrote in message

news:eWPrqcWpBHA.956@tkmsftngp03...

Liu [MSFT]

unread,
Jan 25, 2002, 12:52:06 PM1/25/02
to
This is not a bug. In VS7.0 help, search "dual" in index, you would see it
is a dispatch interface which also goes through VTBL like IUnkown interface.
So dual interface has the both features of IUnknown and IDispatch
interfaces. In your case, you defined your IMainFrames interface as [dual]
which was a dispatch interface. But in the forward declaration, it was a
[object] (IUnknown only), so when compiler was parsing CtrlAcquisitionSystem
class, it found that IMainFrames* is a IUnknown pointer and generate
VT_UNKNOWN for you.

Does this make sense?

Thanks

//Liu


"Edwin Schild" <edwin....@nicolet.shhhh.nl> wrote in message

news:u7bXf0apBHA.1336@tkmsftngp02...

Paolo Severini

unread,
Jan 27, 2002, 10:31:52 AM1/27/02
to
Hi Liu,

I think I could have found another problem with the ATL generated code for
IDispatch::Invoke().
I used the wizard to create a single object with the ATL wizards, added some
method to its IDispatch-generated interface and let the attribute provider
generate the IDispatch code.
But it looks as int it if the __VariantChangeType() method is called passing
the two variants in the wrong position:

v = rgpVars[0];
if (v->vt != VT_I4 && FAILED(__VariantChangeType(v, &v0,
VT_I4)))
here 'v', the source variant, should be the second argument while 'v0', the
destination, should be the first.

Below you can find the definition file of my class and the generated mgr.

I hope that can be useful.

-- paolo


////////////////////////////////////////////////////////////////////////////
////
// Settings.h : Declaration of the CSettings

#pragma once
#include "resource.h" // main symbols

typedef CComPtr<IBasicAudio> IBasicAudioPtr;

class CPlayer;

////////////////////////////////////////////////////////////////////////////
////
// ISettings
[
object,
uuid("82D7C490-03EC-4FF0-8B15-3D0E5F5ED9E7"),
dual, helpstring("ISettings Interface"),
pointer_default(unique)
]
__interface ISettings : IDispatch
{
[id(0x00000068), propget, helpstring("Returns whether audio should be
muted.")]
HRESULT mute([out, retval] VARIANT_BOOL* pfMute);
[id(0x00000068), propput, helpstring("Returns whether audio should be
muted.")]
HRESULT mute([in] VARIANT_BOOL pfMute);
[id(0x00000066), propget, helpstring("Returns current audio Balance")]
HRESULT balance([out, retval] long* plBalance);
[id(0x00000066), propput, helpstring("Returns current audio Balance")]
HRESULT balance([in] long plBalance);
[id(0x0000006b), propget, helpstring("Returns current audio volume")]
HRESULT volume([out, retval] long* plVolume);
[id(0x0000006b), propput, helpstring("Returns current audio volume")]
HRESULT volume([in] long plVolume);
};


// _ISettingsEvents
[
dispinterface,
uuid("F3479DC2-CCA9-44EA-8D36-2EC35FB994D3"),
helpstring("_ISettingsEvents Interface")
]
__interface _ISettingsEvents
{
};


// CSettings

[
coclass,
threading("apartment"),
event_source("com"),
vi_progid("MediaPlayer.Settings"),
progid("MediaPlayer.Settings.1"),
version(1.0),
uuid("7132AEC7-D527-4A5E-ADBF-6DBCB4724075"),
helpstring("Settings Class")
]
class ATL_NO_VTABLE CSettings :
public ISettings
{
public:
CSettings();
virtual ~CSettings();

__event __interface _ISettingsEvents;

DECLARE_PROTECT_FINAL_CONSTRUCT()

HRESULT FinalConstruct()
{
return S_OK;
}

void FinalRelease()
{
}

void initialize(CPlayer* pPlayer, IBasicAudioPtr pBasicAudio);
void cleanUp()
{
_pPlayer = NULL;
_pBasicAudio = NULL;
}

// ISettings
HRESULT get_mute(VARIANT_BOOL* pfMute);
HRESULT put_mute(VARIANT_BOOL pfMute);
HRESULT get_balance(long* plBalance);
HRESULT put_balance(long plBalance);
HRESULT get_volume(long* plVolume);
HRESULT put_volume(long plVolume);

// bool ToggleMute();

private:
CPlayer* _pPlayer;
IBasicAudioPtr _pBasicAudio;
bool _bMute;
long _lVolume;

}; // CSettings

////////////////////////////////////////////////////////////////////////////
////

and this is the resulting generated mgr:

////////////////////////////////////////////////////////////////////////////
////
// Created by Microsoft (R) C/C++ Compiler Version 13.00.9466
//
// l:\projects\skinengine\src\mediaplayer\settings.mrg.h
// compiler-generated file created 01/27/02 at 15:44:03
//
// This C++ source file is intended to be a representation of the
// source code injected by the compiler. It may not compile or
// run exactly as the original source file.
//


//+++ Start Injected Code
[no_injected_text(true)]; // Suppress injected text, it has already
been injected
#pragma warning(disable: 4543) // Suppress warnings about skipping injected
text
#pragma warning(disable: 4199) // Suppress warnings from attribute providers

#pragma message("\n\nNOTE: This merged source file should be visually
inspected for correctness.\n\n")
//--- End Injected Code

// Settings.h : Declaration of the CSettings

#pragma once
#include "resource.h" // main symbols

typedef CComPtr<IBasicAudio> IBasicAudioPtr;

class CPlayer;

////////////////////////////////////////////////////////////////////////////
////
// ISettings
[
object,
uuid("82D7C490-03EC-4FF0-8B15-3D0E5F5ED9E7"),
dual, helpstring("ISettings Interface"),
pointer_default(unique)
]
__interface ISettings : IDispatch
{
[id(0x00000068), propget, helpstring("Returns whether audio should be
muted.")]
HRESULT mute([out, retval] VARIANT_BOOL* pfMute);
[id(0x00000068), propput, helpstring("Returns whether audio should be
muted.")]
HRESULT mute([in] VARIANT_BOOL pfMute);
[id(0x00000066), propget, helpstring("Returns current audio Balance")]
HRESULT balance([out, retval] long* plBalance);
[id(0x00000066), propput, helpstring("Returns current audio Balance")]
HRESULT balance([in] long plBalance);
[id(0x0000006b), propget, helpstring("Returns current audio volume")]
HRESULT volume([out, retval] long* plVolume);
[id(0x0000006b), propput, helpstring("Returns current audio volume")]
HRESULT volume([in] long plVolume);
};


// _ISettingsEvents
[
dispinterface,
uuid("F3479DC2-CCA9-44EA-8D36-2EC35FB994D3"),
helpstring("_ISettingsEvents Interface")
]
__interface _ISettingsEvents
{
};


// CSettings

[
coclass,
threading("apartment"),
event_source("com"),
vi_progid("MediaPlayer.Settings"),
progid("MediaPlayer.Settings.1"),
version(1.0),
uuid("7132AEC7-D527-4A5E-ADBF-6DBCB4724075"),
helpstring("Settings Class")
]
class ATL_NO_VTABLE CSettings :
public ISettings
,
/*+++ Added Baseclass */ public
IConnectionPointContainerImpl<CSettings>,
/*+++ Added Baseclass */ public IPropertyNotifySinkCP<CSettings>,
/*+++ Added Baseclass */ public CComCoClass<CSettings,
&__uuidof(CSettings)>,
/*+++ Added Baseclass */ public CComObjectRootEx<CComSingleThreadModel>
,
/*+++ Added Baseclass */ public IConnectionPointImpl<CSettings,
&__uuidof(::_ISettingsEvents), CComDynamicUnkArray>,
/*+++ Added Baseclass */ public
IProvideClassInfo2Impl<&__uuidof(CSettings), &__uuidof(::_ISettingsEvents)>
{
public:
CSettings();
virtual ~CSettings();

__event __interface _ISettingsEvents;

DECLARE_PROTECT_FINAL_CONSTRUCT()

HRESULT FinalConstruct()
{
return S_OK;
}

void FinalRelease()
{
}

void initialize(CPlayer* pPlayer, IBasicAudioPtr pBasicAudio);
void cleanUp()
{
_pPlayer = NULL;
_pBasicAudio = NULL;
}

// ISettings
HRESULT get_mute(VARIANT_BOOL* pfMute);
HRESULT put_mute(VARIANT_BOOL pfMute);
HRESULT get_balance(long* plBalance);
HRESULT put_balance(long plBalance);
HRESULT get_volume(long* plVolume);
HRESULT put_volume(long plVolume);

// bool ToggleMute();

private:
CPlayer* _pPlayer;
IBasicAudioPtr _pBasicAudio;
bool _bMute;
long _lVolume;


//+++ Start Injected Code For Attribute 'event'
#injected_line 56 "l:\\projects\\skinengine\\src\\mediaplayer\\settings.h"
virtual HRESULT STDMETHODCALLTYPE ISettings::Invoke(

VARIANT v0;
VARIANT* v;
switch (dispIdMember) {
case 102:
{
if (wFlags & 2) {


if (pDispParams->cArgs != 0) {
return DISP_E_BADPARAMCOUNT;
}

long i1;
hr = ((::ISettings*) this)->get_balance(&i1);
if (pVarResult != 0) {
V_VT(pVarResult) = VT_I4;
V_I4(pVarResult) = i1;
}
break;
}
else
if (wFlags & 4) {


if (pDispParams->cArgs != 1) {
return DISP_E_BADPARAMCOUNT;
}
v = rgpVars[0];

if (v->vt != VT_I4 && FAILED(__VariantChangeType(v, &v0,
VT_I4))) {


if (puArgErr != 0) {
*puArgErr = 0;
}
return DISP_E_TYPEMISMATCH;
}

long i1 = V_I4(v);
hr = ((::ISettings*) this)->put_balance(i1);
break;
}
}
case 104:
{
if (wFlags & 2) {


if (pDispParams->cArgs != 0) {
return DISP_E_BADPARAMCOUNT;
}

VARIANT_BOOL i1;
hr = ((::ISettings*) this)->get_mute(&i1);
if (pVarResult != 0) {
V_VT(pVarResult) = VT_BOOL;
V_BOOL(pVarResult) = (VARIANT_BOOL) i1;
}
break;
}
else
if (wFlags & 4) {


if (pDispParams->cArgs != 1) {
return DISP_E_BADPARAMCOUNT;
}
v = rgpVars[0];

if (v->vt != VT_BOOL && FAILED(__VariantChangeType(v,
&v0, VT_BOOL))) {


if (puArgErr != 0) {
*puArgErr = 0;
}
return DISP_E_TYPEMISMATCH;
}

VARIANT_BOOL i1 = (VARIANT_BOOL) V_BOOL(v);
hr = ((::ISettings*) this)->put_mute(i1);
break;
}
}
case 107:
{
if (wFlags & 2) {


if (pDispParams->cArgs != 0) {
return DISP_E_BADPARAMCOUNT;
}

long i1;
hr = ((::ISettings*) this)->get_volume(&i1);
if (pVarResult != 0) {
V_VT(pVarResult) = VT_I4;
V_I4(pVarResult) = i1;
}
break;
}
else
if (wFlags & 4) {


if (pDispParams->cArgs != 1) {
return DISP_E_BADPARAMCOUNT;
}
v = rgpVars[0];

if (v->vt != VT_I4 && FAILED(__VariantChangeType(v, &v0,
VT_I4))) {


if (puArgErr != 0) {
*puArgErr = 0;
}
return DISP_E_TYPEMISMATCH;
}

long i1 = V_I4(v);
hr = ((::ISettings*) this)->put_volume(i1);


break;
}
}
default:
return DISP_E_MEMBERNOTFOUND;
}
return hr;
}

virtual HRESULT STDMETHODCALLTYPE ISettings::GetIDsOfNames(


/* [in] */ REFIID riid,

/* [size_is][in] */ LPOLESTR *rgszNames,
/* [in] */ UINT cNames,


/* [in] */ LCID lcid,

/* [size_is][out] */ DISPID *rgDispId)
{
(void) riid;
(void) rgszNames;
(void) cNames;
(void) lcid;
(void) rgDispId;
static LPOLESTR names[] = { L"mute", L"pfMute", L"get_mute",
L"put_mute", L"balance", L"plBalance", L"get_balance", L"put_balance",
L"volume", L"plVolume", L"get_volume", L"put_volume" };
static DISPID dids[] = { 104, 0, 104, 104, 102, 0, 102, 102, 107, 0,
107, 107 };
for (unsigned int i = 0; i < cNames; ++i) {
int fFoundIt = 0;
for (unsigned int j = 0; j < sizeof(names)/sizeof(LPOLESTR);
++j) {
if (lstrcmpiW(rgszNames[i], names[j]) == 0) {
fFoundIt = 1;
rgDispId[i] = dids[j];
break;
}
}
if (fFoundIt == 0) {
return DISP_E_UNKNOWNNAME;
}
}
return S_OK;
}
HRESULT TypeInfoHelper(REFIID iidDisp, LCID /*lcid*/, ITypeInfo**
ppTypeInfo)
{
if (ppTypeInfo == NULL) {
return E_POINTER;
}
*ppTypeInfo = NULL;
TCHAR szModule1[_MAX_PATH];
::GetModuleFileName(_AtlBaseModule.GetModuleInstance(), szModule1,
_MAX_PATH);
USES_CONVERSION;
CComPtr<ITypeLib> spTypeLib;
HRESULT hr = LoadTypeLib(T2OLE(szModule1), &spTypeLib);
if (SUCCEEDED(hr)) {
CComPtr<ITypeInfo> spTypeInfo;
hr = spTypeLib->GetTypeInfoOfGuid(iidDisp, &spTypeInfo);
if (SUCCEEDED(hr)) {
*ppTypeInfo = spTypeInfo.Detach();
}
}
return hr;
}
virtual HRESULT STDMETHODCALLTYPE ISettings::GetTypeInfoCount(unsigned
int* pctinfo)
{
if (pctinfo == NULL) {
return E_POINTER;
}
CComPtr<ITypeInfo> spTypeInfo;
*pctinfo =
(SUCCEEDED(TypeInfoHelper(__uuidof(ISettings), 0,
&spTypeInfo))) ? 1 : 0;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE ISettings::GetTypeInfo(unsigned int
iTInfo, LCID lcid, ITypeInfo** ppTInfo)
{
if (iTInfo != 0) {
return DISP_E_BADINDEX;
}
return TypeInfoHelper(__uuidof(ISettings), lcid, ppTInfo);
}
#injected_line 65 "l:\\projects\\skinengine\\src\\mediaplayer\\settings.h"

//--- End Injected Code For Attribute 'event'

//+++ Start Injected Code For Attribute 'event'
#injected_line 65 "l:\\projects\\skinengine\\src\\mediaplayer\\settings.h"
BEGIN_CONNECTION_POINT_MAP(CSettings)
CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink)
#injected_line 65
"l:\\projects\\skinengine\\src\\mediaplayer\\settings.h"
CONNECTION_POINT_ENTRY(__uuidof(::_ISettingsEvents))
#injected_line 65
"l:\\projects\\skinengine\\src\\mediaplayer\\settings.h"
END_CONNECTION_POINT_MAP()
#injected_line 65 "l:\\projects\\skinengine\\src\\mediaplayer\\settings.h"
static DWORD* GetOpCodes()
{
static DWORD rgOps[] =
{
0x70000000,
0x30004000,
0x80000002,
0x50000000,
0x3000c000,
0x80000004,
0x60000000,
0x30014000,
0x80000002,
0x50000000,
0x3000c000,
0x80000004,
0x30018000,
0x80000001,
0x60000000,
0x1000c000,
0x3000c000,
0x50000000,
0x20010000,
0x30010000,
0x80000002,
0x50000000,
0x3001c000,
0x80000001,
0x30020000,
0x80000005,
0x20024000,
0x30024000,
0x30028000,
0x8000000b,
0x50000000,
0x8003000d,
0x60000000,
0x8003800f,
0x30040000,
0x80000011,
0x60000000,
0x60000000,
0x60000000,
0
};
return rgOps;
}
#injected_line 65 "l:\\projects\\skinengine\\src\\mediaplayer\\settings.h"
static RGSDWORD* GetOpcodeDWORDVals()
{
static RGSDWORD rgDWORDS[] =
{
{0, 0}
};
return rgDWORDS;
}
#injected_line 65 "l:\\projects\\skinengine\\src\\mediaplayer\\settings.h"
static RGSBinary* GetOpcodeBinaryVals()
{

static RGSBinary rgBinary[] =
{
{0, 0}
};
return rgBinary;
}
#injected_line 65 "l:\\projects\\skinengine\\src\\mediaplayer\\settings.h"
static RGSStrings* GetOpcodeStringVals()
{
static RGSStrings rgStrings[] =
{
{_T(""),0 },
{_T("MediaPlayer.Settings.1"),0 },
{_T("%FriendlyName%"),1 },
{_T("CLSID"),0 },
{_T("{7132AEC7-D527-4A5E-ADBF-6DBCB4724075}"),0 },
{_T("MediaPlayer.Settings"),0 },
{_T("CurVer"),0 },
{_T("ProgID"),0 },
{_T("VersionIndependentProgID"),0 },
{_T("Programmable"),0 },
{_T("%MODULETYPE%"),1 },
{_T("%MODULE%"),1 },
{_T("ThreadingModel"),0 },
{_T("apartment"),0 },
{_T("AppID"),0 },
{_T("%APPID%"),1 },
{_T("TypeLib"),0 },
{_T("%MODULEGUID%"),1 },
{NULL, 0}
};
return rgStrings;
}
#injected_line 65 "l:\\projects\\skinengine\\src\\mediaplayer\\settings.h"
static HRESULT WINAPI UpdateRegistry(BOOL bRegister)
{
CRegistryVirtualMachine rvm;
HRESULT hr;
if (FAILED(hr = rvm.AddStandardReplacements()))
return hr;
rvm.AddReplacement(_T("FriendlyName"), GetObjectFriendlyName());
return rvm.VMUpdateRegistry(GetOpCodes(), GetOpcodeStringVals(),
GetOpcodeDWORDVals(), GetOpcodeBinaryVals(), bRegister);
}
#injected_line 65 "l:\\projects\\skinengine\\src\\mediaplayer\\settings.h"
static const TCHAR* GetObjectFriendlyName()
{
return _T("CSettings Object");
}
#injected_line 65 "l:\\projects\\skinengine\\src\\mediaplayer\\settings.h"
static const TCHAR* GetProgID()
{
return _T("MediaPlayer.Settings.1");
}
#injected_line 65 "l:\\projects\\skinengine\\src\\mediaplayer\\settings.h"
static const TCHAR* GetVersionIndependentProgID()
{
return _T("MediaPlayer.Settings");
}
#injected_line 65 "l:\\projects\\skinengine\\src\\mediaplayer\\settings.h"
BEGIN_COM_MAP(CSettings)
COM_INTERFACE_ENTRY(IProvideClassInfo2)
COM_INTERFACE_ENTRY(IProvideClassInfo)
COM_INTERFACE_ENTRY(ISettings)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
END_COM_MAP()

//--- End Injected Code For Attribute 'event'
};

//+++ Start Injected Code For Attribute 'event'
#injected_line 65 "l:\\projects\\skinengine\\src\\mediaplayer\\settings.h"

OBJECT_ENTRY_AUTO(__uuidof(CSettings), CSettings)

//--- End Injected Code For Attribute 'event'
// CSettings

////////////////////////////////////////////////////////////////////////////
////

[...]
>

Edwin Schild

unread,
Jan 28, 2002, 3:02:37 AM1/28/02
to
Hi Liu,

I know that a dual interface is a dispatch interface. I have been using them
for several years now but always in IDL files. In the IDL files I didn't
have the problem that I had to forward declare them as dual. It's just that
ypu have to know how to do a forward declaration in the ATL attributed code.
I just couldn't find anything in the documentation.
I also noticed that when my interface gets a lot of methods and properties
the compiler switches from generated Invoke to IDispatchImpl. I must say
that I like it because I was afraid that my code would get very big if I had
too much methods and properties. Well done.

Edwin
"Liu [MSFT]" <lxi...@microsoft.com> wrote in message

news:eoc8BkcpBHA.1968@tkmsftngp07...

Liu [MSFT]

unread,
Jan 28, 2002, 3:15:10 PM1/28/02
to
Edwin,

I am sorry. I misunderstood your point. I'll report your question to our
document team.

Thanks

//Liu

"Edwin Schild" <edwin....@nicolet.shhhh.nl> wrote in message

news:uI5fnI9pBHA.2328@tkmsftngp04...

Liu [MSFT]

unread,
Jan 28, 2002, 7:36:03 PM1/28/02
to
Paolo,

This a correct injected code. You can easily verify this by calling the
function through vbscript. You would see the behavior is correct.
Since it is machine generated code, it is not very readable.

Thanks

//Liu

"Paolo Severini" <paolos...@ares.omninet.it> wrote in message
news:#xPQDf0pBHA.1600@tkmsftngp07...

Paolo

unread,
Jan 29, 2002, 3:03:11 AM1/29/02
to
Liu,

Thank you very much for your answer, but I can't agree with you.
I do believe that the lines (for esample, in case 107:)


>> v = rgpVars[0];
>> if (v->vt != VT_I4 && FAILED(__VariantChangeType(v, &v0,
VT_I4)))

can't be right.
It should be:
v0 = rgpVars[0];
because it is v0 that has to be converted into a long in v, which is then
passed to
my function:


> > long i1 = V_I4(v);
> > hr = ((::ISettings*) this)->put_volume(i1);

As it is, when the parameter passed to Invoke contains a double, it doesn't
get converted into an int, and the function is called passing a long
obtained with:
V_I4(v)
that is, taking the first 4 bytes from the 8-bytes binary representation of
a double.
If you want, I can send you a whole project that reproduces this behaviour.
In fact my class, which worked with VS6, didn't work with the injected code
but works perfectly after deriving it from IDispatchImpl to disable the code
injection.

Best wishes,
-- paolo


"Liu [MSFT]" <lxi...@microsoft.com> wrote in message

news:OatOxzFqBHA.2172@tkmsftngp03...

Liu [MSFT]

unread,
Jan 29, 2002, 11:59:47 PM1/29/02
to
Thanks for your reply.
Can you please send me your project?

//Liu

"Paolo" <paolos...@nospam.net> wrote in message
news:#SFV3tJqBHA.2128@tkmsftngp07...

Liu [MSFT]

unread,
Jan 30, 2002, 7:40:52 PM1/30/02
to
Paolo,

Thank you very much for your project. I built with and without using
injected code. It just works fine for me in both ways. Could you please tell
me more details about the problem you found with the injected code?

//Liu

"Paolo Severini" <paolos...@ares.omninet.it> wrote in message

news:unQduQXqBHA.2180@tkmsftngp07...
> Liu,
>
> attached is my complete project with the generated mgr files.
> In the file settings.mgr.h, lines 245-253 you can see that the case 107
> in the Invoke method is incorrect. But other cases are incorrect, too:
> there is always v = rgpVars[0];
> instead of v0 = rgpVars[0];
>
> btw, of course I'm using the final release of VS.NET.
>
> Glad to have been useful :)
> Ciao,


> -- paolo
>
>
> "Liu [MSFT]" <lxi...@microsoft.com> wrote in message

> news:uubs0rUqBHA.1208@tkmsftngp07...

Paolo Severini

unread,
Jan 31, 2002, 3:32:15 AM1/31/02
to
Liu,

The problem arises when you call an object method through
IDispatch::Invoke()
passing as argument a variant with a type different from the type the method
expects.
In this case the injected implementation of Invoke contains code to convert
the
variant type (calling VariantChangeType).
For example, in my sample code, the object CSettings implements the
IDispatch-interface ISettings.
One of the mehods of ISettings is


HRESULT volume([in] long plVolume);

thath expects a long.

The injected code for this method (file settings.mgr.h) is this:

virtual HRESULT STDMETHODCALLTYPE ISettings::Invoke(
/* [in] */ DISPID dispIdMember,
/* [in] */ REFIID riid,
/* [in] */ LCID lcid,
/* [in] */ WORD wFlags,
/* [out][in] */ DISPPARAMS *pDispParams,
/* [out] */ VARIANT *pVarResult,
/* [out] */ EXCEPINFO *pExcepInfo,
/* [out] */ UINT *puArgErr)
{

[...]


VARIANT v0;
VARIANT* v;
switch (dispIdMember) {

[...]


case 107:
{
if (wFlags & 2) {
if (pDispParams->cArgs != 0) {
return DISP_E_BADPARAMCOUNT;
}
long i1;
hr = ((::ISettings*) this)->get_volume(&i1);
if (pVarResult != 0) {
V_VT(pVarResult) = VT_I4;
V_I4(pVarResult) = i1;
}
break;
}
else
if (wFlags & 4) {
if (pDispParams->cArgs != 1) {
return DISP_E_BADPARAMCOUNT;
}
v = rgpVars[0];
if (v->vt != VT_I4 && FAILED(

==> __VariantChangeType(v, &v0, VT_I4))) {


if (puArgErr != 0) {
*puArgErr = 0;
}
return DISP_E_TYPEMISMATCH;
}
long i1 = V_I4(v);
hr = ((::ISettings*) this)->put_volume(i1);
break;
}
}
default:
return DISP_E_MEMBERNOTFOUND;
}
return hr;
}

the problem is in the line with the call to VariantChangeType.
If, for example, rgpVars[0] is a variant that contains a double
(vt == VT_R8), then its value should be converted into an integer
(VT_I4). But that doesn't happen because the code

v = rgpVars[0];
if (v->vt != VT_I4 && FAILED(

__VariantChangeType(v, &v0, VT_I4))) {

works on v0, not on v (and, btw, v0 is never initialized,
so the code must be wrong anyway).
As result, the function
put_volume()
is called passing the binary representation of a float treated as if it was
an int. In this particular case the program doesn't crash, but the parameter
value is incorrect.
To reproduce the problem, set a breakpoint in the file TesterDlg.cpp
line 117 and follow the call to:

hr = CComDispatchDriver::PutProperty(pSettings,
dwDispId, &dblVolVar);

You'll see that the function CSettings::put_volume() receives a "wrong"
argument. That won't happen disabling the code injection.

Ciao,
-- paolo


"Liu [MSFT]" <lxi...@microsoft.com> wrote in message

news:uYj9x$eqBHA.1036@tkmsftngp03...

Liu [MSFT]

unread,
Jan 31, 2002, 2:22:17 PM1/31/02
to
Paolo,

Thank you very much for your time.

The __VariantChangeType is not VariantChangeType. They behaviors are
different. The problem is not in the way to call this function. The problem
is in the implementation of __VariantChageType function. It seems we didn't
handle converting variant between floating type and integral type properly.

I'll report this issue and it will be fixed in the future.

Thanks again for reporting this problem.

//Liu

"Paolo Severini" <paolos...@ares.omninet.it> wrote in message

news:unCISHjqBHA.2344@tkmsftngp07...

0 new messages