Discussion:
Loading a bitmap resource into an IPicture.
(too old to reply)
Alun Jones
2007-07-27 18:06:40 UTC
Permalink
As part of an Outlook add-in, I'm trying to put my own image into a
CommandBarButton.

The usual technique I've seen listed is to open the clipboard, empty it,
fill it with the bitmap, then call PasteFace on the button.

Obviously, this is less than desirable, because it wipes out the content of
the clipboard.

I'm trying to use put_Picture, but can't get it to work. If you've had
success with this, please let me know, otherwise perhaps you could look at
the code below and tell me if I'm doing anything obviously wrong:

HBITMAP hBmp = LoadBitmap((HINSTANCE)gInstance,
MAKEINTRESOURCE(IDB_BITMAP1));
HRESULT hr;
CComPtr<IPicture> pPicture;
PICTDESC pd;
ZeroMemory(&pd,sizeof pd);
pd.cbSizeofstruct = sizeof pd;
pd.picType = PICTYPE_BITMAP;
pd.bmp.hbitmap = hBmp;
pd.bmp.hpal = 0;
hr = OleCreatePictureIndirect( &pd,
__uuidof(pPicture),
FALSE,
(LPVOID *)&pPicture );
if (FAILED(hr))
return hr;
OLE_XSIZE_HIMETRIC nWidth = 0;
OLE_YSIZE_HIMETRIC nHeight = 0;
hr = pPicture->get_Width(&nWidth);
hr = pPicture->get_Height(&nHeight);

At this point, hr is S_OK, and nWidth and nHeight are each 0x1a7 or 423.

Since my original bitmap is 16x16, it seems like I've probably hit a snag
already.

But I go on to do:
CComPtr<IPictureDisp> pPictureDisp;
hr = pPicture->QueryInterface(&pPictureDisp);
if (FAILED(hr))
return hr;
hr = spCmdButton->put_Picture(pPictureDisp);
if (FAILED(hr))
return hr;

put_Picture is returning E_FAIL.

Any ideas why?

Thanks in advance,

