Disabled CommandBarButton image in Office 2000 is always empty

S

SvenC

Hi,

in my COM-Addin (unmanaged shared addin) I need to support Office versions
2000-2007 and stumble upon a problem with Office 2000 and its commandbar
implementation.
I figured out that to put a masked image on a button I need to put two DIBs
with specified clibboard format names on the clipboard ("Toolbar Button
Face" and "Toolbar Button Mask" unfortunately these names are translated
according to the language of your Office version).
Doing that results in the correct button images, if the button is enabled.
But as soon as I disable such a button the image does not show up anymore.
If I use the button style to display image and text, the text is grayed out
but the image is completely gone. As soon as I enable the button the image
is visible again.
Any ideas what is going on?
 
J

Jialiang Ge [MSFT]

Hello SvenC,


From your post, my understanding on this issue is: you want to know how to
resolve the failure of 'PasteFace' when the Office is not an English
version, in addition, you wonder why the button face of the Office add-in
works abnormally when it is disabled. If I'm off base, please feel free to
let me know.

For your first question, please refer to the section '2. Transparent button
icon' of the codeproject article:
http://www.codeproject.com/com/wordhighlight.asp. It enumerates the data
formats currently available on the clipboard and tries to determine the
localized format name in m_szFaceFormatName and m_szMaskFormatName.

For your second question, it depends on how you copied the bitmap as button
face. There are several articles describing how to do it properly:

The KB: http://support.microsoft.com/kb/288771 (How To Create a Transparent
Picture For Office CommandBar Buttons) illustrates the standard way to copy
bitmaps as button face. (see the function 'CopyBitmapAsButtonFace').
Another article (http://www.daveswebsite.com/articles/article1/) translates
the above VB code to C++:
http://www.daveswebsite.com/articles/article1/OfficeTransButton_src.zip.
Besides, there is several tips and samples in the codeproject article
http://www.codeproject.com/com/wordhighlight.asp. I've tried all these
examples, and they work well when I set 'Enable=False' for the add-in
buttons.

Would you have a look at the articles above and check the codes again? If
it still cannot help to resolve the problem, would you paste your
"CopyBitmapAsButtonFace" here? And I will help to see where the problem is.

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

Hello Jialiang,
From your post, my understanding on this issue is: you want to know how
to resolve the failure of 'PasteFace' when the Office is not an English
version, in addition

No, this one i figured out. I do just the enumeration you suggest below.
you wonder why the button face of the Office add-in
works abnormally when it is disabled. If I'm off base, please feel free
to let me know.

Yes, that is my problem. When I create the DIBs (either 256 color or true
color DIB plus a 2 color mask DIB) I face the problem that Office 2000 apps
show empty command bar buttons. When I enable them the DIBs are correctly
used to draw the transparent image.
For your first question, please refer to the section '2. Transparent
button icon' of the codeproject article:
http://www.codeproject.com/com/wordhighlight.asp. It enumerates the data
formats currently available on the clipboard and tries to determine the
localized format name in m_szFaceFormatName and m_szMaskFormatName.

Yes, I followed that approach.
For your second question, it depends on how you copied the bitmap as
button face. There are several articles describing how to do it properly:

The KB: http://support.microsoft.com/kb/288771 (How To Create a
Transparent Picture For Office CommandBar Buttons) illustrates the
standard way to copy bitmaps as button face. (see the function
'CopyBitmapAsButtonFace'). Another article

Yes, that is the article I followd for DIB creation.
Would you have a look at the articles above and check the codes again? If
it still cannot help to resolve the problem, would you paste your
"CopyBitmapAsButtonFace" here? And I will help to see where the problem
is.

Here it is:

// spPic is an IPicture object created from a bmp resource
hr = spPic->get_Handle(&olePic);
hr = spPic->get_hPal(&olePal);
HBITMAP hb = (HBITMAP)olePic;
HPALETTE hp = (HPALETTE)olePal;

HPALETTE hPalOld = SelectPalette(hdc, hp, FALSE);
RealizePalette(hdc);

BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
GetDIBits(hdc, hb, 0, 0, 0, &bmi, DIB_RGB_COLORS);

