- Fix text placement.
[wine] / dlls / user / misc.c
1 /*
2  * Misc USER functions
3  *
4  * Copyright 1995 Thomas Sandford
5  * Copyright 1997 Marcus Meissner
6  * Copyright 1998 Turchanov Sergey
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "wine/windef16.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winnls.h"
31
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(win);
36
37 /* USER signal proc flags and codes */
38 /* See UserSignalProc for comments */
39 #define USIG_FLAGS_WIN32          0x0001
40 #define USIG_FLAGS_GUI            0x0002
41 #define USIG_FLAGS_FEEDBACK       0x0004
42 #define USIG_FLAGS_FAULT          0x0008
43
44 #define USIG_DLL_UNLOAD_WIN16     0x0001
45 #define USIG_DLL_UNLOAD_WIN32     0x0002
46 #define USIG_FAULT_DIALOG_PUSH    0x0003
47 #define USIG_FAULT_DIALOG_POP     0x0004
48 #define USIG_DLL_UNLOAD_ORPHANS   0x0005
49 #define USIG_THREAD_INIT          0x0010
50 #define USIG_THREAD_EXIT          0x0020
51 #define USIG_PROCESS_CREATE       0x0100
52 #define USIG_PROCESS_INIT         0x0200
53 #define USIG_PROCESS_EXIT         0x0300
54 #define USIG_PROCESS_DESTROY      0x0400
55 #define USIG_PROCESS_RUNNING      0x0500
56 #define USIG_PROCESS_LOADED       0x0600
57
58 #define xPRIMARY_MONITOR ((HMONITOR)0x12340042)
59
60 /***********************************************************************
61  *              SignalProc32 (USER.391)
62  *              UserSignalProc (USER32.@)
63  *
64  * The exact meaning of the USER signals is undocumented, but this
65  * should cover the basic idea:
66  *
67  * USIG_DLL_UNLOAD_WIN16
68  *     This is sent when a 16-bit module is unloaded.
69  *
70  * USIG_DLL_UNLOAD_WIN32
71  *     This is sent when a 32-bit module is unloaded.
72  *
73  * USIG_DLL_UNLOAD_ORPHANS
74  *     This is sent after the last Win3.1 module is unloaded,
75  *     to allow removal of orphaned menus.
76  *
77  * USIG_FAULT_DIALOG_PUSH
78  * USIG_FAULT_DIALOG_POP
79  *     These are called to allow USER to prepare for displaying a
80  *     fault dialog, even though the fault might have happened while
81  *     inside a USER critical section.
82  *
83  * USIG_THREAD_INIT
84  *     This is called from the context of a new thread, as soon as it
85  *     has started to run.
86  *
87  * USIG_THREAD_EXIT
88  *     This is called, still in its context, just before a thread is
89  *     about to terminate.
90  *
91  * USIG_PROCESS_CREATE
92  *     This is called, in the parent process context, after a new process
93  *     has been created.
94  *
95  * USIG_PROCESS_INIT
96  *     This is called in the new process context, just after the main thread
97  *     has started execution (after the main thread's USIG_THREAD_INIT has
98  *     been sent).
99  *
100  * USIG_PROCESS_LOADED
101  *     This is called after the executable file has been loaded into the
102  *     new process context.
103  *
104  * USIG_PROCESS_RUNNING
105  *     This is called immediately before the main entry point is called.
106  *
107  * USIG_PROCESS_EXIT
108  *     This is called in the context of a process that is about to
109  *     terminate (but before the last thread's USIG_THREAD_EXIT has
110  *     been sent).
111  *
112  * USIG_PROCESS_DESTROY
113  *     This is called after a process has terminated.
114  *
115  *
116  * The meaning of the dwFlags bits is as follows:
117  *
118  * USIG_FLAGS_WIN32
119  *     Current process is 32-bit.
120  *
121  * USIG_FLAGS_GUI
122  *     Current process is a (Win32) GUI process.
123  *
124  * USIG_FLAGS_FEEDBACK
125  *     Current process needs 'feedback' (determined from the STARTUPINFO
126  *     flags STARTF_FORCEONFEEDBACK / STARTF_FORCEOFFFEEDBACK).
127  *
128  * USIG_FLAGS_FAULT
129  *     The signal is being sent due to a fault.
130  */
131 WORD WINAPI UserSignalProc( UINT uCode, DWORD dwThreadOrProcessID,
132                             DWORD dwFlags, HMODULE16 hModule )
133 {
134     FIXME("(%04x, %08lx, %04lx, %04x)\n",
135           uCode, dwThreadOrProcessID, dwFlags, hModule );
136     /* FIXME: Should chain to GdiSignalProc now. */
137     return 0;
138 }
139
140
141 /**********************************************************************
142  * SetLastErrorEx [USER32.@]
143  *
144  * Sets the last-error code.
145  *
146  * RETURNS
147  *    None.
148  */
149 void WINAPI SetLastErrorEx(
150     DWORD error, /* [in] Per-thread error code */
151     DWORD type)  /* [in] Error type */
152 {
153     TRACE("(0x%08lx, 0x%08lx)\n", error,type);
154     switch(type) {
155         case 0:
156             break;
157         case SLE_ERROR:
158         case SLE_MINORERROR:
159         case SLE_WARNING:
160             /* Fall through for now */
161         default:
162             FIXME("(error=%08lx, type=%08lx): Unhandled type\n", error,type);
163             break;
164     }
165     SetLastError( error );
166 }
167
168 /******************************************************************************
169  * GetAltTabInfoA [USER32.@]
170  */
171 BOOL WINAPI GetAltTabInfoA(HWND hwnd, int iItem, PALTTABINFO pati, LPSTR pszItemText, UINT cchItemText)
172 {
173     FIXME("(%p, 0x%08x, %p, %p, 0x%08x)\n", hwnd, iItem, pati, pszItemText, cchItemText);
174     return FALSE;
175 }
176
177 /******************************************************************************
178  * GetAltTabInfoW [USER32.@]
179  */
180 BOOL WINAPI GetAltTabInfoW(HWND hwnd, int iItem, PALTTABINFO pati, LPWSTR pszItemText, UINT cchItemText)
181 {
182     FIXME("(%p, 0x%08x, %p, %p, 0x%08x)\n", hwnd, iItem, pati, pszItemText, cchItemText);
183     return FALSE;
184 }
185
186 /******************************************************************************
187  * SetDebugErrorLevel [USER32.@]
188  * Sets the minimum error level for generating debugging events
189  *
190  * PARAMS
191  *    dwLevel [I] Debugging error level
192  */
193 VOID WINAPI SetDebugErrorLevel( DWORD dwLevel )
194 {
195     FIXME("(%ld): stub\n", dwLevel);
196 }
197
198
199 /******************************************************************************
200  *                    GetProcessDefaultLayout [USER32.@]
201  *
202  * Gets the default layout for parentless windows.
203  * Right now, just returns 0 (left-to-right).
204  *
205  * RETURNS
206  *    Success: Nonzero
207  *    Failure: Zero
208  *
209  * BUGS
210  *    No RTL
211  */
212 BOOL WINAPI GetProcessDefaultLayout( DWORD *pdwDefaultLayout )
213 {
214     if ( !pdwDefaultLayout ) {
215         SetLastError( ERROR_INVALID_PARAMETER );
216         return FALSE;
217      }
218     FIXME( "( %p ): No BiDi\n", pdwDefaultLayout );
219     *pdwDefaultLayout = 0;
220     return TRUE;
221 }
222
223
224 /******************************************************************************
225  *                    SetProcessDefaultLayout [USER32.@]
226  *
227  * Sets the default layout for parentless windows.
228  * Right now, only accepts 0 (left-to-right).
229  *
230  * RETURNS
231  *    Success: Nonzero
232  *    Failure: Zero
233  *
234  * BUGS
235  *    No RTL
236  */
237 BOOL WINAPI SetProcessDefaultLayout( DWORD dwDefaultLayout )
238 {
239     if ( dwDefaultLayout == 0 )
240         return TRUE;
241     FIXME( "( %08lx ): No BiDi\n", dwDefaultLayout );
242     SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
243     return FALSE;
244 }
245
246
247 /***********************************************************************
248  *              SetWindowStationUser (USER32.@)
249  */
250 DWORD WINAPI SetWindowStationUser(DWORD x1,DWORD x2)
251 {
252     FIXME("(0x%08lx,0x%08lx),stub!\n",x1,x2);
253     return 1;
254 }
255
256 /***********************************************************************
257  *              RegisterLogonProcess (USER32.@)
258  */
259 DWORD WINAPI RegisterLogonProcess(HANDLE hprocess,BOOL x)
260 {
261     FIXME("(%p,%d),stub!\n",hprocess,x);
262     return 1;
263 }
264
265 /***********************************************************************
266  *              SetLogonNotifyWindow (USER32.@)
267  */
268 DWORD WINAPI SetLogonNotifyWindow(HWINSTA hwinsta,HWND hwnd)
269 {
270     FIXME("(%p,%p),stub!\n",hwinsta,hwnd);
271     return 1;
272 }
273
274 /***********************************************************************
275  *              EnumDisplayDevicesA (USER32.@)
276  */
277 BOOL WINAPI EnumDisplayDevicesA( LPVOID unused, DWORD i, LPDISPLAY_DEVICEA lpDisplayDevice,
278                                  DWORD dwFlags )
279 {
280     if (i)
281         return FALSE;
282     FIXME("(%p,%ld,%p,0x%08lx), stub!\n",unused,i,lpDisplayDevice,dwFlags);
283     strcpy(lpDisplayDevice->DeviceName,"X11");
284     strcpy(lpDisplayDevice->DeviceString,"X 11 Windowing System");
285     lpDisplayDevice->StateFlags =
286         DISPLAY_DEVICE_ATTACHED_TO_DESKTOP |
287         DISPLAY_DEVICE_PRIMARY_DEVICE |
288         DISPLAY_DEVICE_VGA_COMPATIBLE;
289     return TRUE;
290 }
291
292 /***********************************************************************
293  *              EnumDisplayDevicesW (USER32.@)
294  */
295 BOOL WINAPI EnumDisplayDevicesW( LPVOID unused, DWORD i, LPDISPLAY_DEVICEW lpDisplayDevice,
296                                  DWORD dwFlags )
297 {
298     if (i)
299         return FALSE;
300     FIXME("(%p,%ld,%p,0x%08lx), stub!\n",unused,i,lpDisplayDevice,dwFlags);
301     MultiByteToWideChar( CP_ACP, 0, "X11", -1, lpDisplayDevice->DeviceName,
302                          sizeof(lpDisplayDevice->DeviceName)/sizeof(WCHAR) );
303     MultiByteToWideChar( CP_ACP, 0, "X11 Windowing System", -1, lpDisplayDevice->DeviceString,
304                          sizeof(lpDisplayDevice->DeviceString)/sizeof(WCHAR) );
305     lpDisplayDevice->StateFlags =
306         DISPLAY_DEVICE_ATTACHED_TO_DESKTOP |
307         DISPLAY_DEVICE_PRIMARY_DEVICE |
308         DISPLAY_DEVICE_VGA_COMPATIBLE;
309     return TRUE;
310 }
311
312 /***********************************************************************
313  *              MonitorFromPoint (USER32.@)
314  */
315 HMONITOR WINAPI MonitorFromPoint(POINT ptScreenCoords, DWORD dwFlags)
316 {
317     if ((dwFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) ||
318         ((ptScreenCoords.x >= 0) &&
319         (ptScreenCoords.x < GetSystemMetrics(SM_CXSCREEN)) &&
320         (ptScreenCoords.y >= 0) &&
321         (ptScreenCoords.y < GetSystemMetrics(SM_CYSCREEN))))
322     {
323         return xPRIMARY_MONITOR;
324     }
325     return NULL;
326 }
327
328 /***********************************************************************
329  *              MonitorFromRect (USER32.@)
330  */
331 HMONITOR WINAPI MonitorFromRect(LPRECT lprcScreenCoords, DWORD dwFlags)
332 {
333     if ((dwFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) ||
334         ((lprcScreenCoords->right > 0) &&
335         (lprcScreenCoords->bottom > 0) &&
336         (lprcScreenCoords->left < GetSystemMetrics(SM_CXSCREEN)) &&
337         (lprcScreenCoords->top < GetSystemMetrics(SM_CYSCREEN))))
338     {
339         return xPRIMARY_MONITOR;
340     }
341     return NULL;
342 }
343
344 /***********************************************************************
345  *              MonitorFromWindow (USER32.@)
346  */
347 HMONITOR WINAPI MonitorFromWindow(HWND hWnd, DWORD dwFlags)
348 {
349     WINDOWPLACEMENT wp;
350
351     if (dwFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST))
352         return xPRIMARY_MONITOR;
353
354     if (IsIconic(hWnd) ?
355             GetWindowPlacement(hWnd, &wp) :
356             GetWindowRect(hWnd, &wp.rcNormalPosition)) {
357
358         return MonitorFromRect(&wp.rcNormalPosition, dwFlags);
359     }
360
361     return NULL;
362 }
363
364 /***********************************************************************
365  *              GetMonitorInfoA (USER32.@)
366  */
367 BOOL WINAPI GetMonitorInfoA(HMONITOR hMonitor, LPMONITORINFO lpMonitorInfo)
368 {
369     RECT rcWork;
370
371     if ((hMonitor == xPRIMARY_MONITOR) &&
372         lpMonitorInfo &&
373         (lpMonitorInfo->cbSize >= sizeof(MONITORINFO)) &&
374         SystemParametersInfoA(SPI_GETWORKAREA, 0, &rcWork, 0))
375     {
376         SetRect( &lpMonitorInfo->rcMonitor, 0, 0,
377                  GetSystemMetrics(SM_CXSCREEN),
378                  GetSystemMetrics(SM_CYSCREEN) );
379         lpMonitorInfo->rcWork = rcWork;
380         lpMonitorInfo->dwFlags = MONITORINFOF_PRIMARY;
381
382         if (lpMonitorInfo->cbSize >= sizeof(MONITORINFOEXA))
383             strcpy(((MONITORINFOEXA*)lpMonitorInfo)->szDevice, "DISPLAY");
384
385         return TRUE;
386     }
387
388     return FALSE;
389 }
390
391 /***********************************************************************
392  *              GetMonitorInfoW (USER32.@)
393  */
394 BOOL WINAPI GetMonitorInfoW(HMONITOR hMonitor, LPMONITORINFO lpMonitorInfo)
395 {
396     static const WCHAR displayW[] = {'D','I','S','P','L','A','Y',0};
397     RECT rcWork;
398
399     if ((hMonitor == xPRIMARY_MONITOR) &&
400         lpMonitorInfo &&
401         (lpMonitorInfo->cbSize >= sizeof(MONITORINFO)) &&
402         SystemParametersInfoW(SPI_GETWORKAREA, 0, &rcWork, 0))
403     {
404         SetRect( &lpMonitorInfo->rcMonitor, 0, 0,
405                  GetSystemMetrics(SM_CXSCREEN),
406                  GetSystemMetrics(SM_CYSCREEN) );
407         lpMonitorInfo->rcWork = rcWork;
408         lpMonitorInfo->dwFlags = MONITORINFOF_PRIMARY;
409
410         if (lpMonitorInfo->cbSize >= sizeof(MONITORINFOEXW))
411             strcpyW(((MONITORINFOEXW*)lpMonitorInfo)->szDevice, displayW);
412
413         return TRUE;
414     }
415
416     return FALSE;
417 }
418
419 /***********************************************************************
420  *              EnumDisplayMonitors (USER32.@)
421  */
422 BOOL WINAPI EnumDisplayMonitors(
423         HDC             hdcOptionalForPainting,
424         LPRECT         lprcEnumMonitorsThatIntersect,
425         MONITORENUMPROC lpfnEnumProc,
426         LPARAM          dwData)
427 {
428     RECT rcLimit;
429     SetRect( &rcLimit, 0, 0, GetSystemMetrics(SM_CXSCREEN),
430              GetSystemMetrics(SM_CYSCREEN) );
431
432     if (!lpfnEnumProc)
433         return FALSE;
434
435     if (hdcOptionalForPainting)
436     {
437         RECT    rcClip;
438         POINT   ptOrg;
439
440         switch (GetClipBox(hdcOptionalForPainting, &rcClip))
441         {
442         default:
443             if (!GetDCOrgEx(hdcOptionalForPainting, &ptOrg))
444                 return FALSE;
445
446             OffsetRect(&rcLimit, -ptOrg.x, -ptOrg.y);
447             if (IntersectRect(&rcLimit, &rcLimit, &rcClip) &&
448                 (!lprcEnumMonitorsThatIntersect ||
449                      IntersectRect(&rcLimit, &rcLimit, lprcEnumMonitorsThatIntersect))) {
450
451                 break;
452             }
453             /* fall through */
454         case NULLREGION:
455              return TRUE;
456         case ERROR:
457              return FALSE;
458         }
459     } else {
460         if (    lprcEnumMonitorsThatIntersect &&
461                 !IntersectRect(&rcLimit, &rcLimit, lprcEnumMonitorsThatIntersect)) {
462
463             return TRUE;
464         }
465     }
466
467     return lpfnEnumProc(
468             xPRIMARY_MONITOR,
469             hdcOptionalForPainting,
470             &rcLimit,
471             dwData);
472 }
473
474 /***********************************************************************
475  *              RegisterSystemThread (USER32.@)
476  */
477 void WINAPI RegisterSystemThread(DWORD flags, DWORD reserved)
478 {
479     FIXME("(%08lx, %08lx)\n", flags, reserved);
480 }
481
482 /***********************************************************************
483  *           RegisterShellHookWindow                    [USER32.@]
484  */
485 BOOL WINAPI RegisterShellHookWindow ( HWND hWnd )
486 {
487     FIXME("(%p): stub\n", hWnd);
488     return 0;
489 }
490
491
492 /***********************************************************************
493  *           DeregisterShellHookWindow                  [USER32.@]
494  */
495 HRESULT WINAPI DeregisterShellHookWindow ( DWORD u )
496 {
497     FIXME("0x%08lx stub\n",u);
498     return 0;
499
500 }
501
502
503 /***********************************************************************
504  *           RegisterTasklist                           [USER32.@]
505  */
506 DWORD WINAPI RegisterTasklist (DWORD x)
507 {
508     FIXME("0x%08lx\n",x);
509     return TRUE;
510 }
511
512
513 /***********************************************************************
514  *              RegisterDeviceNotificationA (USER32.@)
515  *
516  * See RegisterDeviceNotificationW.
517  */
518 HDEVNOTIFY WINAPI RegisterDeviceNotificationA(HANDLE hnd, LPVOID notifyfilter, DWORD flags)
519 {
520     FIXME("(hwnd=%p, filter=%p,flags=0x%08lx), STUB!\n", hnd,notifyfilter,flags );
521     return 0;
522 }
523
524 /***********************************************************************
525  *              RegisterDeviceNotificationW (USER32.@)
526  *
527  * Registers a window with the system so that it will receive
528  * notifications about a device.
529  *
530  * PARAMS
531  *     hRecepient           [I] Window or service status handle that
532  *                              will receive notifications.
533  *     pNotificationFilter  [I] DEV_BROADCAST_HDR followed by some
534  *                              type-specific data.
535  *     dwFlags              [I] See notes
536  *
537  * RETURNS
538  *
539  * A handle to the device notification.
540  *
541  * NOTES
542  *
543  * The dwFlags parameter can be one of two values:
544  *| DEVICE_NOTIFY_WINDOW_HANDLE  - hRecepient is a window handle
545  *| DEVICE_NOTIFY_SERVICE_HANDLE - hRecepient is a service status handle
546  */
547 HDEVNOTIFY WINAPI RegisterDeviceNotificationW(HANDLE hRecepient, LPVOID pNotificationFilter, DWORD dwFlags)
548 {
549     FIXME("(hwnd=%p, filter=%p,flags=0x%08lx), STUB!\n", hRecepient,pNotificationFilter,dwFlags );
550     return 0;
551 }
552
553 /***********************************************************************
554  *           GetAppCompatFlags   (USER32.@)
555  */
556 DWORD WINAPI GetAppCompatFlags( HTASK hTask )
557 {
558     FIXME("stub\n");
559     return 0;
560 }
561
562
563 /***********************************************************************
564  *           AlignRects   (USER32.@)
565  */
566 BOOL WINAPI AlignRects(LPRECT rect, DWORD b, DWORD c, DWORD d)
567 {
568     FIXME("(%p, %ld, %ld, %ld): stub\n", rect, b, c, d);
569     if (rect)
570         FIXME("rect: [[%ld, %ld], [%ld, %ld]]\n", rect->left, rect->top, rect->right, rect->bottom);
571     /* Calls OffsetRect */
572     return FALSE;
573 }
574
575
576 /***********************************************************************
577  *              LoadLocalFonts (USER32.@)
578  */
579 VOID WINAPI LoadLocalFonts(VOID)
580 {
581     /* are loaded. */
582     return;
583 }
584
585
586 /***********************************************************************
587  *              USER_489 (USER.489)
588  */
589 LONG WINAPI stub_USER_489(void) { FIXME("stub\n"); return 0; }
590
591 /***********************************************************************
592  *              USER_490 (USER.490)
593  */
594 LONG WINAPI stub_USER_490(void) { FIXME("stub\n"); return 0; }
595
596 /***********************************************************************
597  *              USER_492 (USER.492)
598  */
599 LONG WINAPI stub_USER_492(void) { FIXME("stub\n"); return 0; }
600
601 /***********************************************************************
602  *              USER_496 (USER.496)
603  */
604 LONG WINAPI stub_USER_496(void) { FIXME("stub\n"); return 0; }
605
606 /***********************************************************************
607  *              User32InitializeImmEntryTable
608  */
609 BOOL WINAPI User32InitializeImmEntryTable(LPVOID ptr)
610 {
611   FIXME("(%p): stub\n", ptr);
612   return TRUE;
613 }
614
615 /**********************************************************************
616  * WINNLSGetIMEHotkey [USER32.@]
617  *
618  */
619 UINT WINAPI WINNLSGetIMEHotkey(HWND hUnknown1)
620 {
621     FIXME("hUnknown1 %p: stub!\n", hUnknown1);
622     return 0; /* unknown */
623 }
624
625 /**********************************************************************
626  * WINNLSEnableIME [USER32.@]
627  *
628  */
629 BOOL WINAPI WINNLSEnableIME(HWND hUnknown1, BOOL bUnknown2)
630 {
631     FIXME("hUnknown1 %p bUnknown2 %d: stub!\n", hUnknown1, bUnknown2);
632     return TRUE; /* success (?) */
633 }
634
635 /**********************************************************************
636  * WINNLSGetEnableStatus [USER32.@]
637  *
638  */
639 BOOL WINAPI WINNLSGetEnableStatus(HWND hUnknown1)
640 {
641     FIXME("hUnknown1 %p: stub!\n", hUnknown1);
642     return TRUE; /* success (?) */
643 }
644
645 /**********************************************************************
646  * SendIMEMessageExA [USER32.@]
647  *
648  */
649 LRESULT WINAPI SendIMEMessageExA(HWND p1, LPARAM p2)
650 {
651   FIXME("(%p,%lx): stub\n", p1, p2);
652   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
653   return 0;
654 }
655
656 /**********************************************************************
657  * SendIMEMessageExW [USER32.@]
658  *
659  */
660 LRESULT WINAPI SendIMEMessageExW(HWND p1, LPARAM p2)
661 {
662   FIXME("(%p,%lx): stub\n", p1, p2);
663   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
664   return 0;
665 }