See the question and my original answer on StackOverflow

Here is a console application code that dumps all GDI handles out for a given process identifier. It should compile and work fine for 32 or 64-bit applications, as well as 32-bit application running on 64-bit OSes. It uses a lot of undocumented functions so don't rely on it :-) Credits on structures for the shared GDI table goes to Feng Yuan original work. (I had to adapt it for WOW64).

Here is a sample output when ran on a Notepad (64-bit) process:

[C:\Temp\EnumGdi\Debug]EnumGdi.exe 5916
DC handle:0xF20105DB
Bitmap handle:0xDF05118B
Font handle:0xDC0A19E0
Font handle:0xAB0A1A62
DC handle:0xA3011A63
Region handle:0xAF041B7B
Brush handle:0x11101C5B
Font handle:0x280A1CA1
Font handle:0xBB0A1D13
Bitmap handle:0xA3051DD8
Font handle:0xB40A1DDC
Region handle:0x3A041EE4
Brush handle:0x0B101F04
Region handle:0xC6041F3D
Font handle:0x2C0A2384
Brush handle:0xBA1024DA

EnumGdi.cpp:

#include "stdafx.h"
#include "enumgdi.h"

int _tmain(int argc, _TCHAR* argv[])
{   
    if (argc < 2)
    {
        printf("Format is EnumGdi <process id>\n");
        return 0;
    }

    // get process identifier
    DWORD dwId = _wtoi(argv[1]);

    // open the process
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwId);
    DWORD err = 0;
    if (hProcess == NULL)
    {
        printf("OpenProcess %u failed\n", dwId);
        err = GetLastError();
        return -1;
    }

    // determine if 64 or 32-bit processor
    SYSTEM_INFO si;
    GetNativeSystemInfo(&si);

    // NOTE: as this is undocumented, it *may vary* depending on bitness (32/64) and on Windows version.
    // use WinDbg "dt ntdll!_PEB" command and search for GdiSharedHandleTable offset to find the truth out
    DWORD GdiSharedHandleTableOffset  = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? 0xF8 : 0x94;
    DWORD tableCount = 16384; // count of GDI table cells

    // determine if this process is running on WOW64
    BOOL wow;
    IsWow64Process(GetCurrentProcess(), &wow);

    // read basic info to get PEB address, we only need the beginning of PEB
    DWORD pebSize = GdiSharedHandleTableOffset + 8;
    LPBYTE peb = (LPBYTE)malloc(pebSize);
    ZeroMemory(peb, pebSize);

    if (wow)
    {
        // we're running as a 32-bit process in a 64-bit process
        PROCESS_BASIC_INFORMATION_WOW64 pbi;
        ZeroMemory(&pbi, sizeof(pbi));

        // get process information from 64-bit world
        _NtQueryInformationProcess query = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtWow64QueryInformationProcess64");
        err = query(hProcess, 0, &pbi, sizeof(pbi), NULL);
        if (err != 0)
        {
            printf("NtWow64QueryInformationProcess64 failed\n");
            CloseHandle(hProcess);
            return -1;
        }

        // read PEB from 64-bit address space
        _NtWow64ReadVirtualMemory64 read = (_NtWow64ReadVirtualMemory64)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtWow64ReadVirtualMemory64");
        err = read(hProcess, pbi.PebBaseAddress, peb, pebSize, NULL);
        if (err != 0)
        {
            printf("NtWow64ReadVirtualMemory64 PEB failed\n");
            CloseHandle(hProcess);
            return -1;
        }

        // get GDI table ptr from PEB
        GDICELL_WOW64* gdiTable = (GDICELL_WOW64*)*(LPVOID*)(peb + GdiSharedHandleTableOffset); // address in remote process adress space
        if (gdiTable == NULL)
        {
            printf("GDI32.DLL is not loaded in the process\n");
            CloseHandle(hProcess);
            return -1;
        }
        free(peb);
        DWORD tableSize = sizeof(GDICELL_WOW64) * tableCount; // size of GDI table
        GDICELL_WOW64* table = (GDICELL_WOW64*)malloc(tableSize); // local table copied over to our address space

        // copy GDI table
        err = read(hProcess, gdiTable, table, tableSize, NULL);
        if (err != 0)
        {
            printf("NtWow64ReadVirtualMemory64 GdiTable failed\n");
            free(table);
            CloseHandle(hProcess);
            return -1;
        }

        for(DWORD i = 0; i < tableCount; i++)
        {
            GDICELL_WOW64 cell = table[i];
            if (cell.wProcessId != dwId)
                continue;

            HGDIOBJ gdiHandle = (HGDIOBJ)((cell.wUpper << 16) + i);
            WORD type = cell.wType & 0x7F;
            switch(type)
            {
                case 1:
                    printf("DC handle:0x%08X\n", gdiHandle );
                    break;

                case 4:
                    printf("Region handle:0x%08X\n", gdiHandle);
                    break;

                case 5:
                    printf("Bitmap handle:0x%08X\n", gdiHandle);
                    break;

                case 8:
                    printf("Palette handle:0x%08X\n", gdiHandle);
                    break;

                case 10:
                    printf("Font handle:0x%08X\n", gdiHandle);
                    break;

                case 16:
                    printf("Brush handle:0x%08X\n", gdiHandle);
                    break;

                case 48:
                    printf("Pen handle:0x%08X\n", gdiHandle);
                    break;

                default:
                    printf("Unknown type handle:0x%08X\n", gdiHandle);
                    break;
            }
        }
        free(table);
    }
    else
    {
        // we're running as a 32-bit process in a 32-bit OS, or as a 64-bit process in a 64-bit OS
        PROCESS_BASIC_INFORMATION pbi;
        ZeroMemory(&pbi, sizeof(pbi));

        // get process information
        _NtQueryInformationProcess query = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess");
        err = query(hProcess, 0, &pbi, sizeof(pbi), NULL);
        if (err != 0)
        {
            printf("NtQueryInformationProcess failed\n");
            CloseHandle(hProcess);
            return -1;
        }

        // read PEB
        _NtReadVirtualMemory read = (_NtReadVirtualMemory)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtReadVirtualMemory");
        err = read(hProcess, pbi.PebBaseAddress, peb, pebSize, NULL);
        if (err != 0)
        {
            printf("NtReadVirtualMemory PEB failed\n");
            CloseHandle(hProcess);
            return -1;
        }

        // get GDI table ptr
        GDICELL* gdiTable = (GDICELL*)*(LPVOID*)(peb + GdiSharedHandleTableOffset); // address in remote process adress space
        if (gdiTable == NULL)
        {
            printf("GDI32.DLL is not loaded in the process\n");
            CloseHandle(hProcess);
            return -1;
        }
        free(peb);

        DWORD tableSize = sizeof(GDICELL) * tableCount; // size of GDI table
        GDICELL* table = (GDICELL*)malloc(tableSize); // local table copied over to our address space

        // read GDI table
        err = read(hProcess, gdiTable, table, tableSize, NULL);
        if (err != 0)
        {
            printf("NtReadVirtualMemory GdiTable failed\n");
            free(table);
            CloseHandle(hProcess);
            return -1;
        }

        for(DWORD i = 0; i < tableCount; i++)
        {
            GDICELL cell = table[i];
            if (cell.wProcessId != dwId)
                continue;

            HGDIOBJ gdiHandle = (HGDIOBJ)((cell.wUpper << 16) + i);
            WORD type = cell.wType & 0x7F;
            switch(type)
            {
                case 1:
                    printf("DC handle:0x%08X\n", gdiHandle );
                    break;

                case 4:
                    printf("Region handle:0x%08X\n", gdiHandle);
                    break;

                case 5:
                    printf("Bitmap handle:0x%08X\n", gdiHandle);
                    break;

                case 8:
                    printf("Palette handle:0x%08X\n", gdiHandle);
                    break;

                case 10:
                    printf("Font handle:0x%08X\n", gdiHandle);
                    break;

                case 16:
                    printf("Brush handle:0x%08X\n", gdiHandle);
                    break;

                case 48:
                    printf("Pen handle:0x%08X\n", gdiHandle);
                    break;

                default:
                    printf("Unknown type handle:0x%08X\n", gdiHandle);
                    break;
            }
        }
        free(table);
    }
    CloseHandle(hProcess);
}