int nColors = (bmi.bmiHeader.biBitCount > 8) ? 0 : (1 <<
bmi.bmiHeader.biBitCount);
DWORD headerLen = sizeof(bmi.bmiHeader) + nColors*sizeof(RGBQUAD);
HGLOBAL hBits = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, headerLen +
bmi.bmiHeader.biSizeImage);
if(hBits)
{
LPVOID pBits = GlobalLock(hBits);
CopyMemory(pBits, &bmi.bmiHeader, sizeof(bmi.bmiHeader));

GetDIBits(hdc, hb, 0, bmi.bmiHeader.biHeight,
((LPBYTE)pBits+headerLen), (LPBITMAPINFO)pBits, DIB_RGB_COLORS);

// S_OFF2000_CLIP_IMAGE was filled earlier with the localized name
of the clipboard format "Toolbar Button Face"
UINT clipImage = RegisterClipboardFormat(S_OFF2000_CLIP_IMAGE);

// I copy the DIB to put CF_DIB as well as the Toolbar format into
the clipboard
// I tried adding only the Toolbar format or both - neither way
the disabled button image was displayed
SIZE_T cbDIB = GlobalSize(hBits);
HANDLE hgDIB = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, cbDIB);
LPVOID pDIB = GlobalLock(hgDIB);
CopyMemory(pDIB, pBits, cbDIB);
GlobalUnlock(hgDIB);

GlobalUnlock(hBits);

BOOL f = OpenClipboard(NULL);
_sntprintf_s(sz, _countof(sz)-1, _TRUNCATE, _T("OpenClipboard =
%ld\n"), (int)f);
OutputDebugString(sz);

EmptyClipboard();

// CF_DIB might be optional so I tried with and without this
clipboard data
if(SetClipboardData(CF_DIB, hgDIB) == NULL)
GlobalFree(hgDIB);

if(SetClipboardData(clipImage, hBits) == NULL)
{
GlobalFree(hBits);
}
else
{
// Mask again is an IPicture
spPic = NULL;
hr = Mask->QueryInterface(&spPic);
if(spPic != NULL)
{
hr = spPic->get_Handle(&olePic);
hr = spPic->get_hPal(&olePal);
hb = (HBITMAP)olePic;
hp = (HPALETTE)olePal;

ZeroMemory(&bmi, sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);

GetDIBits(hdc, hb, 0, 0, 0, &bmi, DIB_RGB_COLORS);

nColors = (bmi.bmiHeader.biBitCount > 8) ? 0 : (1 <<
bmi.bmiHeader.biBitCount);
headerLen = sizeof(bmi.bmiHeader) + nColors*sizeof(RGBQUAD);
hBits = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE,
headerLen+bmi.bmiHeader.biSizeImage);
if(hBits)
{
pBits = GlobalLock(hBits);
CopyMemory(pBits, &bmi.bmiHeader, sizeof(bmi.bmiHeader));

GetDIBits(hdc, hb, 0, bmi.bmiHeader.biHeight,
((LPBYTE)pBits+headerLen), (LPBITMAPINFO)pBits, DIB_RGB_COLORS);

// S_OFF2000_CLIP_MASK contains the localized name of the
"Toolbar Button Mask"
UINT clipMask =
RegisterClipboardFormat(S_OFF2000_CLIP_MASK);
GlobalUnlock(hBits);

if(clipMask == 0 || SetClipboardData(clipMask, hBits) ==
NULL)
GlobalFree(hBits);
}
}
}

f = CloseClipboard();

_sntprintf_s(sz, _countof(sz)-1, _TRUNCATE, _T("CloseClipboard =
%ld\n"), (int)f);
OutputDebugString(sz);
}

}

// apply the clipboard data and ensure the button is visible
hr = Button->raw_PasteFace();
hr = Button->put_Visible(VARIANT_TRUE);

// later on I have Button->put_Enabled(VARIANT_FALSE) which causes the
image to disappear.


Thanks for any help on this. So far I just dropped the transparent image
support and use the standard WinXP background color where my images should
be transparent. As I need Office 2000 support only for a minority of
customers this could be a workaround.
 
S

SvenC

Hi Jialiang,
Thanks for your patience. Based on the codes you provided, your
'CopyTransBitmap' method can be separated into 4 parts:

#1. Load the button image and get a HBITMAP object.

I use LoadBitmap to access an embedded bitmap resource and
OleCreatePictureIndirect:

HBITMAP hb = LoadBitmap(AfxGetResourceHandle(), MAKEINTRESOURCE(resID));
HBITMAP hbMask = NULL;

PICTDESC pd = {0};
pd.cbSizeofstruct = sizeof(pd);
pd.picType = PICTYPE_BITMAP;
pd.bmp.hbitmap = hb;
HRESULT hr = OleCreatePictureIndirect(&pd, IID_IPictureDisp, TRUE,
(void**)ppIcon);
if(SUCCEEDED(hr))
{
hr = HypPictureCreateMask(hb, 0xFF00FF, &hbMask);
pd.bmp.hbitmap = hbMask;
hr = OleCreatePictureIndirect(&pd, IID_IPictureDisp, TRUE,
(void**)ppMask);
hbMask = NULL;
}

return hr;
#2. Load the Mask image and get a HBITMAP object for the mask.

I create the mask on the fly with my helper function HypPictureCreateMask

HRESULT HypPictureCreateMask(HBITMAP hSourceBmp, COLORREF maskColor,
HBITMAP* pMaskBmp)
{
HRESULT hr = S_OK;

HDC hdcTarget, hdcSource;
hdcTarget = CreateCompatibleDC(NULL);
hdcSource = CreateCompatibleDC(hdcTarget);
CBitmap bmp;

BITMAP bm = {0};
SIZE srcSize = {0};
GetObject(hSourceBmp, sizeof(bm), (LPVOID)&bm);
if(GetBitmapDimensionEx(hSourceBmp, &srcSize))
{
HPALETTE hPal = CreateHalftonePalette(hdcTarget);
HPALETTE hPalOld = SelectPalette(hdcSource, hPal, TRUE);
RealizePalette(hdcSource);

HGDIOBJ hOldSource = SelectObject(hdcSource, hSourceBmp);
*pMaskBmp = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL);

HDC hdcMask = CreateCompatibleDC(hdcTarget);
if(hdcMask)
{
HGDIOBJ hOldMask = SelectObject(hdcMask, *pMaskBmp);

SetBkColor(hdcSource, maskColor);
SetTextColor(hdcSource, 0xFFFFFF);

BitBlt(hdcMask, 0, 0, bm.bmWidth, bm.bmHeight, hdcSource, 0, 0,
SRCCOPY);

SelectObject(hdcMask, hOldMask);

DeleteDC(hdcMask);
}

SelectObject(hdcSource, hOldSource);
SelectPalette(hdcSource, hPalOld, FALSE);
}
else
hr = E_FAIL;

DeleteDC(hdcSource);
DeleteDC(hdcTarget);

return hr;
}
You did not provide the codes of part 1 and 2. therefore I suppose that
you are using OleLoadPicture to load the IPicture for both the button
face and mask. I tested the 4 parts and find that #1, #3 and #4 work
well and #2 cause the error. Would you let me know how did you set the
Mask's HBITMAP? When I replace the part2's code with the following code
listing, the button face works well. You may also download the test
project attached to this reply with Outlook Express.

