IRibbonExtensibility and custom ribbon image

N

NickP

Hi there,

I've just seen a video, and read quite allot of articles saying how to
use a custom image for Ribbon button in .NET. Unfortunately I am using
VC2005, so cannot do this, how would I specify a custom bitmap?

STDMETHODIMP CConnect::raw_GetCustomUI(BSTR RibbonID, BSTR * RibbonXml)
{
if (!RibbonXml) return E_POINTER;
*RibbonXml = SysAllocString(L"<customUI
xmlns=\"http://schemas.microsoft.com/office/2006/01/customui\">"
L" <ribbon>"
L" <tabs>"
L" <tab id=\"my tab\""
L" label=\"my tab\">"
L" <group id=\"my ribbon\""
L" label=\"my ribbon\">"
L" <button id=\"foobar\""
L" image=\"<what do I enter here?>\""
L" size=\"large\""
L" label=\"foobar...\""
L" onAction=\"ButtonClicked\"/>"
L" </group>"
L" </tab>"
L" </tabs>"
L" </ribbon>"
L"</customUI>"
);
return (*RibbonXml ? S_OK : E_OUTOFMEMORY);
}

I'm thinking that I might have to use a callback, but again, I cannot
find any C++ examples of doing this. Many thanks in advance for your time
and help.

Nick.
 
N

NickP

Just to add to this, I've been trying to implement the onAction event of the
button via implementing the ICommandBarButtonEvents interface via the ATL
wizard. I thought if i could get this working then I would be half way to
getting the getImage callback working. Unfortunately even though I have
defined the function Click, I am being told that it is an abstract class, if
I remove the interface for ICommandBarButtonEvents the error disappears.

I don't see the problem as the interface is clearly defined,

...

struct __declspec(uuid("55f88890-7708-11d1-aceb-006008961da5"))
ICommandBarButtonEvents : IDispatch
{
//
// Raw methods provided by interface
//
virtual void __stdcall Click (
/*[in]*/ struct _CommandBarButton * Ctrl,
/*[in,out]*/ VARIANT_BOOL * CancelDefault ) = 0;
};

....

// ICommandBarButtonEvents Methods
public:
STDMETHOD_(void, Click)(CommandBarButton * Ctrl, BOOL * CancelDefault)
{

};
....


o_O, it's got me stumped that's for sure, I thought I understood this
interface implementation, especially as it has only 1 method!

Nick.
 
N

NickP

Aaah seemed I was declaring as BOOL, rather than VARIANT_BOOL.

