Leaked source code of windows server 2003
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

  1. // This is a dual threaded test app designed to expose a weakness in
  2. // GDI+. The CreateDCA("DISPLAY", NULL, NULL, NULL) used to create our
  3. // Globals::DesktopDc during GdiplusStartup has thread affinity (as opposed
  4. // to other inputs to CreateDCA) and therefore when the creation thread
  5. // is terminated, the global DC goes away. This will cause random drawing
  6. // failure in gdiplus.
  7. //
  8. // The main thread spawns a 'creation' thread to initialize gdiplus and draw
  9. // something. When it's done and terminated, the main thread attempts to draw
  10. // something on the screen before shutting down gdiplus. By the time the
  11. // main thread gets to draw something, the DesktopDc has been cleaned up and
  12. // we ASSERT in gdiplus.
  13. //
  14. // Created: 02/03/2001 [asecchia]
  15. //
  16. #include "precomp.hpp"
  17. using namespace Gdiplus;
  18. GdiplusStartupInput sti;
  19. ULONG_PTR token;
  20. bool gdiplusInitialized = false;
  21. DWORD threadId;
  22. // This is a CriticalSection Proxy designed to
  23. // automatically acquire the critical section
  24. // when the instance is created and release
  25. // it when it goes out of scope.
  26. class ThreadMutex
  27. {
  28. public:
  29. static VOID InitializeCriticalSection()
  30. {
  31. ::InitializeCriticalSection(&critSec);
  32. }
  33. static VOID DeleteCriticalSection()
  34. {
  35. ::DeleteCriticalSection(&critSec);
  36. }
  37. ThreadMutex()
  38. {
  39. EnterCriticalSection(&critSec);
  40. }
  41. ~ThreadMutex()
  42. {
  43. LeaveCriticalSection(&critSec);
  44. }
  45. private:
  46. static CRITICAL_SECTION critSec;
  47. };
  48. CRITICAL_SECTION ThreadMutex::critSec;
  49. // This is the main routine for the creation thread.
  50. // GDI+ will be initialized on this thread and we'll draw a red rectangle
  51. // on the screen.
  52. // It's protected under the thread mutex help ensure this thread is done
  53. // before the main thread continues.
  54. // This is not normally a useful requirement, but for the purposes of this
  55. // test, it's important.
  56. DWORD WINAPI ThreadProc(VOID*)
  57. {
  58. ThreadMutex tm;
  59. gdiplusInitialized = (Ok == GdiplusStartup(&token, &sti, NULL));
  60. if(gdiplusInitialized)
  61. {
  62. HDC hdc = GetDC(NULL);
  63. // Draw a red rectangle.
  64. Graphics g(hdc);
  65. SolidBrush brush(Color(0x3fff0000));
  66. g.FillRectangle(&brush, 300, 300, 400, 200);
  67. ReleaseDC(NULL, hdc);
  68. }
  69. return 1;
  70. }
  71. // Main thread of execution.
  72. void __cdecl main( void )
  73. {
  74. ThreadMutex::InitializeCriticalSection();
  75. // Make the creation thread.
  76. CreateThread(
  77. NULL, // LPSECURITY_ATTRIBUTES
  78. 0, // same stack size
  79. &ThreadProc,
  80. 0, // parameter to thread
  81. 0, // creation flags
  82. &threadId
  83. );
  84. // wait for the creation thread to initialize gdiplus.
  85. // This ensures the creation thread happens first and ensures the
  86. // correct ordering of acquiring the ThreadMutex.
  87. do { } while(!gdiplusInitialized);
  88. {
  89. // block till the ThreadMutex becomes available.
  90. // This ensures that the creation thread is done before we get started.
  91. ThreadMutex tm;
  92. // The thread mutex will ensure that we don't start till the thread
  93. // proc for the creation thread is done. However we want to wait till
  94. // NTUSER is done cleaning up our thread specific resources during
  95. // thread terminationi and that's not protected by the ThreadMutex.
  96. // Wait 5 seconds here to ensure that thread termination has enough
  97. // time to finish.
  98. Sleep(500);
  99. // If initialization of gdiplus was successful, draw a blue rectangle.
  100. if(gdiplusInitialized)
  101. {
  102. HDC hdc = GetDC(NULL);
  103. // Draw a blue rectangle.
  104. Graphics g(hdc);
  105. SolidBrush brush(Color(0x3f0000ff));
  106. g.FillRectangle(&brush, 100, 100, 400, 200);
  107. ReleaseDC(NULL, hdc);
  108. }
  109. }
  110. // scope barrier so the objects above destruct before we call shutdown.
  111. if(gdiplusInitialized)
  112. {
  113. GdiplusShutdown(token);
  114. }
  115. ThreadMutex::DeleteCriticalSection();
  116. }