How to preview GDI+ images on Image Watch?

Leo Purktz 0 Reputation points
2024-09-18T06:25:55.6733333+00:00

I'm trying to visualize on memory GDI+ images using the Image Watch extension, i requested support on this feature long time ago directly on the developercommunity it got a lot of upvotes but MSFT just market it as "under review".

I tried to follow the documentation and implement the natvis myself, but i'm not suceeding on get it to work.

A reproducible example:

#include <windows.h>
#include <iostream>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment (lib, "Gdiplus.lib")
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
    UINT num = 0;
    UINT size = 0;
    ImageCodecInfo* pImageCodecInfo = nullptr;
    GetImageEncodersSize(&num, &size);
    if (size == 0)
        return -1;
    pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
    if (pImageCodecInfo == nullptr)
        return -1;
    GetImageEncoders(num, size, pImageCodecInfo);
    for (UINT j = 0; j < num; ++j)
    {
        if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0)
        {
            *pClsid = pImageCodecInfo[j].Clsid;
            free(pImageCodecInfo);
            return 1;
        }
    }
    free(pImageCodecInfo);
    return 0;
}
int main()
{
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
    HDC hScreenDC      = GetDC(nullptr);
    HDC hMemoryDC      = CreateCompatibleDC(hScreenDC);
    int screenWidth    = GetSystemMetrics(SM_CXSCREEN);
    int screenHeight   = GetSystemMetrics(SM_CYSCREEN);
    HBITMAP hBitmap    = CreateCompatibleBitmap(hScreenDC, screenWidth, screenHeight);
    HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap);
    BitBlt(hMemoryDC, 0, 0, screenWidth, screenHeight, hScreenDC, 0, 0, SRCCOPY);
    Bitmap bitmap(hBitmap, nullptr);
    CLSID clsid;
    if (GetEncoderClsid(L"image/png", &clsid) == 1)
    {
        if (bitmap.Save(L"test.png", &clsid, nullptr) != Gdiplus::Ok)
            std::wcerr << L"Failed to save the screenshot." << std::endl;
    }
    else
        std::wcerr << L"Failed to get encoder CLSID." << std::endl;
    // ...
    // cleanups ignored as this code is just for debugging
}

And my current natvis implementation:

<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
	<UIVisualizer ServiceId="{A452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1"
				  MenuName="Add to Image Watch"/>
	<!-- GDI BITMAP -->
	<Type Name="tagBITMAP">
		<UIVisualizer ServiceId="{A452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1" />
		<Expand>
			<Item Name="[width]">bmWidth</Item>
			<Item Name="[height]">bmHeight</Item>
			<Item Name="[stride]">bmWidthBytes</Item>
			<Synthetic Name="[channels]">
				<DisplayString Condition="bmBitsPixel == 8">L</DisplayString>
				<DisplayString Condition="bmBitsPixel == 24">RGB</DisplayString>
				<DisplayString Condition="bmBitsPixel == 32">RGBA</DisplayString>
			</Synthetic>
			<Synthetic Name="[type]">
				<DisplayString>UINT8</DisplayString>
			</Synthetic>
			<Item Name="[data]">bmBits</Item>
		</Expand>
	</Type>
	<!-- GDI HBITMAP -->
	<Type Name="HBITMAP__">
		<UIVisualizer ServiceId="{A452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1" />
		<Expand>
			<CustomListItems>
				<Variable Name="pBitmap" InitialValue="0" />
				<Exec>pBitmap = (tagBITMAP*)alloca(sizeof(tagBITMAP))</Exec>
				<Exec>GetObject((HBITMAP)this, sizeof(tagBITMAP), pBitmap)</Exec>
				<Item Name="[width]">pBitmap->bmWidth</Item>
				<Item Name="[height]">pBitmap->bmHeight</Item>
				<Item Name="[stride]">pBitmap->bmWidthBytes</Item>
				<Item Name="[channels]">
					pBitmap->bmBitsPixel == 8 ? "L" :
					pBitmap->bmBitsPixel == 24 ? "RGB" :
					pBitmap->bmBitsPixel == 32 ? "RGBA" : "UNKNOWN"
				</Item>
				<Item Name="[type]">"UINT8"</Item>
				<Item Name="[data]">pBitmap->bmBits</Item>
			</CustomListItems>
		</Expand>
	</Type>
	<!-- GDI+ Bitmap -->
	<Type Name="Gdiplus::Bitmap">
		<UIVisualizer ServiceId="{A452AFEA-3DF6-46BB-9177-C0B08F318025}" Id="1" />
		<Expand>
			<CustomListItems>
				<Variable Name="width" InitialValue="0" />
				<Variable Name="height" InitialValue="0" />
				<Variable Name="stride" InitialValue="0" />
				<Variable Name="pixelFormat" InitialValue="0" />
				<Variable Name="scan0" InitialValue="0" />
				<Exec>this->GetWidth(&amp;width)</Exec>
				<Exec>this->GetHeight(&amp;height)</Exec>
				<Exec>Gdiplus::BitmapData bitmapData;</Exec>
				<Exec>Gdiplus::Rect rect(0, 0, width, height);</Exec>
				<Exec>this->LockBits(&amp;rect, Gdiplus::ImageLockModeRead, PixelFormat32bppARGB, &amp;bitmapData)</Exec>
				<Exec>stride = bitmapData.Stride</Exec>
				<Exec>pixelFormat = bitmapData.PixelFormat</Exec>
				<Exec>scan0 = bitmapData.Scan0</Exec>
				<Exec>this->UnlockBits(&amp;bitmapData)</Exec>
				<Item Name="[width]">width</Item>
				<Item Name="[height]">height</Item>
				<Item Name="[stride]">stride</Item>
				<Item Name="[channels]">
					pixelFormat == PixelFormat24bppRGB ? "RGB" :
					pixelFormat == PixelFormat32bppARGB ? "RGBA" :
					pixelFormat == PixelFormat8bppIndexed ? "L" : "UNKNOWN"
				</Item>
				<Item Name="[type]">"UINT8"</Item>
				<Item Name="[data]">scan0</Item>
			</CustomListItems>
		</Expand>
	</Type>
</AutoVisualizer>

Using the natvis above the extension is detecting the local images but it always show them as invalid:

User's image

I'm testing on VS22/Image Watch for VS22.

Looking for any help on this issue.

Visual Studio
Visual Studio
A family of Microsoft suites of integrated development tools for building applications for Windows, the web and mobile devices.
5,193 questions
C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,760 questions
Visual Studio Extensions
Visual Studio Extensions
Visual Studio: A family of Microsoft suites of integrated development tools for building applications for Windows, the web and mobile devices.Extensions: A program or program module that adds functionality to or extends the effectiveness of a program.
227 questions
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.