So the interface compiles fine now, but when I enter "Click" as the onAction
event, nothing happens :-(

Nick.

NickP said:
Just to add to this, I've been trying to implement the onAction event of
the button via implementing the ICommandBarButtonEvents interface via the
ATL wizard. I thought if i could get this working then I would be half
way to getting the getImage callback working. Unfortunately even though I
have defined the function Click, I am being told that it is an abstract
class, if I remove the interface for ICommandBarButtonEvents the error
disappears.

I don't see the problem as the interface is clearly defined,

..

struct __declspec(uuid("55f88890-7708-11d1-aceb-006008961da5"))
ICommandBarButtonEvents : IDispatch
{
//
// Raw methods provided by interface
//
virtual void __stdcall Click (
/*[in]*/ struct _CommandBarButton * Ctrl,
/*[in,out]*/ VARIANT_BOOL * CancelDefault ) = 0;
};

...

// ICommandBarButtonEvents Methods
public:
STDMETHOD_(void, Click)(CommandBarButton * Ctrl, BOOL * CancelDefault)
{

};
...


o_O, it's got me stumped that's for sure, I thought I understood this
interface implementation, especially as it has only 1 method!

Nick.

NickP said:
Hi there,

I've just seen a video, and read quite allot of articles saying how to
use a custom image for Ribbon button in .NET. Unfortunately I am using
VC2005, so cannot do this, how would I specify a custom bitmap?

STDMETHODIMP CConnect::raw_GetCustomUI(BSTR RibbonID, BSTR * RibbonXml)
{
if (!RibbonXml) return E_POINTER;
*RibbonXml = SysAllocString(L"<customUI
xmlns=\"http://schemas.microsoft.com/office/2006/01/customui\">"
L" <ribbon>"
L" <tabs>"
L" <tab id=\"my tab\""
L" label=\"my tab\">"
L" <group id=\"my ribbon\""
L" label=\"my ribbon\">"
L" <button id=\"foobar\""
L" image=\"<what do I enter here?>\""
L" size=\"large\""
L" label=\"foobar...\""
L" onAction=\"ButtonClicked\"/>"
L" </group>"
L" </tab>"
L" </tabs>"
L" </ribbon>"
L"</customUI>"
);
return (*RibbonXml ? S_OK : E_OUTOFMEMORY);
}

I'm thinking that I might have to use a callback, but again, I cannot
find any C++ examples of doing this. Many thanks in advance for your
time and help.

Nick.
 
J

Jialiang Ge [MSFT]

Hello Nick,

From your post, my understanding on this issue is: you wonder why your
callback function is not fired and how to set a custom image for ribbon
button. If I'm off base, please feel free to let me know.

For the first question, I wonder whether you have switched on the display
of the add-in UI error? Would you let me know the error message. To do so,
use Word Options->Advanced->General section->Show add-in user interface
errors. When it is switched on, you could see all errors related to the
add-in, which include "not find callbackfunction" or any runtime errors in
the callbacks. Besides, please refer to the following page which describe a
similar question to yours: (It also contains a full sample code about how
to set callbacks for your reference.)
http://www.eggheadcafe.com/software/aspnet/28728411/-iribbonextensibility.as
px
Is the callback function a member of your add-in class rather than a member
of IribbonExtensibility? (See picture:
http://www.vczx.com/article/img/20070402151438_addin_7.gif,
http://www.vczx.com/article/img/20070402151507_addin_8.gif) .

For the second question, the attribute imageMso specifies a built-in icon
to display on the button.
<button id="Button1" imageMso="HappyFace" size="large" label="MyButton" />
See the section "Ribbon XML File Reference" in MSDN
http://msdn2.microsoft.com/en-us/library/aa942866(VS.80).aspx

Please let me know if you have any other concerns, or need anything else.

Sincerely,
Jialiang Ge ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
For MSDN subscribers whose posts are left unanswered, please check this
document: http://blogs.msdn.com/msdnts/pages/postingAlias.aspx

Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications. If you are using Outlook Express/Windows Mail, please make sure
you clear the check box "Tools/Options/Read: Get 300 headers at a time" to
see your reply promptly.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
S

SvenC

Hi Nick,
Just to add to this, I've been trying to implement the onAction event of
the button via implementing the ICommandBarButtonEvents interface via
the ATL wizard. I thought if i could get this working then I would be

the Ribbon does not depend on any Office defined callback interface. It just
QueryInterfaces the IDispatch interface and will ask id a Method with the
name you specified for onAction does exist and invoke it.
Also the method name is not predefined, if you use
onAction="HaveBeenClicked"
then your IDispatch will be asked for HaveBeenFixed. Only the method
signature
is fixed, so for the click event you will always be called with an
IRibbonControl
and an in/out bool.

So just define an IDispatch derived interface of your own and make sure
that your Addin COM object returns that IDispatch implementation.

Use COM_INTERFACE_ENTRY2(IDispatch, IYourOwnCallbackInterface)
to return the correct IDispatch interface from your Addin COM object.
half way to getting the getImage callback working. Unfortunately even
though I have defined the function Click, I am being told that it is an
abstract class, if I remove the interface for ICommandBarButtonEvents
the error disappears.
I don't see the problem as the interface is clearly defined,

struct __declspec(uuid("55f88890-7708-11d1-aceb-006008961da5"))
ICommandBarButtonEvents : IDispatch
{
//
// Raw methods provided by interface
//
virtual void __stdcall Click (
/*[in]*/ struct _CommandBarButton * Ctrl,
/*[in,out]*/ VARIANT_BOOL * CancelDefault ) = 0;
};

COM methods always return HRESULTs so use virtual HRESULT Click([in]
IRibbonControl* pCtrl, [in, out] VARIANT_BOOL* CancelDefault);
 
N

NickP

Hi Sven,

I attempted to go down this same route previously and actually already
have an interface defined in AddIn.h. Using the ATL wizard I implement the
interface for CConnect, which then adds the following line to the class
declaration,

public IDispatchImpl<ICallbackInterface, &__uuidof(ICallbackInterface),
&LIBID_MyAddinLib, 1, 0>

Unfortunately this results in 2 linker errors,

Error 1 error LNK2001: unresolved external symbol _LIBID_MyAddinLib
Connect.obj
Error 2 fatal error LNK1120: 1 unresolved externals Debug/MyAddin.dll

The CConnect class can definitely see AddIn.h, but why it says it is
external is unknown to me, as it is declared internally, or am I missing
something? I have tried missing the last 3 parameters, but the callback
does not fire, as it is "not found".

BTW, in this interface my click method gets defined as follows,

STDMETHOD(ButtonClicked)( IDispatch * RibbonControl)
{
// Add your function implementation here.
MessageBox(NULL, _T("Blaaa!"), _T(""), 0);
return E_NOTIMPL;
}

Presumably this part is fine?

Many thanks for your time and help.

Nick.

SvenC said:
Hi Nick,
Just to add to this, I've been trying to implement the onAction event of
the button via implementing the ICommandBarButtonEvents interface via
the ATL wizard. I thought if i could get this working then I would be

the Ribbon does not depend on any Office defined callback interface. It
just
QueryInterfaces the IDispatch interface and will ask id a Method with the
name you specified for onAction does exist and invoke it.
Also the method name is not predefined, if you use
onAction="HaveBeenClicked"
then your IDispatch will be asked for HaveBeenFixed. Only the method
signature
is fixed, so for the click event you will always be called with an
IRibbonControl
and an in/out bool.

So just define an IDispatch derived interface of your own and make sure
that your Addin COM object returns that IDispatch implementation.

Use COM_INTERFACE_ENTRY2(IDispatch, IYourOwnCallbackInterface)
to return the correct IDispatch interface from your Addin COM object.
half way to getting the getImage callback working. Unfortunately even
though I have defined the function Click, I am being told that it is an
abstract class, if I remove the interface for ICommandBarButtonEvents
the error disappears.
I don't see the problem as the interface is clearly defined,

struct __declspec(uuid("55f88890-7708-11d1-aceb-006008961da5"))
ICommandBarButtonEvents : IDispatch
{
//
// Raw methods provided by interface
//
virtual void __stdcall Click (
/*[in]*/ struct _CommandBarButton * Ctrl,
/*[in,out]*/ VARIANT_BOOL * CancelDefault ) = 0;
};

COM methods always return HRESULTs so use virtual HRESULT Click([in]
IRibbonControl* pCtrl, [in, out] VARIANT_BOOL* CancelDefault);
 
N

NickP

Hi Jialiang,

Please refer to my reply to Sven which clarifies my question a little
more.

I have the interface created via following an article that I found,
unfortunately I have an issue trying to resolve the interface.

Thanks for your time and help.

Nick.
 
S

SvenC

Hi NickP,
I attempted to go down this same route previously and actually already
have an interface defined in AddIn.h. Using the ATL wizard I implement
the interface for CConnect, which then adds the following line to the
class declaration,

public IDispatchImpl<ICallbackInterface,
&__uuidof(ICallbackInterface), &LIBID_MyAddinLib, 1, 0>

Try __uuidof(MyAddinLib) instead of &LIBID_MyAddinLib
Unfortunately this results in 2 linker errors,

Error 1 error LNK2001: unresolved external symbol _LIBID_MyAddinLib
Connect.obj
Error 2 fatal error LNK1120: 1 unresolved externals Debug/MyAddin.dll

The CConnect class can definitely see AddIn.h, but why it says it is
external is unknown to me, as it is declared internally, or am I missing
something? I have tried missing the last 3 parameters, but the callback
does not fire, as it is "not found".

BTW, in this interface my click method gets defined as follows,

STDMETHOD(ButtonClicked)( IDispatch * RibbonControl)
{
// Add your function implementation here.
MessageBox(NULL, _T("Blaaa!"), _T(""), 0);
return E_NOTIMPL;
}

Presumably this part is fine?

Yes, looks good.

Don't forget COM_INTERFACE_ENTRY2(IDispatch, ICallbackInterface)
 
N

NickP

Hi Sven,

Great, that compiles now, but... unfortunately it says that it cannot
find the callback "ButtonClicked", after obviously renaming the callback in
the Ribbon XML, just to clarify,

...

public IDispatchImpl<ICallbackInterface, &__uuidof(ICallbackInterface),
&__uuidof(EquilibriumLib), 1, 0>

...

BEGIN_COM_MAP(CConnect)
...
COM_INTERFACE_ENTRY2(IDispatch, ICallbackInterface)
COM_INTERFACE_ENTRY(ICallbackInterface)
...
END_COM_MAP()

^I have tried with and without the 2nd
"COM_INTERFACE_ENTRY(ICallbackInterface)" part.

...

// ICallbackInterface Methods
STDMETHOD(ButtonClicked)( IDispatch * RibbonControl)
{
// Add your function implementation here.
MessageBox(NULL, _T("Blaaa!"), _T(""), 0);
return E_NOTIMPL;
}

...

My interface itself, looks like this,

MIDL_INTERFACE("ECA08819-5425-48CF-91D0-BF8D79D39B53")
ICallbackInterface : public IDispatch
{
public:
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE
ButtonClicked(
/* [in] */ IDispatch *RibbonControl) = 0;
};

...

I'm beginning to think that it just doesn't like me!

Nick.
 
S

SvenC

Great, that compiles now, but... unfortunately it says that it cannot
find the callback "ButtonClicked", after obviously renaming the callback
in the Ribbon XML, just to clarify,

...

public IDispatchImpl<ICallbackInterface, &__uuidof(ICallbackInterface),
&__uuidof(EquilibriumLib), 1, 0>

In your IDL file, did you specify 1.0 as version information of the library
block?

Like so:

[uuid(...), version(1.0)] library EquilibriumLib
{...}
BEGIN_COM_MAP(CConnect)
...
COM_INTERFACE_ENTRY2(IDispatch, ICallbackInterface)
COM_INTERFACE_ENTRY(ICallbackInterface)
...
END_COM_MAP()

Looks good.
^I have tried with and without the 2nd
"COM_INTERFACE_ENTRY(ICallbackInterface)" part.

This is unimportant as Office does not know your custom interface. It will
only QI for IDispatch.
Only if your own code QIs for ICallbackInterface you must "expose" that
interface in the map.
// ICallbackInterface Methods
STDMETHOD(ButtonClicked)( IDispatch * RibbonControl)
{
// Add your function implementation here.
MessageBox(NULL, _T("Blaaa!"), _T(""), 0);
return E_NOTIMPL;
}

Looks good, too
My interface itself, looks like this,

MIDL_INTERFACE("ECA08819-5425-48CF-91D0-BF8D79D39B53")
ICallbackInterface : public IDispatch
{
public:
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE
ButtonClicked(
/* [in] */ IDispatch *RibbonControl) = 0;
};

Can you show some idl code: how is your coclass CConnect and the interface
ICallbackInterface defined
I'm beginning to think that it just doesn't like me!

;-)
 
N

NickP

Hi Sven,
In your IDL file, did you specify 1.0 as version information of the
library block?

Like so:

[uuid(...), version(1.0)] library EquilibriumLib
{...}

Indeed (BTW, I change the name of the app for my code snips)...

....
[
uuid(C6D81C90-E082-4513-9E23-03697BE264AF),
version(1.0),
helpstring("MyAddin 1.0 Type Library")
]
....
This is unimportant as Office does not know your custom interface. It will
only QI for IDispatch.
Only if your own code QIs for ICallbackInterface you must "expose" that
interface in the map.

Aah okay, I understand now, I shall remove it permanently.
Can you show some idl code: how is your coclass CConnect and the interface
ICallbackInterface defined

Straight copy and paste from the AddIn.idl file....

// AddIn.idl : IDL source for AddIn
//
// This file will be processed by the MIDL tool to
// produce the type library (AddIn.tlb) and marshalling code.
import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(ECA08819-5425-48CF-91D0-BF8D79D39B53),
dual,
nonextensible,
helpstring("ICallbackInterface Interface"),
pointer_default(unique)
]
interface ICallbackInterface : IDispatch{
[id(1), helpstring("method ButtonClicked")] HRESULT ButtonClicked([in]
IDispatch* RibbonControl);
};
[
uuid(C6D81C90-E082-4513-9E23-03697BE264AF),
version(1.0),
helpstring("MyAddin 1.0 Type Library")
]
library MyAddinLib
{
importlib("stdole2.tlb");
[
uuid(D846B572-38F2-400D-AA02-A3A93242752F),
helpstring("Connect Class")
]
coclass Connect
{
[default] interface IUnknown;
};
[
uuid(EEDD4FA9-7A45-4892-AED6-2E01B8BD9866),
helpstring("CallbackInterface Class")
]
coclass CallbackInterface
{
[default] interface ICallbackInterface;
};
};
 
