You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
4.3 KiB
158 lines
4.3 KiB
// This is a dual threaded test app designed to expose a weakness in
|
|
// GDI+. The CreateDCA("DISPLAY", NULL, NULL, NULL) used to create our
|
|
// Globals::DesktopDc during GdiplusStartup has thread affinity (as opposed
|
|
// to other inputs to CreateDCA) and therefore when the creation thread
|
|
// is terminated, the global DC goes away. This will cause random drawing
|
|
// failure in gdiplus.
|
|
//
|
|
// The main thread spawns a 'creation' thread to initialize gdiplus and draw
|
|
// something. When it's done and terminated, the main thread attempts to draw
|
|
// something on the screen before shutting down gdiplus. By the time the
|
|
// main thread gets to draw something, the DesktopDc has been cleaned up and
|
|
// we ASSERT in gdiplus.
|
|
//
|
|
// Created: 02/03/2001 [asecchia]
|
|
//
|
|
|
|
#include "precomp.hpp"
|
|
|
|
using namespace Gdiplus;
|
|
|
|
GdiplusStartupInput sti;
|
|
ULONG_PTR token;
|
|
bool gdiplusInitialized = false;
|
|
DWORD threadId;
|
|
|
|
|
|
// This is a CriticalSection Proxy designed to
|
|
// automatically acquire the critical section
|
|
// when the instance is created and release
|
|
// it when it goes out of scope.
|
|
|
|
class ThreadMutex
|
|
{
|
|
public:
|
|
|
|
static VOID InitializeCriticalSection()
|
|
{
|
|
::InitializeCriticalSection(&critSec);
|
|
}
|
|
|
|
static VOID DeleteCriticalSection()
|
|
{
|
|
::DeleteCriticalSection(&critSec);
|
|
}
|
|
|
|
ThreadMutex()
|
|
{
|
|
EnterCriticalSection(&critSec);
|
|
}
|
|
|
|
~ThreadMutex()
|
|
{
|
|
LeaveCriticalSection(&critSec);
|
|
}
|
|
|
|
private:
|
|
static CRITICAL_SECTION critSec;
|
|
};
|
|
|
|
CRITICAL_SECTION ThreadMutex::critSec;
|
|
|
|
// This is the main routine for the creation thread.
|
|
// GDI+ will be initialized on this thread and we'll draw a red rectangle
|
|
// on the screen.
|
|
// It's protected under the thread mutex help ensure this thread is done
|
|
// before the main thread continues.
|
|
// This is not normally a useful requirement, but for the purposes of this
|
|
// test, it's important.
|
|
|
|
DWORD WINAPI ThreadProc(VOID*)
|
|
{
|
|
ThreadMutex tm;
|
|
|
|
gdiplusInitialized = (Ok == GdiplusStartup(&token, &sti, NULL));
|
|
|
|
if(gdiplusInitialized)
|
|
{
|
|
HDC hdc = GetDC(NULL);
|
|
|
|
// Draw a red rectangle.
|
|
|
|
Graphics g(hdc);
|
|
SolidBrush brush(Color(0x3fff0000));
|
|
g.FillRectangle(&brush, 300, 300, 400, 200);
|
|
|
|
ReleaseDC(NULL, hdc);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Main thread of execution.
|
|
|
|
void __cdecl main( void )
|
|
{
|
|
ThreadMutex::InitializeCriticalSection();
|
|
|
|
// Make the creation thread.
|
|
|
|
CreateThread(
|
|
NULL, // LPSECURITY_ATTRIBUTES
|
|
0, // same stack size
|
|
&ThreadProc,
|
|
0, // parameter to thread
|
|
0, // creation flags
|
|
&threadId
|
|
);
|
|
|
|
|
|
// wait for the creation thread to initialize gdiplus.
|
|
// This ensures the creation thread happens first and ensures the
|
|
// correct ordering of acquiring the ThreadMutex.
|
|
|
|
do { } while(!gdiplusInitialized);
|
|
|
|
{
|
|
// block till the ThreadMutex becomes available.
|
|
// This ensures that the creation thread is done before we get started.
|
|
|
|
ThreadMutex tm;
|
|
|
|
// The thread mutex will ensure that we don't start till the thread
|
|
// proc for the creation thread is done. However we want to wait till
|
|
// NTUSER is done cleaning up our thread specific resources during
|
|
// thread terminationi and that's not protected by the ThreadMutex.
|
|
// Wait 5 seconds here to ensure that thread termination has enough
|
|
// time to finish.
|
|
|
|
Sleep(500);
|
|
|
|
// If initialization of gdiplus was successful, draw a blue rectangle.
|
|
|
|
if(gdiplusInitialized)
|
|
{
|
|
HDC hdc = GetDC(NULL);
|
|
|
|
// Draw a blue rectangle.
|
|
|
|
Graphics g(hdc);
|
|
SolidBrush brush(Color(0x3f0000ff));
|
|
g.FillRectangle(&brush, 100, 100, 400, 200);
|
|
|
|
ReleaseDC(NULL, hdc);
|
|
}
|
|
}
|
|
|
|
// scope barrier so the objects above destruct before we call shutdown.
|
|
|
|
if(gdiplusInitialized)
|
|
{
|
|
GdiplusShutdown(token);
|
|
}
|
|
|
|
ThreadMutex::DeleteCriticalSection();
|
|
}
|
|
|
|
|