Wine の HDC, DC, DCE, HWND の関係

# Wine の HDC, DC, DCE, HWND の関係


## 関連リンク

[目次] (https://qiita.com/Yutaka_Aoki/items/9d38ea98406f4096435b)


## DC 型 = sturct DC

```c:~/wine/dlls/gdi32/gdi_private.h
typedef struct tagDC {
    HDC          hSelf;            /* Handle to this DC */
    struct gdi_physdev nulldrv;    /* physdev for the null driver */
    PHYSDEV      physDev;          /* current top of the physdev stack */
    DWORD        thread;           /* thread owning the DC */
    LONG         refcount;         /* thread refcount */
    LONG         dirty;            /* dirty flag */
    LONG         disabled;         /* get_dc_ptr() will return NULL.  Controlled by DCHF_(DISABLE|ENABLE)DC */
    INT          saveLevel;
    struct tagDC *saved_dc;
    DWORD_PTR    dwHookData;
    DCHOOKPROC   hookProc;         /* DC hook */
    BOOL         bounds_enabled:1; /* bounds tracking is enabled */
    BOOL         path_open:1;      /* path is currently open (only for saved DCs) */

    POINT        wnd_org;          /* Window origin */
    SIZE         wnd_ext;          /* Window extent */
    POINT        vport_org;        /* Viewport origin */
    SIZE         vport_ext;        /* Viewport extent */
    SIZE         virtual_res;      /* Initially HORZRES,VERTRES. Changed by SetVirtualResolution */
    SIZE         virtual_size;     /* Initially HORZSIZE,VERTSIZE. Changed by SetVirtualResolution */
    RECT         vis_rect;         /* visible rectangle in screen coords */
    RECT         device_rect;      /* rectangle for the whole device */
    int          pixel_format;     /* pixel format (for memory DCs) */
    UINT         aa_flags;         /* anti-aliasing flags to pass to GetGlyphOutline for current font */
    FLOAT        miterLimit;

    int           flags;
    DWORD         layout;
    HRGN          hClipRgn;      /* Clip region */
    HRGN          hMetaRgn;      /* Meta region */
    HRGN          hVisRgn;       /* Visible region */
    HRGN          region;        /* Total DC region (intersection of clip and visible) */
    HPEN          hPen;
    HBRUSH        hBrush;
    HFONT         hFont;
    HBITMAP       hBitmap;
    HPALETTE      hPalette;

    struct gdi_path *path;

    UINT          font_code_page;
    WORD          ROPmode;
    WORD          polyFillMode;
    WORD          stretchBltMode;
    WORD          relAbsMode;
    WORD          backgroundMode;
    COLORREF      backgroundColor;
    COLORREF      textColor;
    COLORREF      dcBrushColor;
    COLORREF      dcPenColor;
    POINT         brush_org;

    DWORD         mapperFlags;       /* Font mapper flags */
    WORD          textAlign;         /* Text alignment from SetTextAlign() */
    INT           charExtra;         /* Spacing from SetTextCharacterExtra() */
    INT           breakExtra;        /* breakTotalExtra / breakCount */
    INT           breakRem;          /* breakTotalExtra % breakCount */
    INT           MapMode;
    INT           GraphicsMode;      /* Graphics mode */
    ABORTPROC     pAbortProc;        /* AbortProc for Printing */
    POINT         cur_pos;           /* Current position */
    INT           ArcDirection;
    XFORM         xformWorld2Wnd;    /* World-to-window transformation */
    XFORM         xformWorld2Vport;  /* World-to-viewport transformation */
    XFORM         xformVport2World;  /* Inverse of the above transformation */
    BOOL          vport2WorldValid;  /* Is xformVport2World valid? */
    RECT          bounds;            /* Current bounding rect */
} DC;
```

## struct dce

```c:~/wine/dlls/user32/painting.c
struct dce {
    struct list entry;         /* entry in global DCE list */
    HDC         hdc;
    HWND        hwnd;
    HRGN        clip_rgn;
    DWORD       flags;
    LONG        count;         /* usage count; 0 or 1 for cache DCEs, always 1 for window DCEs,
                                  always >= 1 for class DCEs */
};
```



## DC と struct dce の相互リンク

結論的には:

```c:
HDC			hdc;
struct dce	*dce;
DC			*dc		= get_dc_ptr( hdc );

dce->hdc       = hdc;
dc->dwHookData = dce:
```

根拠 :

```c:~/dlls/user32/painting.c
// Allocate a new DCE.
static struct dce *alloc_dce(void)
{
    struct dce *dce;

    if (!(dce = HeapAlloc( GetProcessHeap(), 0, sizeof(*dce) ))) return NULL;
    if (!(dce->hdc = CreateDCW( displayW, NULL, NULL, NULL )))
    {
        HeapFree( GetProcessHeap(), 0, dce );
        return 0;
    }
    dce->hwnd      = 0;
    dce->clip_rgn  = 0;
    dce->flags     = 0;
    dce->count     = 1;

    /* store DCE handle in DC hook data field */
    SetDCHook( dce->hdc, dc_hook, (DWORD_PTR)dce );
    SetHookFlags( dce->hdc, DCHF_INVALIDATEVISRGN );
    return dce;
}
```

```c:~/wine/dlls/gdi32/dc.c
// Note: this doesn't exist in Win32, we add it here because user32 needs it.
BOOL WINAPI SetDCHook( HDC hdc, DCHOOKPROC hookProc, DWORD_PTR dwHookData )
{
    DC *dc = get_dc_ptr( hdc );

    if (!dc) return FALSE;

    dc->dwHookData = dwHookData;
    dc->hookProc = hookProc;
    release_dc_ptr( dc );
    return TRUE;
}

// Note: this doesn't exist in Win32, we add it here because user32 needs it.
DWORD_PTR WINAPI GetDCHook( HDC hdc, DCHOOKPROC *proc )
{
    DC *dc = get_dc_ptr( hdc );
    DWORD_PTR ret;

    if (!dc) return 0;
    if (proc) *proc = dc->hookProc;
    ret = dc->dwHookData;
    release_dc_ptr( dc );
    return ret;
}
```


## hdc から dc を取得

```c:
DC *dc = get_dc_ptr( hdc );

/* dc に関する処理 */

release_dc_ptr( dc );
```

get_dc_ptr() を呼び出すと、「GDI lock」なる処理が行われる。「unlock」するために、release_dc_ptr() が必要らしい。


## dc から dce を取得

(絶対に正しく動作するかは不明です)

```c:独自関数
struct dce *get_dce_of_dc( DC *dc )
{
	return	(struct dce *)(dc->dwHookData);
}
```

## dce から hdc を取得

```c:独自関数
HDC get_hdc_of_dce( struct dce *dce )
{
	return	dce->hdc;
}
```

## dc から hdc を取得

(絶対に正しく動作するかは不明です)

```c:独自関数1
HDC get_hdc_of_dce( DC *dc )
{
	return	dc->hSelf;
}
```

```c:独自関数2
HDC get_hdc_of_dce2( DC *dc )
{
	struct dce	*dce	= (struct dce *)(dc->dwHookData);
	
	return	dce->hdc;
}
```


## HDC から HWND を取得する方法

実際に上手く行くかは条件次第なので、注意が必要であり、実際に使うには、条件を満たしているかをチェックする必要がある。正確な条件は今のところよく分かってない。そもそも、CompatibleDC で HBITMAP を使う場合などは、HDC には、HWND が対応していない場合があるはず。危険なので、このままコピペして使うのは絶対してはならない。

```c:独自関数
HWND __get_hwnd_of_hdc( HDC hdc )
{
	DC			*dc		= get_dc_ptr( hdc );
	
	struct dce	*dce	= (struct dce *)(dc->dwHookData);
	HWNE		hwnd	= dce->hwnd;
    
    release_dc_ptr( dc );
    
    return	hwnd;
}
```




### DC *get_dc_ptr( HDC hdc)

```c:~/wine/dlls/gdi32/dc.c
// Retrieve a DC pointer but release the GDI lock.
DC *get_dc_ptr( HDC hdc )
{
    DC *dc = get_dc_obj( hdc );
    if (!dc) return NULL;
    if (dc->disabled)
    {
        GDI_ReleaseObj( hdc );
        return NULL;
    }

    if (!InterlockedCompareExchange( &dc->refcount, 1, 0 ))
    {
        dc->thread = GetCurrentThreadId();
    }
    else if (dc->thread != GetCurrentThreadId())
    {
        WARN( "dc %p belongs to thread %04x\n", hdc, dc->thread );
        GDI_ReleaseObj( hdc );
        return NULL;
    }
    else InterlockedIncrement( &dc->refcount );

    GDI_ReleaseObj( hdc );
    return dc;
}

static inline DC *get_dc_obj( HDC hdc )
{
    WORD type;
    DC *dc = get_any_obj_ptr( hdc, &type );
    if (!dc) return NULL;

    switch (type)
    {
    case OBJ_DC:
    case OBJ_MEMDC:
    case OBJ_METADC:
    case OBJ_ENHMETADC:
        return dc;
    default:
        GDI_ReleaseObj( hdc );
        SetLastError( ERROR_INVALID_HANDLE );
        return NULL;
    }
}
```