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