Alun.
~~~~
Sheng Jiang[MVP]
2007-07-27 22:03:45 UTC
Permalink
see HOWTO: Creating custom pictures for Visual Studio .NET add-ins commands,
buttons and toolwindows(http://support.microsoft.com/kb/555417)
--
Sheng Jiang
Microsoft MVP in VC++
Post by Alun Jones
As part of an Outlook add-in, I'm trying to put my own image into a
CommandBarButton.
The usual technique I've seen listed is to open the clipboard, empty it,
fill it with the bitmap, then call PasteFace on the button.
Obviously, this is less than desirable, because it wipes out the content of
the clipboard.
I'm trying to use put_Picture, but can't get it to work. If you've had
success with this, please let me know, otherwise perhaps you could look at
HBITMAP hBmp = LoadBitmap((HINSTANCE)gInstance,
MAKEINTRESOURCE(IDB_BITMAP1));
HRESULT hr;
CComPtr<IPicture> pPicture;
PICTDESC pd;
ZeroMemory(&pd,sizeof pd);
pd.cbSizeofstruct = sizeof pd;
pd.picType = PICTYPE_BITMAP;
pd.bmp.hbitmap = hBmp;
pd.bmp.hpal = 0;
hr = OleCreatePictureIndirect( &pd,
__uuidof(pPicture),
FALSE,
(LPVOID *)&pPicture );
if (FAILED(hr))
return hr;
OLE_XSIZE_HIMETRIC nWidth = 0;
OLE_YSIZE_HIMETRIC nHeight = 0;
hr = pPicture->get_Width(&nWidth);
hr = pPicture->get_Height(&nHeight);
At this point, hr is S_OK, and nWidth and nHeight are each 0x1a7 or 423.
Since my original bitmap is 16x16, it seems like I've probably hit a snag
already.
CComPtr<IPictureDisp> pPictureDisp;
hr = pPicture->QueryInterface(&pPictureDisp);
if (FAILED(hr))
return hr;
hr = spCmdButton->put_Picture(pPictureDisp);
if (FAILED(hr))
return hr;
put_Picture is returning E_FAIL.
Any ideas why?
Thanks in advance,
Alun.
~~~~
Alun Jones
2007-07-27 22:53:17 UTC
Permalink
That might be helpful _if_ I am working in .NET, but here I am working in
C++. I have ATL, if that helps a little.

I believe my code is consistent with the article that you pointed me to.

Please let me know if you can see otherwise.

Alun.
~~~~
Post by Sheng Jiang[MVP]
see HOWTO: Creating custom pictures for Visual Studio .NET add-ins commands,
buttons and toolwindows(http://support.microsoft.com/kb/555417)
--
Sheng Jiang
Microsoft MVP in VC++
Post by Alun Jones
As part of an Outlook add-in, I'm trying to put my own image into a
CommandBarButton.
The usual technique I've seen listed is to open the clipboard, empty it,
fill it with the bitmap, then call PasteFace on the button.
Obviously, this is less than desirable, because it wipes out the content
of
Post by Alun Jones
the clipboard.
I'm trying to use put_Picture, but can't get it to work. If you've had
success with this, please let me know, otherwise perhaps you could look at
HBITMAP hBmp = LoadBitmap((HINSTANCE)gInstance,
MAKEINTRESOURCE(IDB_BITMAP1));
HRESULT hr;
CComPtr<IPicture> pPicture;
PICTDESC pd;
ZeroMemory(&pd,sizeof pd);
pd.cbSizeofstruct = sizeof pd;
pd.picType = PICTYPE_BITMAP;
pd.bmp.hbitmap = hBmp;
pd.bmp.hpal = 0;
hr = OleCreatePictureIndirect( &pd,
__uuidof(pPicture),
FALSE,
(LPVOID *)&pPicture );
if (FAILED(hr))
return hr;
OLE_XSIZE_HIMETRIC nWidth = 0;
OLE_YSIZE_HIMETRIC nHeight = 0;
hr = pPicture->get_Width(&nWidth);
hr = pPicture->get_Height(&nHeight);
At this point, hr is S_OK, and nWidth and nHeight are each 0x1a7 or 423.
Since my original bitmap is 16x16, it seems like I've probably hit a snag
already.
CComPtr<IPictureDisp> pPictureDisp;
hr = pPicture->QueryInterface(&pPictureDisp);
if (FAILED(hr))
return hr;
hr = spCmdButton->put_Picture(pPictureDisp);
if (FAILED(hr))
return hr;
put_Picture is returning E_FAIL.
Any ideas why?
Thanks in advance,
Alun.
~~~~
Michael Phillips, Jr.
2007-07-28 14:57:37 UTC
Permalink
Post by Alun Jones
put_Picture is returning E_FAIL.
It is returning E_FAIL because it is a read-only property. See MSDN, only
the hpal is a read/write property.

You need to use IPicture's Render method to draw you image on to your
spCmdButton's face.
Post by Alun Jones
As part of an Outlook add-in, I'm trying to put my own image into a
CommandBarButton.
The usual technique I've seen listed is to open the clipboard, empty it,
fill it with the bitmap, then call PasteFace on the button.
Obviously, this is less than desirable, because it wipes out the content
of the clipboard.
I'm trying to use put_Picture, but can't get it to work. If you've had
success with this, please let me know, otherwise perhaps you could look at
HBITMAP hBmp = LoadBitmap((HINSTANCE)gInstance,
MAKEINTRESOURCE(IDB_BITMAP1));
HRESULT hr;
CComPtr<IPicture> pPicture;
PICTDESC pd;
ZeroMemory(&pd,sizeof pd);
pd.cbSizeofstruct = sizeof pd;
pd.picType = PICTYPE_BITMAP;
pd.bmp.hbitmap = hBmp;
pd.bmp.hpal = 0;
hr = OleCreatePictureIndirect( &pd,
__uuidof(pPicture),
FALSE,
(LPVOID *)&pPicture );
if (FAILED(hr))
return hr;
OLE_XSIZE_HIMETRIC nWidth = 0;
OLE_YSIZE_HIMETRIC nHeight = 0;
hr = pPicture->get_Width(&nWidth);
hr = pPicture->get_Height(&nHeight);
At this point, hr is S_OK, and nWidth and nHeight are each 0x1a7 or 423.
Since my original bitmap is 16x16, it seems like I've probably hit a snag
already.
CComPtr<IPictureDisp> pPictureDisp;
hr = pPicture->QueryInterface(&pPictureDisp);
if (FAILED(hr))
return hr;
hr = spCmdButton->put_Picture(pPictureDisp);
if (FAILED(hr))
return hr;
put_Picture is returning E_FAIL.
Any ideas why?
Thanks in advance,
Alun.
~~~~
a***@texis.invalid
2007-07-28 19:13:07 UTC
Permalink
Post by Michael Phillips, Jr.
Post by Alun Jones
put_Picture is returning E_FAIL.
It is returning E_FAIL because it is a read-only property. See MSDN, only
the hpal is a read/write property.
MSDN says: http://msdn2.microsoft.com/en-us/library/aa210853(office.11).aspx
and provides a sample in VB.NET of how you set the object.

I'm willing to believe that the underlying COM implementation acts as if
it's read-only (but then why would there be a "put_Picture" function?), but
the samples, documentation and headers all suggest otherwise.

Please don't think I haven't been reading up as much documentation as I can
find before posting here - but do feel free to point me to any you think
I've missed.
Post by Michael Phillips, Jr.
You need to use IPicture's Render method to draw you image on to your
spCmdButton's face.
That's good news - another avenue to try.

Do you have any example code?

Alun.
~~~~
--
Texas Imperial Software | Web: http://www.wftpd.com/
23921 57th Ave SE | Blog: http://msmvps.com/alunj/
Woodinville WA 98072-8661 | WFTPD, WFTPD Pro are Windows FTP servers.
Fax/Voice +1(425)807-1787 | Try our client software, WFTPD Explorer.
Michael Phillips, Jr.
2007-07-28 23:51:17 UTC
Permalink
http://msdn2.microsoft.com/en-us/library/aa210853(office.11).aspx and
provides a sample in VB.NET of how you set the object.
The above example and other similar Microsoft MSDN samples all create and
pass the IDispatch interface in process.

By any chance are you attempting to marshal your IDispatch pointer across
process boundaries?

If so, then put_Picture will return E_FAIL.

See the following Microsoft Knowledge Base articles:
1) http://support.microsoft.com/kb/286460
2) http://support.microsoft.com/kb/150034/
a***@texis.invalid
2007-07-29 02:03:53 UTC
Permalink
Post by Michael Phillips, Jr.
http://msdn2.microsoft.com/en-us/library/aa210853(office.11).aspx and
provides a sample in VB.NET of how you set the object.
The above example and other similar Microsoft MSDN samples all create and
pass the IDispatch interface in process.
By any chance are you attempting to marshal your IDispatch pointer across
process boundaries?
If so, then put_Picture will return E_FAIL.
1) http://support.microsoft.com/kb/286460
2) http://support.microsoft.com/kb/150034/
I read those, and as far as I can tell, that should apply to my add-in when
I'm debugging (perhaps?), but not when I register the release version of the
DLL as an add-in for Outlook.

