2 * Implementation of the Common Property Sheets User Interface
4 * Copyright 2006 Detlef Riekenberg
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "ddk/compstui.h"
34 #include "wine/debug.h"
35 #include "wine/list.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(compstui
);
39 static HMODULE compstui_hmod
;
57 } PROPSHEETUI_INFO_HEADERAW
;
83 #define HANDLE_FIRST 0x43440001
84 static struct cps_data
96 struct cps_data
*next_free
;
98 struct propsheetpage
*psp
;
99 struct propsheetfunc
*psf
;
102 static struct cps_data
*first_free_handle
= handles
;
104 static CRITICAL_SECTION handles_cs
;
105 static CRITICAL_SECTION_DEBUG handles_cs_debug
=
108 { &handles_cs_debug
.ProcessLocksList
, &handles_cs_debug
.ProcessLocksList
},
109 0, 0, { (DWORD_PTR
)(__FILE__
": handles_cs") }
111 static CRITICAL_SECTION handles_cs
= { &handles_cs_debug
, -1, 0, 0, 0, 0 };
113 static LONG_PTR WINAPI
cps_callback(HANDLE hcps
, UINT func
, LPARAM lparam1
, LPARAM lparam2
);
115 static struct cps_data
* get_handle_data(HANDLE handle
)
117 struct cps_data
*ret
;
119 if ((ULONG_PTR
)handle
< HANDLE_FIRST
|| (ULONG_PTR
)handle
>= HANDLE_FIRST
+ ARRAY_SIZE(handles
))
122 ret
= &handles
[(ULONG_PTR
)handle
- HANDLE_FIRST
];
123 return ret
->type
== HANDLE_FREE
? NULL
: ret
;
126 static HANDLE
alloc_handle(struct cps_data
**cps_data
, int type
)
132 case HANDLE_PROPSHEET
:
133 data
= calloc(1, sizeof(struct propsheet
));
135 case HANDLE_PROPSHEETPAGE
:
136 data
= calloc(1, sizeof(struct propsheetpage
));
138 case HANDLE_PROPSHEETFUNC
:
139 data
= calloc(1, sizeof(struct propsheetfunc
));
146 EnterCriticalSection(&handles_cs
);
148 if (first_free_handle
>= handles
+ ARRAY_SIZE(handles
))
150 LeaveCriticalSection(&handles_cs
);
151 FIXME("out of handles\n");
156 *cps_data
= first_free_handle
;
157 if ((*cps_data
)->next_free
)
158 first_free_handle
= (*cps_data
)->next_free
;
160 first_free_handle
= (*cps_data
) + 1;
161 LeaveCriticalSection(&handles_cs
);
163 (*cps_data
)->type
= type
;
164 (*cps_data
)->data
= data
;
165 return (HANDLE
)(HANDLE_FIRST
+ ((*cps_data
) - handles
));
168 static void free_handle(HANDLE handle
)
170 struct cps_data
*data
= get_handle_data(handle
);
175 data
->type
= HANDLE_FREE
;
178 EnterCriticalSection(&handles_cs
);
179 data
->next_free
= first_free_handle
;
180 first_free_handle
= data
;
181 LeaveCriticalSection(&handles_cs
);
184 static HANDLE
add_hpropsheetpage(HANDLE hcps
, HPROPSHEETPAGE hpsp
)
186 struct cps_data
*cps_data
= get_handle_data(hcps
);
187 struct cps_data
*cpsp_data
;
190 if (!cps_data
|| !hpsp
)
193 if (cps_data
->type
!= HANDLE_PROPSHEET
)
195 FIXME("unsupported handle type %d\n", cps_data
->type
);
199 if (cps_data
->ps
->pages_cnt
== ARRAY_SIZE(cps_data
->ps
->pages
))
202 ret
= alloc_handle(&cpsp_data
, HANDLE_PROPSHEETPAGE
);
205 cpsp_data
->psp
->hpsp
= hpsp
;
207 cps_data
->ps
->pages
[cps_data
->ps
->pages_cnt
++] = ret
;
211 static HANDLE
add_propsheetfunc(HANDLE hcps
, PFNPROPSHEETUI func
, LPARAM lparam
, BOOL unicode
)
213 struct cps_data
*cps_data
= get_handle_data(hcps
);
214 struct cps_data
*cpsf_data
;
215 PROPSHEETUI_INFO info
, callback_info
;
219 if (!cps_data
|| !func
)
222 if (cps_data
->type
!= HANDLE_PROPSHEET
)
224 FIXME("unsupported handle type %d\n", cps_data
->type
);
228 ret
= alloc_handle(&cpsf_data
, HANDLE_PROPSHEETFUNC
);
231 cpsf_data
->psf
->handle
= ret
;
232 cpsf_data
->psf
->func
= func
;
233 cpsf_data
->psf
->unicode
= unicode
;
234 cpsf_data
->psf
->lparam
= lparam
;
236 memset(&info
, 0, sizeof(info
));
237 info
.cbSize
= sizeof(info
);
238 info
.Version
= PROPSHEETUI_INFO_VERSION
;
239 info
.Flags
= unicode
? PSUIINFO_UNICODE
: 0;
240 info
.Reason
= PROPSHEETUI_REASON_INIT
;
241 info
.hComPropSheet
= hcps
;
242 info
.pfnComPropSheet
= cps_callback
;
243 info
.lParamInit
= lparam
;
245 callback_info
= info
;
246 lret
= func(&callback_info
, lparam
);
247 cpsf_data
->psf
->user_data
= callback_info
.UserData
;
248 cpsf_data
->psf
->result
= callback_info
.Result
;
251 callback_info
= info
;
252 callback_info
.Reason
= PROPSHEETUI_REASON_DESTROY
;
253 callback_info
.UserData
= cpsf_data
->psf
->user_data
;
254 callback_info
.Result
= cpsf_data
->psf
->result
;
256 func(&callback_info
, 0);
260 list_add_tail(&cps_data
->ps
->funcs
, &cpsf_data
->psf
->entry
);
264 static HANDLE
add_propsheetpage(HANDLE hcps
, void *psp
, PSPINFO
*info
,
265 DLGPROC dlg_proc
, BOOL unicode
)
267 struct cps_data
*cps_data
= get_handle_data(hcps
);
268 struct cps_data
*cpsp_data
;
275 if (cps_data
->type
!= HANDLE_PROPSHEET
)
277 FIXME("unsupported handle type %d\n", cps_data
->type
);
281 if (cps_data
->ps
->pages_cnt
== ARRAY_SIZE(cps_data
->ps
->pages
))
284 ret
= alloc_handle(&cpsp_data
, HANDLE_PROPSHEETPAGE
);
288 info
->cbSize
= sizeof(*info
);
290 info
->hComPropSheet
= hcps
;
291 info
->hCPSUIPage
= ret
;
292 info
->pfnComPropSheet
= cps_callback
;
295 hpsp
= CreatePropertySheetPageW((PROPSHEETPAGEW
*)psp
);
297 hpsp
= CreatePropertySheetPageA((PROPSHEETPAGEA
*)psp
);
304 cpsp_data
->psp
->hpsp
= hpsp
;
305 cpsp_data
->psp
->dlg_proc
= dlg_proc
;
306 cps_data
->ps
->pages
[cps_data
->ps
->pages_cnt
++] = ret
;
310 static INT_PTR CALLBACK
propsheetpage_dlg_procW(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
312 if (msg
== WM_INITDIALOG
)
314 PROPSHEETPAGEW
*psp
= (PROPSHEETPAGEW
*)lparam
;
315 PSPINFO
*info
= (PSPINFO
*)((BYTE
*)lparam
+ psp
->dwSize
- sizeof(*info
));
316 struct cps_data
*cpsp_data
= get_handle_data(info
->hCPSUIPage
);
318 psp
->dwSize
-= sizeof(*info
);
319 psp
->pfnDlgProc
= cpsp_data
->psp
->dlg_proc
;
320 SetWindowLongPtrW(hwnd
, DWLP_DLGPROC
, (LONG_PTR
)psp
->pfnDlgProc
);
321 return psp
->pfnDlgProc(hwnd
, msg
, wparam
, lparam
);
327 static HANDLE
add_propsheetpageW(HANDLE hcps
, PROPSHEETPAGEW
*psp
)
329 PROPSHEETPAGEW
*psp_copy
;
333 if (!psp
|| psp
->dwSize
< PROPSHEETPAGEW_V1_SIZE
)
336 psp_copy
= (PROPSHEETPAGEW
*)malloc(psp
->dwSize
+ sizeof(*info
));
339 memcpy(psp_copy
, psp
, psp
->dwSize
);
340 psp_copy
->dwSize
+= sizeof(*info
);
341 psp_copy
->pfnDlgProc
= propsheetpage_dlg_procW
;
343 info
= (PSPINFO
*)((BYTE
*)psp_copy
+ psp
->dwSize
);
344 ret
= add_propsheetpage(hcps
, psp_copy
, info
, psp
->pfnDlgProc
, TRUE
);
349 static INT_PTR CALLBACK
propsheetpage_dlg_procA(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
351 if (msg
== WM_INITDIALOG
)
353 PROPSHEETPAGEA
*psp
= (PROPSHEETPAGEA
*)lparam
;
354 PSPINFO
*info
= (PSPINFO
*)((BYTE
*)lparam
+ psp
->dwSize
- sizeof(*info
));
355 struct cps_data
*cpsp_data
= get_handle_data(info
->hCPSUIPage
);
357 psp
->dwSize
-= sizeof(*info
);
358 psp
->pfnDlgProc
= cpsp_data
->psp
->dlg_proc
;
359 SetWindowLongPtrA(hwnd
, DWLP_DLGPROC
, (LONG_PTR
)psp
->pfnDlgProc
);
360 return psp
->pfnDlgProc(hwnd
, msg
, wparam
, lparam
);
366 static HANDLE
add_propsheetpageA(HANDLE hcps
, PROPSHEETPAGEA
*psp
)
368 PROPSHEETPAGEA
*psp_copy
;
372 if (!psp
|| psp
->dwSize
< PROPSHEETPAGEW_V1_SIZE
)
375 psp_copy
= (PROPSHEETPAGEA
*)malloc(psp
->dwSize
+ sizeof(*info
));
378 memcpy(psp_copy
, psp
, psp
->dwSize
);
379 psp_copy
->dwSize
+= sizeof(*info
);
380 psp_copy
->pfnDlgProc
= propsheetpage_dlg_procA
;
382 info
= (PSPINFO
*)((BYTE
*)psp_copy
+ psp
->dwSize
);
383 ret
= add_propsheetpage(hcps
, psp_copy
, info
, psp
->pfnDlgProc
, FALSE
);
388 static LONG_PTR WINAPI
cps_callback(HANDLE hcps
, UINT func
, LPARAM lparam1
, LPARAM lparam2
)
390 TRACE("(%p, %u, %Ix, %Ix\n", hcps
, func
, lparam1
, lparam2
);
394 case CPSFUNC_ADD_HPROPSHEETPAGE
:
395 return (LONG_PTR
)add_hpropsheetpage(hcps
, (HPROPSHEETPAGE
)lparam1
);
396 case CPSFUNC_ADD_PFNPROPSHEETUIA
:
397 case CPSFUNC_ADD_PFNPROPSHEETUIW
:
398 return (LONG_PTR
)add_propsheetfunc(hcps
, (PFNPROPSHEETUI
)lparam1
,
399 lparam2
, func
== CPSFUNC_ADD_PFNPROPSHEETUIW
);
400 case CPSFUNC_ADD_PROPSHEETPAGEA
:
401 return (LONG_PTR
)add_propsheetpageA(hcps
, (PROPSHEETPAGEA
*)lparam1
);
402 case CPSFUNC_ADD_PROPSHEETPAGEW
:
403 return (LONG_PTR
)add_propsheetpageW(hcps
, (PROPSHEETPAGEW
*)lparam1
);
404 case CPSFUNC_ADD_PCOMPROPSHEETUIA
:
405 case CPSFUNC_ADD_PCOMPROPSHEETUIW
:
406 case CPSFUNC_DELETE_HCOMPROPSHEET
:
407 case CPSFUNC_SET_HSTARTPAGE
:
408 case CPSFUNC_GET_PAGECOUNT
:
409 case CPSFUNC_SET_RESULT
:
410 case CPSFUNC_GET_HPSUIPAGES
:
411 case CPSFUNC_LOAD_CPSUI_STRINGA
:
412 case CPSFUNC_LOAD_CPSUI_STRINGW
:
413 case CPSFUNC_LOAD_CPSUI_ICON
:
414 case CPSFUNC_GET_PFNPROPSHEETUI_ICON
:
415 case CPSFUNC_INSERT_PSUIPAGEA
:
416 case CPSFUNC_INSERT_PSUIPAGEW
:
417 case CPSFUNC_SET_PSUIPAGE_TITLEA
:
418 case CPSFUNC_SET_PSUIPAGE_TITLEW
:
419 case CPSFUNC_SET_PSUIPAGE_ICON
:
420 case CPSFUNC_SET_DATABLOCK
:
421 case CPSFUNC_QUERY_DATABLOCK
:
422 case CPSFUNC_SET_DMPUB_HIDEBITS
:
423 case CPSFUNC_IGNORE_CPSUI_PSN_APPLY
:
424 case CPSFUNC_DO_APPLY_CPSUI
:
425 case CPSFUNC_SET_FUSION_CONTEXT
:
426 FIXME("func not supported %d\n", func
);
429 ERR("unknown func: %d\n", func
);
434 static LONG
create_property_sheetW(struct propsheet
*ps
, PROPSHEETUI_INFO_HEADERAW
*header
)
436 HPROPSHEETPAGE hpsp
[100];
437 PROPSHEETHEADERW psh
;
443 return ERR_CPSUI_NO_PROPSHEETPAGE
;
445 memset(&psh
, 0, sizeof(psh
));
446 psh
.dwSize
= sizeof(psh
);
447 if (header
->flags
& PSUIHDRF_NOAPPLYNOW
)
448 psh
.dwFlags
|= PSH_NOAPPLYNOW
;
449 psh
.hwndParent
= header
->parent
;
450 psh
.hInstance
= header
->hinst
;
451 psh
.pszCaption
= title
;
453 if (!(header
->flags
& PSUIHDRF_USEHICON
) && !header
->icon_id
)
454 header
->icon_id
= IDI_CPSUI_OPTION
;
456 if (header
->flags
& PSUIHDRF_USEHICON
)
458 psh
.dwFlags
|= PSH_USEHICON
;
459 psh
.hIcon
= header
->hicon
;
461 else if (header
->icon_id
>= IDI_CPSUI_ICONID_FIRST
&&
462 header
->icon_id
<= IDI_CPSUI_ICONID_LAST
)
464 FIXME("icon not implemented: %Id\n", header
->icon_id
);
468 psh
.dwFlags
|= PSH_USEICONID
;
469 psh
.pszIcon
= (WCHAR
*)header
->icon_id
;
473 wcscpy_s(title
, ARRAY_SIZE(title
), header
->titleW
);
475 LoadStringW(compstui_hmod
, IDS_CPSUI_OPTIONS
, title
, ARRAY_SIZE(title
));
477 if ((header
->flags
& PSUIHDRF_DEFTITLE
) &&
478 (!header
->titleW
|| !(header
->flags
& PSUIHDRF_EXACT_PTITLE
)))
481 if (len
< ARRAY_SIZE(title
))
483 LoadStringW(compstui_hmod
, IDS_CPSUI_DEFAULT
, title
+ len
, ARRAY_SIZE(title
) - len
);
486 if ((header
->flags
& PSUIHDRF_PROPTITLE
) &&
487 (!header
->titleW
|| !(header
->flags
& PSUIHDRF_EXACT_PTITLE
)))
490 if (len
< ARRAY_SIZE(title
))
492 LoadStringW(compstui_hmod
, IDS_CPSUI_PROPERTIES
, title
+ len
, ARRAY_SIZE(title
) - len
);
495 psh
.nPages
= ps
->pages_cnt
;
497 for (i
= 0; i
< ps
->pages_cnt
; i
++)
498 hpsp
[i
] = get_handle_data(ps
->pages
[i
])->psp
->hpsp
;
500 ret
= PropertySheetW(&psh
);
505 return ERR_CPSUI_GETLASTERROR
;
506 case ID_PSREBOOTSYSTEM
:
507 return CPSUI_REBOOTSYSTEM
;
508 case ID_PSRESTARTWINDOWS
:
509 return CPSUI_RESTARTWINDOWS
;
515 static LONG
create_prop_dlg(HWND hwnd
, PFNPROPSHEETUI callback
, LPARAM lparam
, DWORD
*res
, BOOL unicode
)
517 PROPSHEETUI_INFO info
, callback_info
;
518 PROPSHEETUI_INFO_HEADERAW header
;
519 struct cps_data
*cps_data
;
524 if (!callback
|| !(cps_handle
= alloc_handle(&cps_data
, HANDLE_PROPSHEET
)))
527 return ERR_CPSUI_GETLASTERROR
;
529 list_init(&cps_data
->ps
->funcs
);
531 memset(&info
, 0, sizeof(info
));
532 info
.cbSize
= sizeof(info
);
533 info
.lParamInit
= lparam
;
534 callback_info
= info
;
535 callback_info
.Reason
= PROPSHEETUI_REASON_BEFORE_INIT
;
536 callback(&callback_info
, lparam
);
538 info
.Version
= PROPSHEETUI_INFO_VERSION
;
539 info
.Flags
= unicode
? PSUIINFO_UNICODE
: 0;
540 info
.hComPropSheet
= cps_handle
;
541 info
.pfnComPropSheet
= cps_callback
;
542 callback_info
= info
;
543 callback_info
.Reason
= PROPSHEETUI_REASON_INIT
;
544 ret
= callback(&callback_info
, lparam
);
545 info
.UserData
= callback_info
.UserData
;
546 info
.Result
= callback_info
.Result
;
549 ret
= ERR_CPSUI_GETLASTERROR
;
553 memset(&header
, 0, sizeof(header
));
554 header
.size
= sizeof(header
);
555 header
.parent
= hwnd
;
556 callback_info
= info
;
557 callback_info
.Reason
= PROPSHEETUI_REASON_GET_INFO_HEADER
;
558 ret
= callback(&callback_info
, (LPARAM
)&header
);
559 info
.UserData
= callback_info
.UserData
;
560 info
.Result
= callback_info
.Result
;
563 ret
= ERR_CPSUI_GETLASTERROR
;
567 ret
= create_property_sheetW(cps_data
->ps
, &header
);
570 info
.Reason
= PROPSHEETUI_REASON_DESTROY
;
571 while (!list_empty(&cps_data
->ps
->funcs
))
573 struct propsheetfunc
*func
= LIST_ENTRY(list_head(&cps_data
->ps
->funcs
),
574 struct propsheetfunc
, entry
);
576 list_remove(&func
->entry
);
578 callback_info
= info
;
579 callback_info
.Flags
= func
->unicode
? PSUIINFO_UNICODE
: 0;
580 callback_info
.lParamInit
= func
->lparam
;
581 callback_info
.UserData
= func
->user_data
;
582 callback_info
.Result
= func
->result
;
583 func
->func(&callback_info
, ret
<= 0 ? 0 : 0x100);
584 free_handle(func
->handle
);
587 callback_info
= info
;
588 callback(&callback_info
, ret
<= 0 ? 0 : 0x100);
590 for (i
= 0; i
< cps_data
->ps
->pages_cnt
; i
++)
591 free_handle(cps_data
->ps
->pages
[i
]);
592 free_handle(cps_handle
);
594 if (res
) *res
= callback_info
.Result
;
598 /******************************************************************
599 * CommonPropertySheetUIA (COMPSTUI.@)
602 LONG WINAPI
CommonPropertySheetUIA(HWND hWnd
, PFNPROPSHEETUI pfnPropSheetUI
, LPARAM lparam
, LPDWORD pResult
)
604 FIXME("(%p, %p, 0x%Ix, %p)\n", hWnd
, pfnPropSheetUI
, lparam
, pResult
);
608 /******************************************************************
609 * CommonPropertySheetUIW (COMPSTUI.@)
612 LONG WINAPI
CommonPropertySheetUIW(HWND hwnd
, PFNPROPSHEETUI callback
, LPARAM lparam
, LPDWORD res
)
614 TRACE("(%p, %p, 0x%Ix, %p)\n", hwnd
, callback
, lparam
, res
);
615 return create_prop_dlg(hwnd
, callback
, lparam
, res
, TRUE
);
618 /******************************************************************
619 * GetCPSUIUserData (COMPSTUI.@)
622 ULONG_PTR WINAPI
GetCPSUIUserData(HWND hDlg
)
624 FIXME("(%p): stub\n", hDlg
);
628 /******************************************************************
629 * SetCPSUIUserData (COMPSTUI.@)
632 BOOL WINAPI
SetCPSUIUserData(HWND hDlg
, ULONG_PTR UserData
)
634 FIXME("(%p, %08Ix): stub\n", hDlg
, UserData
);
638 BOOL WINAPI
DllMain(HINSTANCE hinst
, DWORD reason
, void *reserved
)
640 if (reason
== DLL_PROCESS_ATTACH
)
641 compstui_hmod
= hinst
;