S

SvenC

A few minor IDL tweaks might help.
Can you show some idl code: how is your coclass CConnect and the
interface ICallbackInterface defined

Straight copy and paste from the AddIn.idl file....

[
uuid(C6D81C90-E082-4513-9E23-03697BE264AF),
version(1.0),
helpstring("MyAddin 1.0 Type Library")
]
library MyAddinLib
{
importlib("stdole2.tlb");
[
uuid(D846B572-38F2-400D-AA02-A3A93242752F),
helpstring("Connect Class")
]
coclass Connect
{
[default] interface IUnknown;

remove IUnknown and replace with this

[default] interface IDispatch;
interface ICallbackInterface
};
[
uuid(EEDD4FA9-7A45-4892-AED6-2E01B8BD9866),
helpstring("CallbackInterface Class")
]
coclass CallbackInterface
{
[default] interface ICallbackInterface;
};
};

I don't think that anybody would create a CallbackInterface object, so just
remove that coclass completely.
Office will only care about your Connect coclass and that has to hand out
IDispatch. I am not sure how Office calls back but it might use the type
library to see that only IUnknown and not IDispatch is available.
 
N

NickP

Hi Sven,
remove IUnknown and replace with this

[default] interface IDispatch;
interface ICallbackInterface

Unfortunately it seems to be even more than this that is the issue as it
still isn't functional, the section of the idl now looks like this,

