admin管理员组

文章数量:1122847

I attached a project which shows a problem with DrawText() not outputting the correct color via SetTextColor().

Note that if you don't include the manifest for themes, it works.

So the question is, with theming enabled, how do you set your own color for DrawText().

Download the project I threw together from here for the "minimal reproducible sample" (as the x64 version).

The bitmap has "TEXT" added to it but it's not red text (unless themes are disabled), it's the background color.

This is the main routine which was already listed but they wanted a reproducible example, so I provided one, then apparently it's too much, so here's the main routine again from the reproducible project:

void AddTextToBitmap(HBITMAP hbitmap)
{
  HICON iconnew=NULL;

  // buffer for text
  TCHAR textbuffer[32];
  textbuffer[_countof(textbuffer)-1]=0;

  _tcsncpy(textbuffer, _T("TEST"), _countof(textbuffer)-1);

  BITMAP bm;
  if (GetObject(hbitmap, sizeof(bm), &bm)==sizeof(bm)) {
    // get dc to where the icon will go
    HDC hdc=GetDC(NULL);
    if (hdc) {
      // create a DC to modify our bitmap
      HDC hmemdc=CreateCompatibleDC(hdc);
      if (hmemdc!=NULL) {
        // apply the icon bitmap to the dc we created 
        HGDIOBJ orgmemdcbitmap=SelectObject(hmemdc, hbitmap);
        if (orgmemdcbitmap!=NULL) {
          // set our white color
          SetTextColor(hmemdc, RGB(255, 0, 0)); // RGB(255, 255, 255));
          // make text background transparent when writing text
          SetBkMode(hmemdc, TRANSPARENT);

          // setup rect of dc area for drawing text
          RECT rect;
          rect.bottom=bm.bmHeight-1;
          rect.right=bm.bmWidth-1;
          rect.top=2;
          rect.left=2;
          // draw the text to bar on our icon
          DrawText(hmemdc, textbuffer, -1, &rect, DT_TOP|DT_CENTER);

          // release our icon bitmap and put back the original bitmap
          SelectObject(hmemdc, orgmemdcbitmap);
        }
        // delete the dc we created
        DeleteDC(hmemdc);
      }
      // release the dc we acquired
      ReleaseDC(NULL, hdc);
    }
  }
}

Again: If you don't enable visual themes it works (red text), if you do (via manifest) it doesn't (text is background color).

Here's the manifest to enable themes for x64 - input file of project manifest option (see the full download project linked above):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 

    <dependency> 

        <dependentAssembly> 

            <assemblyIdentity 

            type="win32" 

            name="Microsoft.Windows.Common-Controls" 

            version="6.0.0.0" 

            processorArchitecture="amd64" 

            publicKeyToken="6595b64144ccf1df" 

            language="*" 

            /> 

        </dependentAssembly> 

    </dependency> 

</assembly> 

In the test app, I tried setting SetThemeAppProperties(0); at the top if InitInstance() (before creating class/window) but that didn't change anything. It's all dependent on the manifest being used or not. When the manifest is not used, you get the red text, also the 32bit graphic has black background area instead of transparent. I think the text is also actually transparent. This gives me an idea that maybe DrawText() is drawing with the alpha being transparent (0).

The Answer

Not sure why this can't be answered but the issue is related to enabling themes via the manifest which enables support for alpha channel in 32 bit graphics. When DrawText() draws, it sets the alpha channel to zero (transparent).

To work around it, you can check for themes enabled and 32bit graphic and use a unique oddball color with DrawText() then use a separate routine to set the actual color and transparency desired. Here's an example of such routine.

void FixDrawTextColor(HBITMAP hbitmap, COLORREF searchcolor, COLORREF desiredcolor, BYTE desiredalpha)
{
  BITMAP bm;
  if (GetObject(hbitmap, sizeof(bm), &bm)==sizeof(bm)) {
    // scan though bits to check
    if (bm.bmBitsPixel==32 && bm.bmBits) {
      // look for colors to make opaque
      for (int y=0; y<bm.bmHeight; ++y) {
        BYTE* ppixel=(BYTE*) bm.bmBits + (bm.bmWidthBytes * y);
        for (int x=0; x<bm.bmWidth; x++) {
          // check if search color that is transparent
          if (ppixel[3]==0 && ppixel[0]==GetBValue(searchcolor) && ppixel[1]==GetGValue(searchcolor) && ppixel[2]==GetRValue(searchcolor)) {
            // set new color
            ppixel[0]=GetBValue(desiredcolor);
            ppixel[1]=GetGValue(desiredcolor);
            ppixel[2]=GetRValue(desiredcolor);
            ppixel[3]=desiredalpha;
          }
          ppixel+=4;
        }
      }
    }
  }
}

本文标签: