Graphics That Are Rendered by GDI+ Cannot Be Magnified by Screen Magnifiers (319261)
The information in this article applies to:
- Microsoft .NET Framework 1.0, when used with:
- the operating system: Microsoft Windows XP
- Microsoft GDI+ 1.0, when used with:
- the operating system: Microsoft Windows XP
- Microsoft Office XP, when used with:
- the operating system: Microsoft Windows XP
- Microsoft Visio 2002 Professional, when used with:
- the operating system: Microsoft Windows XP
- Microsoft Visio 2002 Standard, when used with:
- the operating system: Microsoft Windows XP
This article was previously published under Q319261 SYMPTOMS
Graphics that are rendered by GDI+ cannot be magnified by screen magnifiers. This issue affects any program that uses GDI+, including Microsoft Office XP, Microsoft Visio 2002, Microsoft .NET Framework, and the Windows shell.
CAUSE
GDI+ uses a mechanism that is named DCI to render directly into the front buffer. GDI+ does not generate GDI DDI calls when it renders in this manner. However, screen magnifiers work by assuming that all rendering occurs through GDI. Screen magnifiers hook the GDI DDI calls, capture all rendering into an offscreen bitmap, and draw a portion of that bitmap magnified on the screen.
If a screen magnifier runs with a program that uses GDI+, some portions of the screen are drawn magnified and some portions are drawn unmagnified.
RESOLUTIONTo resolve this problem, obtain the latest service pack for Windows XP. For additional information, click the following article number to view the article in the
Microsoft Knowledge Base:
322389 How to Obtain the Latest Windows XP Service Pack
To resolve this problem, obtain the update that is mentioned in the following Microsoft Knowledge Base article:
318966 Problems Viewing, Editing, or Printing Some Images in Windows XP
For Program Developers
If you are a program developer, you must update your program so that it tells GDI+ to use GDI instead of DCI for rendering. Each GDI+ instance contains a hidden top-level window whose title is "GDI+ Window" and whose class name is GDI+ Hook Window Class. When you install the update that is described in article Q318966, the GDI+ hidden window listens for a private window message that is named "GDI+ Accessibility." If the GDI+ hidden window receives this message, it stops using DCI for rendering and starts using GDI instead. This makes GDI+ work correctly with screen magnifiers.
When a screen magnifier loads, it must register a private window message that is named "GDI+ Accessibility." GDI+ registers a private message of the same name, so the magnifier can communicate with GDI+ by using this message. The magnifier must then scan all existing top-level windows. If the magnifier finds any windows that are named "GDI+ Window" and whose class name is GDI+ Hook Window Class, the magnifier must send the "GDI+ Accessibility" message to those windows. This makes any existing GDI+ programs magnify correctly.
The screen magnifier must also watch for any new GDI+ programs that are loaded after it starts. The magnifier can do this by setting a callback function by using SetWinEventHook that is called every time a new window is created. If a new window is created with the correct title and class name, the magnifier must send the "GDI+ Accessibility" message to it.
Note that after a particular instance of GDI+ begins using GDI instead of DCI to render, it cannot switch back to using DCI unless the program is quit and restarted. GDI+ renders more slowly by using GDI than it does by using DCI. If the user no longer requires a magnifier with GDI+ and wants to increase rendering performance, the user can restart the GDI+ program.
STATUSMicrosoft has confirmed that this is a problem in the Microsoft products that are listed at the beginning of this article. This problem was first corrected in Windows XP Service Pack 1.MORE INFORMATION
The following sample program demonstrates how to use the new GDI+ functionality in your program. Include the Gdipacs.c and Gdipacs.h files in your project. You must call GDIPlusDCIOff_Init when your program starts. This causes all existing GDI+ programs to stop rendering by using DCI, and it causes any new GDI+ programs that are loaded not to use DCI to render. You must call GDIPlusDCIOff_Uninit when your program quits. Existing GDI+ programs cannot revert to using DCI, but new GDI+ programs will use DCI as they typically do.
The Testmain.c file demonstrates this functionality. Compile and run the file to test the "GDI+ Accessibility" message with your GDI+ programs.
Sample CodeMicrosoft provides programming examples for illustration only, without warranty either
expressed or implied, including, but not limited to, the implied warranties of
merchantability and/or fitness for a particular purpose. This article assumes
that you are familiar with the programming language being demonstrated and the
tools used to create and debug procedures. Microsoft support professionals can
help explain the functionality of a particular procedure, but they will not
modify these examples to provide added functionality or construct procedures to
meet your specific needs. If you have limited programming experience, you may
want to contact a Microsoft Certified Partner or the Microsoft fee-based
consulting line at (800) 936-5200. For more information about Microsoft Certified
Partners, please visit the following Microsoft Web site:
For more information about the support options that are available and about how to contact Microsoft, visit the following Microsoft Web site:
/*********************** Module*Header ************************\
* Module Name: gdipacs.h
*
* Copyright (c) 2002 Microsoft Corporation
\**************************************************************/
/*
* To tell GDI+ to stop using DCI:
* Call GDIPlusDCIOff_Init as part of your program startup.
* This must be called by a thread that has a message pump.
* Before terminating, call GDIPlusDCIOff_Uninit on that
* same thread to clean up.
*/
BOOL GDIPlusDCIOff_Init();
VOID GDIPlusDCIOff_Uninit();
/*********************** Module*Header ************************\
* Module Name: gdipacs.cpp
*
* Copyright (c) 2002 Microsoft Corporation
\**************************************************************/
// Need WINVER 0x0500 to get the definitions for WinEvents.
// (They will still work on Windows 95 and Windows NT 4.0 SP6.)
#define WINVER 0x0500
#include <windows.h>
#include "gdipacs.h"
#define GDIPLUS_TITLE TEXT("GDI+ Window")
#define GDIPLUS_CLASSNAME TEXT("GDI+ Hook Window Class")
#define GDIPLUS_DCIOFFMSG TEXT("GDI+ Accessibility")
HWINEVENTHOOK ghWinEventHook = NULL;
UINT gwmGdipMessage = 0;
static BOOL IsGDIPlusWindow(HWND hwnd)
{
TCHAR str[MAX_PATH];
// Check that window is top-level and unowned...
if(GetParent(hwnd) != NULL)
return FALSE;
// Check window class name...
if(GetClassName(hwnd, str, MAX_PATH) == 0
|| lstrcmp(str, GDIPLUS_CLASSNAME) != 0)
return FALSE;
// Check window title...
if(GetWindowText(hwnd, str, MAX_PATH) == 0
|| lstrcmp(str, GDIPLUS_TITLE) != 0)
return FALSE;
return TRUE;
}
static VOID SendDCIOFFMessage(HWND hwnd)
{
SendMessage(hwnd, gwmGdipMessage, 0, 0);
#ifdef _DEBUG
{
TCHAR strDebug[MAX_PATH];
// For debug purposes, output handle to hidden window.
wsprintf(
strDebug,
TEXT("Sent GDI+ Message: HWND=%08x\n"),
hwnd);
OutputDebugString(strDebug);
}
#endif
}
static BOOL CALLBACK WndEnumProc(
HWND hwnd,
LPARAM lParam
)
{
if(IsGDIPlusWindow(hwnd))
{
SendDCIOFFMessage(hwnd);
}
return TRUE;
}
VOID CALLBACK WindowCreateProc(
HWINEVENTHOOK hWinEventHook,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD dwEventThread,
DWORD dwmsEventTime
)
{
if (idObject == OBJID_WINDOW && IsGDIPlusWindow(hwnd))
{
SendDCIOFFMessage(hwnd);
}
}
BOOL GDIPlusDCIOff_Init()
{
if(ghWinEventHook != NULL)
return FALSE;
// Register the "turn off DCI" message...
gwmGdipMessage = RegisterWindowMessage(GDIPLUS_DCIOFFMSG);
if (gwmGdipMessage == 0)
{
return FALSE;
}
// Set a hook to watch for new windows being created...
ghWinEventHook = SetWinEventHook(
EVENT_OBJECT_CREATE,
EVENT_OBJECT_CREATE,
NULL,
WindowCreateProc,
0,
0,
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
if (ghWinEventHook == NULL)
{
return FALSE;
}
// Scan through existing windows...
EnumWindows(WndEnumProc, 0);
return TRUE;
}
VOID GDIPlusDCIOff_Uninit()
{
if(ghWinEventHook != NULL)
{
UnhookWinEvent(ghWinEventHook);
ghWinEventHook = NULL;
}
}
/*********************** Module*Header ************************\
* Module Name: testmain.c
*
* Copyright (c) 2002 Microsoft Corporation
\**************************************************************/
/*
* Sample program that demonstrates using GDIPACS.h to turn off
* the GDI+ use of DCI.
*/
#include <windows.h>
#include "gdipacs.h"
#define TITLE TEXT("GDI+ DCI Disabler")
int WINAPI
WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR szCmdLine,
int nCmdShow )
{
MessageBox(NULL,TEXT("Click OK to start disabling use of DCI..."), TITLE, MB_OK);
/*
* GDIPlusDCIOff_Init() must be called from a thread that pumps
* messages - typically the main UI thread. In this sample, the
* MessageBox calls contain message pumps. A real-world program
* likely has its own GetMessage() loop instead.
*/
if( ! GDIPlusDCIOff_Init() )
{
MessageBox(NULL,TEXT("GDIPlusDCIOff_Init() failed"), TITLE, MB_OK);
return 0;
}
MessageBox(NULL,TEXT("DCI is now turned off in all existing GDI+ programs. Click OK to turn on DCI again..."), TITLE, MB_OK);
GDIPlusDCIOff_Uninit();
MessageBox(NULL,TEXT("DCI remains turned off in all existing GDI+ programs, but will be turned on for new programs that start. Click OK to exit this sample."), TITLE, MB_OK);
return 0;
}
Modification Type: | Major | Last Reviewed: | 6/28/2004 |
---|
Keywords: | kbbug kbfix kbshell kbWinXPsp1fix KB319261 |
---|
|