....

library MyAddinLib
{
importlib("stdole2.tlb");
[
uuid(D846B572-38F2-400D-AA02-A3A93242752F),
helpstring("Connect Class")
]
coclass Connect
{
//[default] interface IUnknown;
[default] interface IDispatch;
interface ICallbackInterface;
};
//[
// uuid(EEDD4FA9-7A45-4892-AED6-2E01B8BD9866),
// helpstring("CallbackInterface Class")
//]
//coclass CallbackInterface
//{
// [default] interface ICallbackInterface;
//};
};

....

Which compiles perfectly, but no ButtonClicked function can be found. I
tried implementing the IDispose interface by adding the GetTypeInfo,
GetTypeInfoCount, GetIDofNames and Invoke methods manually and I managed to
get a callback from the button! But! Surely this is the wrong way for me
to be going about it? It works but, that's not to say it won't crash for
some unknown reason.
I don't think that anybody would create a CallbackInterface object, so
just remove that coclass completely.
Office will only care about your Connect coclass and that has to hand out
IDispatch. I am not sure how Office calls back but it might use the type
library to see that only IUnknown and not IDispatch is available.

Okay, I have commented out this section to exclude it from the equation.

Hmmmm, thanks a million for your help so far, I'm sure it must be some
really small detail remaining now.