What's a good way to check if that is the cause of the problem?

Alun.
~~~~
--
Texas Imperial Software | Web: http://www.wftpd.com/
23921 57th Ave SE | Blog: http://msmvps.com/alunj/
Woodinville WA 98072-8661 | WFTPD, WFTPD Pro are Windows FTP servers.
Fax/Voice +1(425)807-1787 | Try our client software, WFTPD Explorer.
Michael Phillips, Jr.
2007-07-29 14:28:08 UTC
Permalink
Post by a***@texis.invalid
What's a good way to check if that is the cause of the problem?
The best way is to check your code for compliance against the OLE2
specification.
MSDN publishes documentation pertaining to the COM rules that developers
should follow.

If your DLL code creates threads and attempts to pass COM interface pointers
between threads without marshaling, then your code will fail.

Since your add in will be loaded "in process" with Outlook, this should not
be an issue.

I have used the approach listed in these KB articles and have had no issues
with Office 2003 and Office 2007.

Of course the dot net interop assemblies make it easy to use C# and VB.Net
with this approach.

I haven't tried to use the aforementioned method with c++ using ATL.
Post by a***@texis.invalid
Post by Michael Phillips, Jr.
http://msdn2.microsoft.com/en-us/library/aa210853(office.11).aspx and
provides a sample in VB.NET of how you set the object.
The above example and other similar Microsoft MSDN samples all create and
pass the IDispatch interface in process.
By any chance are you attempting to marshal your IDispatch pointer across
process boundaries?
If so, then put_Picture will return E_FAIL.
1) http://support.microsoft.com/kb/286460
2) http://support.microsoft.com/kb/150034/
I read those, and as far as I can tell, that should apply to my add-in
when I'm debugging (perhaps?), but not when I register the release version
of the DLL as an add-in for Outlook.
What's a good way to check if that is the cause of the problem?
Alun.
~~~~
--
Texas Imperial Software | Web: http://www.wftpd.com/
23921 57th Ave SE | Blog: http://msmvps.com/alunj/
Woodinville WA 98072-8661 | WFTPD, WFTPD Pro are Windows FTP servers.
Fax/Voice +1(425)807-1787 | Try our client software, WFTPD Explorer.
Michael Phillips, Jr.
2007-07-29 19:24:22 UTC
Permalink
You may want to check the image that you are trying to use.

I coded up a test case using c++.

I used the the comaddin code found here:
http://support.microsoft.com/kb/230689/

I used the images found here:
http://support.microsoft.com:80/kb/286460

I was able to pass the IPictureDisp interface pointers with no problems.

My button displayed without error.
Post by Michael Phillips, Jr.
Post by a***@texis.invalid
What's a good way to check if that is the cause of the problem?
The best way is to check your code for compliance against the OLE2
specification.
MSDN publishes documentation pertaining to the COM rules that developers
should follow.
If your DLL code creates threads and attempts to pass COM interface
pointers between threads without marshaling, then your code will fail.
Since your add in will be loaded "in process" with Outlook, this should
not be an issue.
I have used the approach listed in these KB articles and have had no
issues with Office 2003 and Office 2007.
Of course the dot net interop assemblies make it easy to use C# and VB.Net
with this approach.
I haven't tried to use the aforementioned method with c++ using ATL.
Post by a***@texis.invalid
Post by Michael Phillips, Jr.
http://msdn2.microsoft.com/en-us/library/aa210853(office.11).aspx and
provides a sample in VB.NET of how you set the object.
The above example and other similar Microsoft MSDN samples all create
and pass the IDispatch interface in process.
By any chance are you attempting to marshal your IDispatch pointer
across process boundaries?
If so, then put_Picture will return E_FAIL.
1) http://support.microsoft.com/kb/286460
2) http://support.microsoft.com/kb/150034/
I read those, and as far as I can tell, that should apply to my add-in
when I'm debugging (perhaps?), but not when I register the release
version of the DLL as an add-in for Outlook.
What's a good way to check if that is the cause of the problem?
Alun.
~~~~
--
Texas Imperial Software | Web: http://www.wftpd.com/
23921 57th Ave SE | Blog: http://msmvps.com/alunj/
Woodinville WA 98072-8661 | WFTPD, WFTPD Pro are Windows FTP servers.
Fax/Voice +1(425)807-1787 | Try our client software, WFTPD Explorer.
a***@texis.invalid
2007-07-29 21:19:48 UTC
Permalink
Post by Michael Phillips, Jr.
You may want to check the image that you are trying to use.
I coded up a test case using c++.
http://support.microsoft.com/kb/230689/
http://support.microsoft.com:80/kb/286460
I was able to pass the IPictureDisp interface pointers with no problems.
My button displayed without error.
I finally found the problem.

I needed to call LoadImage and pass the LR_CREATEDIBSECTION flag to bring my
bitmap in from the resource properly.

Thank you, everyone, for your kind and considerate help - even if it looks
like all you did was point me to things I was already doing, of course that
allowed me to concentrate on other areas of my code, and to stop messing
with those portions that actually were working properly.

Alun.
~~~~
--
Texas Imperial Software | Web: http://www.wftpd.com/
23921 57th Ave SE | Blog: http://msmvps.com/alunj/
Woodinville WA 98072-8661 | WFTPD, WFTPD Pro are Windows FTP servers.
Fax/Voice +1(425)807-1787 | Try our client software, WFTPD Explorer.
a***@texis.invalid
2007-07-28 22:24:50 UTC
Permalink
Post by Michael Phillips, Jr.
Post by Alun Jones
put_Picture is returning E_FAIL.
It is returning E_FAIL because it is a read-only property. See MSDN, only
the hpal is a read/write property.
I think I see where I confused you.

hpal is a read/write property of iPicture, put_Picture is a method of
commandBarButton, that sets its read/write property called "Picture".

Setting the commandBarButton.Picture property is supposed to be the way to
put a custom graphic on a button in an Outlook add-in. It would certainly
beat the PasteFace method, the only other documented means of attaching
custom graphics to buttons.
Post by Michael Phillips, Jr.
You need to use IPicture's Render method to draw you image on to your
spCmdButton's face.
I think you might be barking up the wrong tree here, but if you have done
this, I'd love to see a sample.

Alun.
~~~~
--
Texas Imperial Software | Web: http://www.wftpd.com/
23921 57th Ave SE | Blog: http://msmvps.com/alunj/
Woodinville WA 98072-8661 | WFTPD, WFTPD Pro are Windows FTP servers.
Fax/Voice +1(425)807-1787 | Try our client software, WFTPD Explorer.
Loading...