Support for nonstandard baud rate in SetCommState.
[wine] / dlls / ddraw / dsurface / user.c
1 /*      User-based primary surface driver
2  *
3  * Copyright 2000-2001 TransGaming Technologies Inc.
4  */
5
6 #include "config.h"
7
8 #include <assert.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "winerror.h"
13 #include "debugtools.h"
14 #include "ddraw_private.h"
15 #include "dsurface/main.h"
16 #include "dsurface/dib.h"
17 #include "dsurface/user.h"
18 #include "dsurface/wndproc.h"
19
20 DEFAULT_DEBUG_CHANNEL(ddraw);
21
22 /* if you use OWN_WINDOW, don't use SYNC_UPDATE, or you may get trouble */
23 /* #define SYNC_UPDATE */
24 #define OWN_WINDOW
25
26 #ifdef OWN_WINDOW
27 static void User_create_own_window(IDirectDrawSurfaceImpl* This);
28 static void User_destroy_own_window(IDirectDrawSurfaceImpl* This);
29 #endif
30 #ifndef SYNC_UPDATE
31 static DWORD CALLBACK User_update_thread(LPVOID);
32 #endif
33 static void User_copy_to_screen(IDirectDrawSurfaceImpl* This, LPCRECT rc);
34 static void User_copy_from_screen(IDirectDrawSurfaceImpl* This, LPCRECT rc);
35
36 static HWND get_display_window(IDirectDrawSurfaceImpl* This, LPPOINT pt);
37
38 static ICOM_VTABLE(IDirectDrawSurface7) User_IDirectDrawSurface7_VTable;
39
40 HRESULT
41 User_DirectDrawSurface_Construct(IDirectDrawSurfaceImpl* This,
42                                  IDirectDrawImpl* pDD,
43                                  const DDSURFACEDESC2* pDDSD)
44 {
45     USER_PRIV_VAR(priv, This);
46     HRESULT hr;
47
48     TRACE("(%p,%p,%p)\n",This,pDD,pDDSD);
49     hr = DIB_DirectDrawSurface_Construct(This, pDD, pDDSD);
50     if (FAILED(hr)) return hr;
51
52     ICOM_INIT_INTERFACE(This, IDirectDrawSurface7,
53                         User_IDirectDrawSurface7_VTable);
54
55     This->final_release = User_DirectDrawSurface_final_release;
56     This->duplicate_surface = User_DirectDrawSurface_duplicate_surface;
57
58     This->lock_update   = User_DirectDrawSurface_lock_update;
59     This->unlock_update = User_DirectDrawSurface_unlock_update;
60
61     This->flip_data   = User_DirectDrawSurface_flip_data;
62     This->flip_update = User_DirectDrawSurface_flip_update;
63
64     This->get_dc     = User_DirectDrawSurface_get_dc;
65     This->release_dc = User_DirectDrawSurface_release_dc;
66
67     This->set_palette    = User_DirectDrawSurface_set_palette;
68     This->update_palette = User_DirectDrawSurface_update_palette;
69
70     This->get_gamma_ramp = User_DirectDrawSurface_get_gamma_ramp;
71     This->set_gamma_ramp = User_DirectDrawSurface_set_gamma_ramp;
72
73     This->get_display_window = User_DirectDrawSurface_get_display_window;
74
75     if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
76     {
77 #ifdef OWN_WINDOW
78         DirectDrawSurface_RegisterClass();
79 #endif
80 #ifndef SYNC_UPDATE
81         priv->user.update_event = CreateEventA(NULL, FALSE, FALSE, NULL);
82         priv->user.update_thread = CreateThread(NULL, 0, User_update_thread, This, 0, NULL);
83 #ifdef OWN_WINDOW
84         if (This->ddraw_owner->cooperative_level & DDSCL_FULLSCREEN) {
85             /* wait for window creation (or update thread destruction) */
86             while (WaitForMultipleObjects(1, &priv->user.update_thread, FALSE, 10) == WAIT_TIMEOUT)
87                 if (This->more.lpDDRAWReserved) break;
88             if (!This->more.lpDDRAWReserved) {
89                 ERR("window creation failed\n");
90             }
91         }
92 #endif
93 #else
94 #ifdef OWN_WINDOW
95         User_create_own_window(This);
96 #endif
97 #endif
98         if (!This->more.lpDDRAWReserved)
99             This->more.lpDDRAWReserved = (LPVOID)pDD->window;
100     }
101
102     return DIB_DirectDrawSurface_alloc_dc(This, &priv->user.cached_dc);
103 }
104
105 HRESULT
106 User_DirectDrawSurface_Create(IDirectDrawImpl *pDD,
107                               const DDSURFACEDESC2 *pDDSD,
108                               LPDIRECTDRAWSURFACE7 *ppSurf,
109                               IUnknown *pUnkOuter)
110 {
111     IDirectDrawSurfaceImpl* This;
112     HRESULT hr;
113     assert(pUnkOuter == NULL);
114
115     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
116                      sizeof(*This) + sizeof(User_DirectDrawSurfaceImpl));
117     if (This == NULL) return E_OUTOFMEMORY;
118
119     This->private = (User_DirectDrawSurfaceImpl*)(This+1);
120
121     hr = User_DirectDrawSurface_Construct(This, pDD, pDDSD);
122     if (FAILED(hr))
123         HeapFree(GetProcessHeap(), 0, This);
124     else
125         *ppSurf = ICOM_INTERFACE(This, IDirectDrawSurface7);
126
127     return hr;
128 }
129
130 void User_DirectDrawSurface_final_release(IDirectDrawSurfaceImpl* This)
131 {
132     USER_PRIV_VAR(priv, This);
133
134     if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
135     {
136 #ifndef SYNC_UPDATE
137         HANDLE event = priv->user.update_event;
138         priv->user.update_event = 0;
139         SetEvent(event);
140         TRACE("waiting for update thread to terminate...\n");
141 #ifdef OWN_WINDOW
142         /* dispatch any waiting sendmessages */
143         {
144             MSG msg;
145             PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
146         }
147         /* to avoid deadlocks, allow SendMessages from update thread
148          * through while we wait for it */
149         while (MsgWaitForMultipleObjects(1, &priv->user.update_thread, FALSE,
150                                          INFINITE, QS_SENDMESSAGE) == WAIT_OBJECT_0+1)
151         {
152             MSG msg;
153             PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE);
154         }
155 #else
156         WaitForSingleObject(priv->user.update_thread,INFINITE);
157 #endif
158         TRACE("update thread terminated\n");
159         CloseHandle(priv->user.update_thread);
160 #else
161 #ifdef OWN_WINDOW
162         User_destroy_own_window(This);
163 #endif
164 #endif
165         This->more.lpDDRAWReserved = 0;
166 #ifdef OWN_WINDOW
167         DirectDrawSurface_UnregisterClass();
168 #endif
169     }
170     DIB_DirectDrawSurface_free_dc(This, priv->user.cached_dc);
171     DIB_DirectDrawSurface_final_release(This);
172 }
173
174 void User_DirectDrawSurface_lock_update(IDirectDrawSurfaceImpl* This,
175                                         LPCRECT pRect, DWORD dwFlags)
176 {
177     if (!(dwFlags & DDLOCK_WRITEONLY))
178         User_copy_from_screen(This, pRect);
179
180     if (pRect) {
181         This->lastlockrect = *pRect;
182     } else {
183         This->lastlockrect.left = This->lastlockrect.right = 0;
184     }
185 }
186
187 void User_DirectDrawSurface_unlock_update(IDirectDrawSurfaceImpl* This,
188                                           LPCRECT pRect)
189 {
190 #ifdef SYNC_UPDATE
191     User_copy_to_screen(This, pRect);
192 #else
193     USER_PRIV_VAR(priv, This);
194     SetEvent(priv->user.update_event);
195 #endif
196 }
197
198 void User_DirectDrawSurface_set_palette(IDirectDrawSurfaceImpl* This,
199                                         IDirectDrawPaletteImpl* pal) 
200 {
201     USER_PRIV_VAR(priv, This);
202
203     if (!pal) {
204         FIXME("selecting null palette\n");
205         /* I don't think selecting GDI object 0 will work, we should select
206          * the original palette, returned by the first SelectPalette */
207         SelectPalette(priv->user.cached_dc, 0, FALSE);
208         return;
209     }
210
211     SelectPalette(priv->user.cached_dc, pal->hpal, FALSE);
212
213     DIB_DirectDrawSurface_set_palette(This, pal);
214 }
215
216 void User_DirectDrawSurface_update_palette(IDirectDrawSurfaceImpl* This,
217                                            IDirectDrawPaletteImpl* pal,
218                                            DWORD dwStart, DWORD dwCount,
219                                            LPPALETTEENTRY palent)
220 {
221     USER_PRIV_VAR(priv, This);
222
223     DIB_DirectDrawSurface_update_palette(This, pal, dwStart, dwCount, palent);
224     /* FIXME: realize palette on display window */
225
226 #ifndef SYNC_UPDATE
227     /* with async updates, it's probably cool to force an update */
228     SetEvent(priv->user.update_event);
229 #endif
230 }
231
232 HRESULT User_DirectDrawSurface_duplicate_surface(IDirectDrawSurfaceImpl* This,
233                                                  LPDIRECTDRAWSURFACE7* ppDup)
234 {
235     return User_DirectDrawSurface_Create(This->ddraw_owner,
236                                          &This->surface_desc, ppDup, NULL);
237 }
238
239 BOOL User_DirectDrawSurface_flip_data(IDirectDrawSurfaceImpl* front,
240                                       IDirectDrawSurfaceImpl* back,
241                                       DWORD dwFlags)
242 {
243     USER_PRIV_VAR(front_priv, front);
244     USER_PRIV_VAR(back_priv, back);
245
246     {
247         HDC tmp;
248         tmp = front_priv->user.cached_dc;
249         front_priv->user.cached_dc = back_priv->user.cached_dc;
250         back_priv->user.cached_dc = tmp;
251     }
252
253     return DIB_DirectDrawSurface_flip_data(front, back, dwFlags);
254 }
255
256 void User_DirectDrawSurface_flip_update(IDirectDrawSurfaceImpl* This, DWORD dwFlags)
257 {
258 #ifdef SYNC_UPDATE
259     This->lastlockrect.left = This->lastlockrect.right = 0;
260     assert(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE);
261     User_copy_to_screen(This,NULL);
262 #else
263     USER_PRIV_VAR(priv, This);
264     This->lastlockrect.left = This->lastlockrect.right = 0;
265     assert(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE);
266     SetEvent(priv->user.update_event);
267 #endif
268 }
269
270 HRESULT User_DirectDrawSurface_get_dc(IDirectDrawSurfaceImpl* This, HDC* phDC)
271 {
272     USER_PRIV_VAR(priv, This);
273
274     *phDC = priv->user.cached_dc;
275     return S_OK;
276 }
277
278 HRESULT User_DirectDrawSurface_release_dc(IDirectDrawSurfaceImpl* This,
279                                           HDC hDC)
280 {
281     return S_OK;
282 }
283
284 HRESULT User_DirectDrawSurface_get_gamma_ramp(IDirectDrawSurfaceImpl* This,
285                                               DWORD dwFlags,
286                                               LPDDGAMMARAMP lpGammaRamp)
287 {
288     if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
289     {
290         POINT offset;
291         HWND hDisplayWnd;
292         HDC hDisplayDC;
293         HRESULT hr;
294         hDisplayWnd = get_display_window(This, &offset);
295         hDisplayDC = GetDCEx(hDisplayWnd, 0, DCX_CLIPSIBLINGS|DCX_CACHE);
296         hr = GetDeviceGammaRamp(hDisplayDC, lpGammaRamp) ? DD_OK : DDERR_UNSUPPORTED;
297         ReleaseDC(hDisplayWnd, hDisplayDC);
298         return hr;
299     }
300     return Main_DirectDrawSurface_get_gamma_ramp(This, dwFlags, lpGammaRamp);
301 }
302
303 HRESULT User_DirectDrawSurface_set_gamma_ramp(IDirectDrawSurfaceImpl* This,
304                                               DWORD dwFlags,
305                                               LPDDGAMMARAMP lpGammaRamp)
306 {
307     if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
308     {
309         POINT offset;
310         HWND hDisplayWnd;
311         HDC hDisplayDC;
312         HRESULT hr;
313         hDisplayWnd = get_display_window(This, &offset);
314         hDisplayDC = GetDCEx(hDisplayWnd, 0, DCX_CLIPSIBLINGS|DCX_CACHE);
315         hr = SetDeviceGammaRamp(hDisplayDC, lpGammaRamp) ? DD_OK : DDERR_UNSUPPORTED;
316         ReleaseDC(hDisplayWnd, hDisplayDC);
317         return hr;
318     }
319     return Main_DirectDrawSurface_set_gamma_ramp(This, dwFlags, lpGammaRamp);
320 }
321
322 /* Returns the window that hosts the display.
323  * *pt is set to the upper left position of the window relative to the
324  * upper left corner of the surface. */
325 static HWND get_display_window(IDirectDrawSurfaceImpl* This, LPPOINT pt)
326 {
327     memset(pt, 0, sizeof(*pt));
328
329     if (This->ddraw_owner->cooperative_level & DDSCL_FULLSCREEN)
330     {
331 #ifdef OWN_WINDOW
332         USER_PRIV_VAR(priv, This);
333 #if 1
334         SetWindowPos(priv->user.window, HWND_TOP, 0, 0, 0, 0,
335                      SWP_DEFERERASE|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|
336                      SWP_NOREDRAW|SWP_NOSENDCHANGING|SWP_NOSIZE);
337 #endif
338         return priv->user.window;
339 #else
340         return This->ddraw_owner->window;
341 #endif
342     }
343     else
344     {
345         if (This->clipper != NULL)
346         {
347             /* looks silly, but since we don't have the clipper locked */
348             HWND hWnd = This->clipper->hWnd;
349
350             if (hWnd != 0)
351             {
352                 ClientToScreen(hWnd, pt);
353                 return hWnd;
354             }
355             else
356             {
357                 static BOOL warn = 0;
358                 if (!warn++) FIXME("clipper clip lists not supported\n");
359
360                 return GetDesktopWindow();
361             }
362         }
363         else
364         {
365             static BOOL warn = 0;
366             if (!warn++) WARN("hosting on root\n");
367
368             return GetDesktopWindow();
369         }
370     }
371 }
372
373 HWND User_DirectDrawSurface_get_display_window(IDirectDrawSurfaceImpl* This)
374 {
375     POINT offset;
376     return get_display_window(This, &offset);
377 }
378
379 #ifdef OWN_WINDOW
380 static void User_create_own_window(IDirectDrawSurfaceImpl* This)
381 {
382     USER_PRIV_VAR(priv, This);
383
384     if (This->ddraw_owner->cooperative_level & DDSCL_FULLSCREEN)
385     {
386         priv->user.window = CreateWindowExA(WS_EX_TOPMOST |
387                                             WS_EX_LAYERED |
388                                             WS_EX_TRANSPARENT,
389                                             "WINE_DDRAW", "DirectDraw",
390                                             WS_POPUP,
391                                             0, 0,
392                                             This->surface_desc.dwWidth,
393                                             This->surface_desc.dwHeight,
394                                             GetDesktopWindow(),
395                                             0, 0, This);
396         This->more.lpDDRAWReserved = (LPVOID)priv->user.window;
397         SetWindowPos(priv->user.window, HWND_TOP, 0, 0, 0, 0,
398                      SWP_DEFERERASE|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|
399                      SWP_NOREDRAW|SWP_NOSENDCHANGING|SWP_NOSIZE|SWP_SHOWWINDOW);
400         UpdateWindow(priv->user.window);
401     }
402 }
403
404 static void User_destroy_own_window(IDirectDrawSurfaceImpl* This)
405 {
406     USER_PRIV_VAR(priv, This);
407
408     if (priv->user.window)
409     {
410         SetWindowPos(priv->user.window, 0, 0, 0, 0, 0,
411                      SWP_DEFERERASE|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOZORDER|
412                      SWP_NOREDRAW|SWP_NOSENDCHANGING|SWP_NOSIZE|SWP_HIDEWINDOW);
413         This->more.lpDDRAWReserved = NULL;
414         DestroyWindow(priv->user.window);
415         priv->user.window = 0;
416     }
417 }
418 #endif
419
420 #ifndef SYNC_UPDATE
421 static DWORD CALLBACK User_update_thread(LPVOID arg)
422 {
423     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)arg;
424     USER_PRIV_VAR(priv, This);
425     volatile DWORD *pActive = (volatile DWORD *)&priv->user.update_event;
426     HANDLE event = *pActive;
427
428 #ifdef OWN_WINDOW
429     User_create_own_window(This);
430 #endif
431
432     /* the point of this is that many games lock the primary surface
433      * multiple times per frame; this thread will then simply copy as
434      * often as it can without keeping the main thread waiting for
435      * each unlock, thus keeping the frame rate high */
436     do {
437 #ifdef OWN_WINDOW
438         DWORD ret = MsgWaitForMultipleObjects(1, &event, FALSE, INFINITE, QS_ALLINPUT);
439         MSG msg;
440
441         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
442         {
443             switch (msg.message) {
444             case WM_PAINT:
445                 DispatchMessageA(&msg);
446                 break;
447             default:
448                 /* since we risk getting keyboard messages posted to us,
449                  * repost posted messages to cooperative window */
450                 PostMessageA(This->ddraw_owner->window, msg.message, msg.wParam, msg.lParam);
451             }
452         }
453 #else
454         DWORD ret = WaitForSingleObject(event, INFINITE);
455 #endif
456         if (ret == WAIT_OBJECT_0)
457         {
458             if (*pActive)
459                 User_copy_to_screen(This, NULL);
460             else
461                 break;
462         }
463         else if (ret != WAIT_OBJECT_0+1) break;
464     } while (TRUE);
465
466 #ifdef OWN_WINDOW
467     User_destroy_own_window(This);
468 #endif
469
470     return 0;
471 }
472 #endif
473
474 static void User_copy_to_screen(IDirectDrawSurfaceImpl* This, LPCRECT rc)
475 {
476     if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
477     {
478         POINT offset;
479         HWND hDisplayWnd;
480         HDC hDisplayDC;
481         HDC hSurfaceDC;
482         RECT drawrect;
483
484         if (FAILED(This->get_dc(This, &hSurfaceDC)))
485             return;
486
487         hDisplayWnd = get_display_window(This, &offset);
488         hDisplayDC = GetDCEx(hDisplayWnd, 0, DCX_CLIPSIBLINGS|DCX_CACHE);
489 #if 0
490         /* FIXME: this doesn't work... if users really want to run
491          * X in 8bpp, then we need to call directly into display.drv
492          * (or Wine's equivalent), and force a private colormap
493          * without default entries. */
494         if (This->palette) {
495             SelectPalette(hDisplayDC, This->palette->hpal, FALSE);
496             RealizePalette(hDisplayDC); /* sends messages => deadlocks */
497         }
498 #endif
499         drawrect.left   = 0;
500         drawrect.right  = This->surface_desc.dwWidth;
501         drawrect.top    = 0;
502         drawrect.bottom = This->surface_desc.dwHeight;
503
504         if (This->clipper) {
505             RECT xrc;
506             HWND hwnd = This->clipper->hWnd;
507             if (hwnd && GetWindowRect(hwnd,&xrc)) {
508                 /* Do not forget to honor the offset within the clip window. */
509                 /* translate the surface to 0.0 of the clip window */
510                 OffsetRect(&drawrect,offset.x,offset.y);
511                 IntersectRect(&drawrect,&drawrect,&xrc);
512                 /* translate it back to its original position */
513                 OffsetRect(&drawrect,-offset.x,-offset.y);
514             }
515         }
516         if (rc)
517             IntersectRect(&drawrect,&drawrect,rc);
518         else {
519             /* Only use this if the caller did not pass a rectangle, since
520              * due to double locking this could be the wrong one ... */
521             if (This->lastlockrect.left != This->lastlockrect.right)
522                 IntersectRect(&drawrect,&drawrect,&This->lastlockrect);
523         }
524         BitBlt(hDisplayDC,
525                 drawrect.left+offset.x, drawrect.top+offset.y,
526                 drawrect.right-drawrect.left, drawrect.bottom-drawrect.top,
527                 hSurfaceDC,
528                 drawrect.left, drawrect.top,
529                 SRCCOPY
530         );
531         ReleaseDC(hDisplayWnd, hDisplayDC);
532     }
533 }
534
535 static void User_copy_from_screen(IDirectDrawSurfaceImpl* This, LPCRECT rc)
536 {
537     if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
538     {
539         POINT offset;
540         HWND hDisplayWnd = get_display_window(This, &offset);
541         HDC hDisplayDC = GetDC(hDisplayWnd);
542         RECT drawrect;
543
544         drawrect.left   = 0;
545         drawrect.right  = This->surface_desc.dwWidth;
546         drawrect.top    = 0;
547         drawrect.bottom = This->surface_desc.dwHeight;
548         if (rc)
549             IntersectRect(&drawrect,&drawrect,rc);
550
551         BitBlt(This->hDC,
552             drawrect.left, drawrect.top,
553             drawrect.right-drawrect.left, drawrect.bottom-drawrect.top,
554             hDisplayDC,
555             drawrect.left+offset.x, drawrect.top+offset.y,
556             SRCCOPY
557         );
558         ReleaseDC(hDisplayWnd, hDisplayDC);
559     }
560 }
561
562 static ICOM_VTABLE(IDirectDrawSurface7) User_IDirectDrawSurface7_VTable =
563 {
564     Main_DirectDrawSurface_QueryInterface,
565     Main_DirectDrawSurface_AddRef,
566     Main_DirectDrawSurface_Release,
567     Main_DirectDrawSurface_AddAttachedSurface,
568     Main_DirectDrawSurface_AddOverlayDirtyRect,
569     DIB_DirectDrawSurface_Blt,
570     Main_DirectDrawSurface_BltBatch,
571     DIB_DirectDrawSurface_BltFast,
572     Main_DirectDrawSurface_DeleteAttachedSurface,
573     Main_DirectDrawSurface_EnumAttachedSurfaces,
574     Main_DirectDrawSurface_EnumOverlayZOrders,
575     Main_DirectDrawSurface_Flip,
576     Main_DirectDrawSurface_GetAttachedSurface,
577     Main_DirectDrawSurface_GetBltStatus,
578     Main_DirectDrawSurface_GetCaps,
579     Main_DirectDrawSurface_GetClipper,
580     Main_DirectDrawSurface_GetColorKey,
581     Main_DirectDrawSurface_GetDC,
582     Main_DirectDrawSurface_GetFlipStatus,
583     Main_DirectDrawSurface_GetOverlayPosition,
584     Main_DirectDrawSurface_GetPalette,
585     Main_DirectDrawSurface_GetPixelFormat,
586     Main_DirectDrawSurface_GetSurfaceDesc,
587     Main_DirectDrawSurface_Initialize,
588     Main_DirectDrawSurface_IsLost,
589     Main_DirectDrawSurface_Lock,
590     Main_DirectDrawSurface_ReleaseDC,
591     DIB_DirectDrawSurface_Restore,
592     Main_DirectDrawSurface_SetClipper,
593     Main_DirectDrawSurface_SetColorKey,
594     Main_DirectDrawSurface_SetOverlayPosition,
595     Main_DirectDrawSurface_SetPalette,
596     Main_DirectDrawSurface_Unlock,
597     Main_DirectDrawSurface_UpdateOverlay,
598     Main_DirectDrawSurface_UpdateOverlayDisplay,
599     Main_DirectDrawSurface_UpdateOverlayZOrder,
600     Main_DirectDrawSurface_GetDDInterface,
601     Main_DirectDrawSurface_PageLock,
602     Main_DirectDrawSurface_PageUnlock,
603     DIB_DirectDrawSurface_SetSurfaceDesc,
604     Main_DirectDrawSurface_SetPrivateData,
605     Main_DirectDrawSurface_GetPrivateData,
606     Main_DirectDrawSurface_FreePrivateData,
607     Main_DirectDrawSurface_GetUniquenessValue,
608     Main_DirectDrawSurface_ChangeUniquenessValue,
609     Main_DirectDrawSurface_SetPriority,
610     Main_DirectDrawSurface_GetPriority,
611     Main_DirectDrawSurface_SetLOD,
612     Main_DirectDrawSurface_GetLOD
613 };