Nick.
 
S

SvenC

Hi Nick,
remove IUnknown and replace with this

[default] interface IDispatch;
interface ICallbackInterface

Unfortunately it seems to be even more than this that is the issue as
it still isn't functional, the section of the idl now looks like this,

Is your typelib registered correctly? If you made changes to the IDL and
maybe its GUIDs, did you also change your rgs file?
Please post the content of your rgs file.
...
Which compiles perfectly, but no ButtonClicked function can be found.
I tried implementing the IDispose interface by adding the GetTypeInfo,
GetTypeInfoCount, GetIDofNames and Invoke methods manually and I managed
to get a callback from the button! But! Surely this is the wrong way
for me to be going about it? It works but, that's not to say it won't
crash for some unknown reason.

Ok, that shows that you are really close, as Office is already using the
IDispatch.
It just seems to be the "ATL glue" of IDispatchImpl which is not absolutely
correct.

You might want to remove your IDispatch implementation methods and instead
set breakpoints on the IDispatchImpl methods which you find in atlcom.h. I
would expect that it fails on retrieving type info - which might be due to a
mismatch of the rgs file. The Addin wizard should also create a
DllRegisterServer function, did you change anything there? It should call
_AtlModule.DllRegisterServer();

The rgs file is "hooked up" with the DECLARE_REGISTRY_RESOURCEID macro which
you should find in your CConnect class definition.