EnumGdi.h:

#pragma once
#include "stdafx.h"

// defines a GDI CELL
typedef struct
{
    LPVOID pKernelAddress;
    USHORT wProcessId;
    USHORT wCount;
    USHORT wUpper;
    USHORT wType;
    LPVOID pUserAddress;
} GDICELL;

// defines a GDI CELL for WOW64
typedef struct
{
    PVOID64 pKernelAddress;
    USHORT wProcessId;
    USHORT wCount;
    USHORT wUpper;
    USHORT wType;
    PVOID64 pUserAddress;
} GDICELL_WOW64;

// NtQueryInformationProcess for pure 32 and 64-bit processes
typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
    IN HANDLE ProcessHandle,
    ULONG ProcessInformationClass,
    OUT PVOID ProcessInformation,
    IN ULONG ProcessInformationLength,
    OUT PULONG ReturnLength OPTIONAL
    );

typedef NTSTATUS (NTAPI *_NtReadVirtualMemory)(
    IN HANDLE ProcessHandle,
    IN PVOID BaseAddress,
    OUT PVOID Buffer,
    IN SIZE_T Size,
    OUT PSIZE_T NumberOfBytesRead);

// NtQueryInformationProcess for 32-bit process on WOW64
typedef NTSTATUS (NTAPI *_NtWow64ReadVirtualMemory64)(
    IN HANDLE ProcessHandle,
    IN PVOID64 BaseAddress,
    OUT PVOID Buffer,
    IN ULONG64 Size,
    OUT PULONG64 NumberOfBytesRead);

// PROCESS_BASIC_INFORMATION for pure 32 and 64-bit processes
typedef struct _PROCESS_BASIC_INFORMATION {
    PVOID Reserved1;
    PVOID PebBaseAddress;
    PVOID Reserved2[2];
    ULONG_PTR UniqueProcessId;
    PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;

// PROCESS_BASIC_INFORMATION for 32-bit process on WOW64
// The definition is quite funky, as we just lazily doubled sizes to match offsets...
typedef struct _PROCESS_BASIC_INFORMATION_WOW64 {
    PVOID Reserved1[2];
    PVOID64 PebBaseAddress;
    PVOID Reserved2[4];
    ULONG_PTR UniqueProcessId[2];
    PVOID Reserved3[2];
} PROCESS_BASIC_INFORMATION_WOW64;