Wine の HDC, DC, DCE, HWND の関係
関連リンク
[目次] (https://qiita.com/Yutaka_Aoki/items/9d38ea98406f4096435b)
DC 型 = sturct DC
~/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
~/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 の相互リンク
結論的には:
HDC hdc;
struct dce *dce;
DC *dc = get_dc_ptr( hdc );
dce->hdc = hdc;
dc->dwHookData = dce:
根拠 :
~/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;
}
~/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 を取得
DC *dc = get_dc_ptr( hdc );
/* dc に関する処理 */
release_dc_ptr( dc );
get_dc_ptr() を呼び出すと、「GDI lock」なる処理が行われる。「unlock」するために、release_dc_ptr() が必要らしい。
dc から dce を取得
(絶対に正しく動作するかは不明です)
独自関数
struct dce *get_dce_of_dc( DC *dc )
{
return (struct dce *)(dc->dwHookData);
}
dce から hdc を取得
独自関数
HDC get_hdc_of_dce( struct dce *dce )
{
return dce->hdc;
}
dc から hdc を取得
(絶対に正しく動作するかは不明です)
独自関数1
HDC get_hdc_of_dce( DC *dc )
{
return dc->hSelf;
}
独自関数2
HDC get_hdc_of_dce2( DC *dc )
{
struct dce *dce = (struct dce *)(dc->dwHookData);
return dce->hdc;
}
HDC から HWND を取得する方法
実際に上手く行くかは条件次第なので、注意が必要であり、実際に使うには、条件を満たしているかをチェックする必要がある。正確な条件は今のところよく分かってない。そもそも、CompatibleDC で HBITMAP を使う場合などは、HDC には、HWND が対応していない場合があるはず。危険なので、このままコピペして使うのは絶対してはならない。
独自関数
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)
~/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;
}
}