At the end of connect.h, do you have an OBJECT_ENTRY_AUTO macro?
 
N

NickP

Hi Sven!

I think you have it the nail on the head as I had to remove a check in
my dispatch methods as it was passing GUID_NULL as the type.
Is your typelib registered correctly? If you made changes to the IDL and
maybe its GUIDs, did you also change your rgs file?
Please post the content of your rgs file.

HKCR
{
MyAddin.Connect.1 = s 'Connect Class'
{
CLSID = s '{D846B572-38F2-400D-AA02-A3A93242752F}'
}
MyAddin.Connect = s 'Connect Class'
{
CLSID = s '{D846B572-38F2-400D-AA02-A3A93242752F}'
CurVer = s 'MyAddin.Connect.1'
}
NoRemove CLSID
{
ForceRemove '{D846B572-38F2-400D-AA02-A3A93242752F}' = s 'Connect
Class'
{
ProgID = s 'MyAddin.Connect.1'
VersionIndependentProgID = s 'MyAddin.Connect'
ForceRemove 'Programmable'
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Apartment'
}
'TypeLib' = s '{C6D81C90-E082-4513-9E23-03697BE264AF}'
}
}
}

I haven't actually modifed this file once since it was first created, so
it is very likely that this is incorrect now.

Although I have no point of reference for this file and have not seen it
mentioned in any articles written on implementing the Button click method
for the Ribbon in C++. But then again that's typical of the internet.

Can you suggest any URLS where I can get more of an indepth outline as
to how to customise this file?
At the end of connect.h, do you have an OBJECT_ENTRY_AUTO macro?

Yup, all of that appears to be there fine.

Many many thanks for your help! You're a star.

Nick.
 
S

SvenC

Hi Nick,
I think you have it the nail on the head as I had to remove a check in
my dispatch methods as it was passing GUID_NULL as the type.

Did you try removing your IDispatch implementation and debug into ATLs
IDispatchImpl implementation?
I guess with GUID_NULL you are talking about the refiid param of Invoke and
GetIDsOfNames? It is a reserved param which must be set to GUID_NULL, so
Office is correctly using that one. So please try to break on the ATL
methods and single step them to see where something goes wrong.
CLSID = s '{D846B572-38F2-400D-AA02-A3A93242752F}' ....
'TypeLib' = s '{C6D81C90-E082-4513-9E23-03697BE264AF}'

From your earlier posts those GUIDs seem to be identical to what is defined
in you IDL, so the rgs file looks good
I haven't actually modifed this file once since it was first created,
so it is very likely that this is incorrect now.

Although I have no point of reference for this file and have not seen
it mentioned in any articles written on implementing the Button click
method for the Ribbon in C++. But then again that's typical of the
internet.
Can you suggest any URLS where I can get more of an indepth outline as
to how to customise this file?

This is an ATL feature to declaratively specify the COM registration. Search
MSDN for RGS and ATL and you should find some information. I would say it is
just a more powerful version of regedits reg file. So there is not much
magic in there.
 
N

NickP

Hi Sven,
Did you try removing your IDispatch implementation and debug into ATLs
IDispatchImpl implementation?
I guess with GUID_NULL you are talking about the refiid param of Invoke
and GetIDsOfNames? It is a reserved param which must be set to GUID_NULL,
so Office is correctly using that one. So please try to break on the ATL
methods and single step them to see where something goes wrong.

Well I have an old class that I use as a button handler for Office prior
to the Ribbon control. At the top of the method it checks the parameters as
you would expect. The first line reads,

if (IID_NULL != riid) return DISP_E_UNKNOWNINTERFACE;

