Creating a Direct2D BitmapSource from a Win32 icon

2019-07-21 07:39发布

问题:

I created an application in C# that gets icon images from window handles using user32.dll like this:

[DllImport("user32.dll", EntryPoint = "GetClassLong")]
private static extern int GetClassLongPtr32(IntPtr hWnd, int nIndex);

public static IntPtr GetAppIcon(IntPtr hwnd)
{
    return WI.GetClassLongPtr32(hwnd, WI.ICON_SMALL);
}

And I want to create a BitmapSource from this icon pointer. Usually for WPF I would use

Imaging.CreateBitmapSourceFromHIcon(handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());

But since I need the BitmapSource to draw it in a Direct2D render target I would need to use DirectX's BitmapSource

Microsoft.WindowsAPICodePack.DirectX.WindowImagingComponent.BitmapSource

How can I create this kind of BitmapSource using the icon handle or can I transfer one BitmapSource type to the other?

回答1:

The ID2D1DeviceContext has a method CreateBitmapFromWicBitmap.

With its help you can create an ID2D1Bitmap. The only thing you have to do is to create an IWICBitmap from your HICON and then create an IWICFormatConverter, so you can keep the alpha channel. You can do it this way (The snippet from below is a delphi one but in C# should be very similar):

procedure iconToD2D1Bitmap;
var
  hIcon: HICON;
  wicBitmap: IWICBitmap;
  wicConverter: IWICFormatConverter;
  wicFactory: IWICImagingFactory;  
  bitmapProps: D2D1_BITMAP_PROPERTIES1;
  bitmap: ID2D1Bitmap1;
begin
  // get a HICON
  hIcon := SendMessage(Handle, WM_GETICON, ICON_BIG, 0);
  try  
    // create wic imaging factory
    CoCreateInstance(CLSID_WICImagingFactory, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IUnknown, wicFactory);

    wicFactory.CreateBitmapFromHICON(hIcon, wicBitmap);
    wicFactory.CreateFormatConverter(wicConverter);

    wicConverter.Initialize(wicBitmap, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, nil, 0, WICBitmapPaletteTypeMedianCut);

    bitmapProps.bitmapOptions := D2D1_BITMAP_OPTIONS_NONE;
    bitmapProps.pixelFormat.format := DXGI_FORMAT_B8G8R8A8_UNORM;
    bitmapProps.pixelFormat.alphaMode := D2D1_ALPHA_MODE_PREMULTIPLIED;
    bitmapProps.dpiX := 96;
    bitmapProps.dpiY := 96;
    bitmapProps.colorContext := nil;    

    // deviceContext should be a valid D2D1DeviceContext
    deviceContext.CreateBitmapFromWicBitmap(wicConverter, @bitmapProps, bitmap);

    // the bitmap variable contains your icon

  except
    //
  end;
end;