I do not see any bigger differences between the two code fragments. Do you
see something?
To make my problem clear again: the enabled button face displays correctly.
So the image and mask are used correctly. Only when this the buttons Enabled
attribute is set to False the image is not displayed at all. Can you
reproduce this behaviour?

Best regards,
Sven
 
J

Jialiang Ge [MSFT]

Hi Sven,

Would you mind letting me know the result of the suggestions? If you need
further assistance, feel free to let me know. I will be more than happy to
be of assistance.

Have a great day!

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

=================================================
When responding to posts, please "Reply to Group" via your newsreader
so that others may learn and benefit from your issue.
=================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
S

SvenC

Hi Jialiang,
I reproduce the issue in my side with the codes about how you load the
bitmap resource. I think the problem is caused by the call:
HBITMAP hSrcBmp = LoadBitmap(AfxGetResourceHandle(),
MAKEINTRESOURCE(IDB_BITMAP1));
The method LoadBitmap has been superseded by the LoadImage function
because it is incompatible with some device context. The problem is
resolved in my side when I changed the sentence to:
HBITMAP hSrcBmp = (HBITMAP)::LoadImage(GetModuleHandle(NULL),
MAKEINTRESOURCE(IDB_BITMAP1), IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION);
Please have a try and let me know the result.

Absolutely correct!
LR_CREATEDIBSECTION seems to be the key. Without that flag the image
vanishes when the button is disabled, with that bit everything is fine.
Thanks a lot!
 

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