If I implement these methods manually and breakpoint the first line,
riid is allways GUID_NULL, so to get it to work, I just commented the check
out.

As for atlcom.h, I get a breakpoint hit in the function GetIDsOfNames,
riid = GUID_NULL again. So I presume this is the problem, it cannot resolve
the type correctly as you said earlier. My CConnect class is declared as
follows,

// CConnect
class ATL_NO_VTABLE CConnect :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CConnect, &CLSID_Connect>,
public IDispatchImpl<AddInDesignerObjects::_IDTExtensibility2,
&AddInDesignerObjects::IID__IDTExtensibility2,
&AddInDesignerObjects::LIBID_AddInDesignerObjects, 1, 0>,
public IDispatchImpl<IRibbonExtensibility,
&__uuidof(IRibbonExtensibility), &LIBID_Office, 2, 4>,
public IDispatchImpl<ICallbackInterface, &__uuidof(ICallbackInterface),
&__uuidof(MyAddinLib), 1, 0>
{

Could this be an issue with my declaration maybe?
This is an ATL feature to declaratively specify the COM registration.
Search MSDN for RGS and ATL and you should find some information. I would
say it is just a more powerful version of regedits reg file. So there is
not much magic in there.

Cheers I'll have a read up out of curiosity! Thanks.

Nick.
 
S

SvenC

Hi Nick,
Well I have an old class that I use as a button handler for Office
prior to the Ribbon control. At the top of the method it checks the
parameters as you would expect. The first line reads,

if (IID_NULL != riid) return DISP_E_UNKNOWNINTERFACE;

If I implement these methods manually and breakpoint the first line,
riid is allways GUID_NULL, so to get it to work, I just commented the
check out.

Hmm - I would expect that IID_NULL == GUID_NULL, so your if statement should
be false
As for atlcom.h, I get a breakpoint hit in the function GetIDsOfNames,
riid = GUID_NULL again. So I presume this is the problem, it cannot
resolve the type correctly as you said earlier. My CConnect class is
declared as follows,

I would expect GUID_NULL to be OK, so when you step on, you should see a
call to _tih.GetIDsOfNames. Can you step into that call?
If yes, check if you see any HRESULTs not equal to 0. If you cannot step in,
just execute that line of code an in the watch window check the value of
eax, that register will hold the hresult of the last method call.
Do you get a dispid from that call? According to your idl it should be 1.
// CConnect
class ATL_NO_VTABLE CConnect :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CConnect, &CLSID_Connect>,
public IDispatchImpl<AddInDesignerObjects::_IDTExtensibility2,
&AddInDesignerObjects::IID__IDTExtensibility2,
&AddInDesignerObjects::LIBID_AddInDesignerObjects, 1, 0>,
public IDispatchImpl<IRibbonExtensibility,
&__uuidof(IRibbonExtensibility), &LIBID_Office, 2, 4>,
public IDispatchImpl<ICallbackInterface,
&__uuidof(ICallbackInterface), &__uuidof(MyAddinLib), 1, 0>
{

Could this be an issue with my declaration maybe?

Looks OK to me.
 
N

NickP

Hi Sven,
Hmm - I would expect that IID_NULL == GUID_NULL, so your if statement
should be false

Oops! I read that as GUID_NULL, how stupid of me! LOL!
I would expect GUID_NULL to be OK, so when you step on, you should see a
call to _tih.GetIDsOfNames. Can you step into that call?
If yes, check if you see any HRESULTs not equal to 0. If you cannot step
in, just execute that line of code an in the watch window check the value
of eax, that register will hold the hresult of the last method call.
Do you get a dispid from that call? According to your idl it should be 1.


Okay, stepping through the names of the functions, it does not appear to
have ButtonClicked cached in m_pMap. There are 8 in total, these are,

GetCustomUI
Invoke
GetIDsOfNames
GetTypeInfo
GetTypeInfoCount
Release
AddRef
QueryInterface

But no ButtonClicked. I have just implemented the code at the following
in order to assure the RGS file is correct,

http://www.codeproject.com/atl/RegistryMap.asp

But this has had no effect either. Although I'm not 100% confident that
it has actually done anything anyway.

Nick.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top