gdi32/tests: Mark tests failing randomly on Windows as flaky.
[wine.git] / dlls / compstui / compstui_main.c
blobb7a08e1c52baf1d416b7b273522db9a3eef01ef5
1 /*
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
21 #include <assert.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
26 #define COBJMACROS
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "prsht.h"
32 #include "ddk/compstui.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(compstui);
38 static HMODULE compstui_hmod;
40 typedef struct
42 WORD size;
43 WORD flags;
44 union
46 WCHAR *titleW;
47 char *titleA;
49 HWND parent;
50 HINSTANCE hinst;
51 union
53 HICON hicon;
54 ULONG_PTR icon_id;
56 } PROPSHEETUI_INFO_HEADERAW;
58 struct propsheet
60 int pages_cnt;
61 HANDLE pages[100];
64 struct propsheetpage
66 HPROPSHEETPAGE hpsp;
69 #define HANDLE_FIRST 0x43440001
70 static struct cps_data
72 enum
74 HANDLE_FREE = 0,
75 HANDLE_PROPSHEET,
76 HANDLE_PROPSHEETPAGE
77 } type;
78 union
80 void *data;
81 struct cps_data *next_free;
82 struct propsheet *ps;
83 struct propsheetpage *psp;
85 } handles[0x1000];
86 static struct cps_data *first_free_handle = handles;
88 static CRITICAL_SECTION handles_cs;
89 static CRITICAL_SECTION_DEBUG handles_cs_debug =
91 0, 0, &handles_cs,
92 { &handles_cs_debug.ProcessLocksList, &handles_cs_debug.ProcessLocksList },
93 0, 0, { (DWORD_PTR)(__FILE__ ": handles_cs") }
95 static CRITICAL_SECTION handles_cs = { &handles_cs_debug, -1, 0, 0, 0, 0 };
97 static struct cps_data* get_handle_data(HANDLE handle)
99 struct cps_data *ret;
101 if ((ULONG_PTR)handle < HANDLE_FIRST || (ULONG_PTR)handle >= HANDLE_FIRST + ARRAY_SIZE(handles))
102 return NULL;
104 ret = &handles[(ULONG_PTR)handle - HANDLE_FIRST];
105 return ret->type == HANDLE_FREE ? NULL : ret;
108 static HANDLE alloc_handle(struct cps_data **cps_data, int type)
110 void *data = NULL;
112 switch(type)
114 case HANDLE_PROPSHEET:
115 data = calloc(1, sizeof(struct propsheet));
116 break;
117 case HANDLE_PROPSHEETPAGE:
118 data = calloc(1, sizeof(struct propsheetpage));
119 break;
122 if (!data)
123 return NULL;
125 EnterCriticalSection(&handles_cs);
127 if (first_free_handle >= handles + ARRAY_SIZE(handles))
129 LeaveCriticalSection(&handles_cs);
130 FIXME("out of handles\n");
131 free(data);
132 return NULL;
135 *cps_data = first_free_handle;
136 if ((*cps_data)->next_free)
137 first_free_handle = (*cps_data)->next_free;
138 else
139 first_free_handle = (*cps_data) + 1;
140 LeaveCriticalSection(&handles_cs);
142 (*cps_data)->type = type;
143 (*cps_data)->data = data;
144 return (HANDLE)(HANDLE_FIRST + ((*cps_data) - handles));
147 static void free_handle(HANDLE handle)
149 struct cps_data *data = get_handle_data(handle);
151 if (!data)
152 return;
154 data->type = HANDLE_FREE;
155 free(data->data);
157 EnterCriticalSection(&handles_cs);
158 data->next_free = first_free_handle;
159 first_free_handle = data;
160 LeaveCriticalSection(&handles_cs);
163 static HANDLE add_hpropsheetpage(HANDLE hcps, HPROPSHEETPAGE hpsp)
165 struct cps_data *cps_data = get_handle_data(hcps);
166 struct cps_data *cpsp_data;
167 HANDLE ret;
169 if (!cps_data || !hpsp)
170 return 0;
172 if (cps_data->type != HANDLE_PROPSHEET)
174 FIXME("unsupported handle type %d\n", cps_data->type);
175 return 0;
178 if (cps_data->ps->pages_cnt == ARRAY_SIZE(cps_data->ps->pages))
179 return 0;
181 ret = alloc_handle(&cpsp_data, HANDLE_PROPSHEETPAGE);
182 if (!ret)
183 return 0;
184 cpsp_data->psp->hpsp = hpsp;
186 cps_data->ps->pages[cps_data->ps->pages_cnt++] = ret;
187 return ret;
190 static LONG_PTR WINAPI cps_callback(HANDLE hcps, UINT func, LPARAM lparam1, LPARAM lparam2)
192 TRACE("(%p, %u, %Ix, %Ix\n", hcps, func, lparam1, lparam2);
194 switch(func)
196 case CPSFUNC_ADD_HPROPSHEETPAGE:
197 return (LONG_PTR)add_hpropsheetpage(hcps, (HPROPSHEETPAGE)lparam1);
198 case CPSFUNC_ADD_PROPSHEETPAGEW:
199 case CPSFUNC_ADD_PCOMPROPSHEETUIA:
200 case CPSFUNC_ADD_PCOMPROPSHEETUIW:
201 case CPSFUNC_ADD_PFNPROPSHEETUIA:
202 case CPSFUNC_ADD_PFNPROPSHEETUIW:
203 case CPSFUNC_DELETE_HCOMPROPSHEET:
204 case CPSFUNC_SET_HSTARTPAGE:
205 case CPSFUNC_GET_PAGECOUNT:
206 case CPSFUNC_SET_RESULT:
207 case CPSFUNC_GET_HPSUIPAGES:
208 case CPSFUNC_LOAD_CPSUI_STRINGA:
209 case CPSFUNC_LOAD_CPSUI_STRINGW:
210 case CPSFUNC_LOAD_CPSUI_ICON:
211 case CPSFUNC_GET_PFNPROPSHEETUI_ICON:
212 case CPSFUNC_ADD_PROPSHEETPAGEA:
213 case CPSFUNC_INSERT_PSUIPAGEA:
214 case CPSFUNC_INSERT_PSUIPAGEW:
215 case CPSFUNC_SET_PSUIPAGE_TITLEA:
216 case CPSFUNC_SET_PSUIPAGE_TITLEW:
217 case CPSFUNC_SET_PSUIPAGE_ICON:
218 case CPSFUNC_SET_DATABLOCK:
219 case CPSFUNC_QUERY_DATABLOCK:
220 case CPSFUNC_SET_DMPUB_HIDEBITS:
221 case CPSFUNC_IGNORE_CPSUI_PSN_APPLY:
222 case CPSFUNC_DO_APPLY_CPSUI:
223 case CPSFUNC_SET_FUSION_CONTEXT:
224 FIXME("func not supported %d\n", func);
225 return 0;
226 default:
227 ERR("unknown func: %d\n", func);
228 return 0;
232 static LONG create_property_sheetW(struct propsheet *ps, PROPSHEETUI_INFO_HEADERAW *header)
234 HPROPSHEETPAGE hpsp[100];
235 PROPSHEETHEADERW psh;
236 WCHAR title[256];
237 LONG_PTR ret;
238 int i, len;
240 if (!ps->pages_cnt)
241 return ERR_CPSUI_NO_PROPSHEETPAGE;
243 memset(&psh, 0, sizeof(psh));
244 psh.dwSize = sizeof(psh);
245 if (header->flags & PSUIHDRF_NOAPPLYNOW)
246 psh.dwFlags |= PSH_NOAPPLYNOW;
247 psh.hwndParent = header->parent;
248 psh.hInstance = header->hinst;
249 psh.pszCaption = title;
251 if (!(header->flags & PSUIHDRF_USEHICON) && !header->icon_id)
252 header->icon_id = IDI_CPSUI_OPTION;
254 if (header->flags & PSUIHDRF_USEHICON)
256 psh.dwFlags |= PSH_USEHICON;
257 psh.hIcon = header->hicon;
259 else if (header->icon_id >= IDI_CPSUI_ICONID_FIRST &&
260 header->icon_id <= IDI_CPSUI_ICONID_LAST)
262 FIXME("icon not implemented: %Id\n", header->icon_id);
264 else
266 psh.dwFlags |= PSH_USEICONID;
267 psh.pszIcon = (WCHAR*)header->icon_id;
270 if (header->titleW)
271 wcscpy_s(title, ARRAY_SIZE(title), header->titleW);
272 else
273 LoadStringW(compstui_hmod, IDS_CPSUI_OPTIONS, title, ARRAY_SIZE(title));
275 if ((header->flags & PSUIHDRF_DEFTITLE) &&
276 (!header->titleW || !(header->flags & PSUIHDRF_EXACT_PTITLE)))
278 len = wcslen(title);
279 if (len < ARRAY_SIZE(title))
280 title[len++] = ' ';
281 LoadStringW(compstui_hmod, IDS_CPSUI_DEFAULT, title + len, ARRAY_SIZE(title) - len);
284 if ((header->flags & PSUIHDRF_PROPTITLE) &&
285 (!header->titleW || !(header->flags & PSUIHDRF_EXACT_PTITLE)))
287 len = wcslen(title);
288 if (len < ARRAY_SIZE(title))
289 title[len++] = ' ';
290 LoadStringW(compstui_hmod, IDS_CPSUI_PROPERTIES, title + len, ARRAY_SIZE(title) - len);
293 psh.nPages = ps->pages_cnt;
294 psh.phpage = hpsp;
295 for (i = 0; i < ps->pages_cnt; i++)
296 hpsp[i] = get_handle_data(ps->pages[i])->psp->hpsp;
298 ret = PropertySheetW(&psh);
300 switch(ret)
302 case -1:
303 return ERR_CPSUI_GETLASTERROR;
304 case ID_PSREBOOTSYSTEM:
305 return CPSUI_REBOOTSYSTEM;
306 case ID_PSRESTARTWINDOWS:
307 return CPSUI_RESTARTWINDOWS;
308 default:
309 return CPSUI_OK;
313 static LONG create_prop_dlg(HWND hwnd, PFNPROPSHEETUI callback, LPARAM lparam, DWORD *res, BOOL unicode)
315 PROPSHEETUI_INFO info, callback_info;
316 PROPSHEETUI_INFO_HEADERAW header;
317 struct cps_data *cps_data;
318 HANDLE cps_handle;
319 LONG ret;
320 int i;
322 if (!callback || !(cps_handle = alloc_handle(&cps_data, HANDLE_PROPSHEET)))
324 SetLastError(0);
325 return ERR_CPSUI_GETLASTERROR;
328 memset(&info, 0, sizeof(info));
329 info.cbSize = sizeof(info);
330 info.lParamInit = lparam;
331 callback_info = info;
332 callback_info.Reason = PROPSHEETUI_REASON_BEFORE_INIT;
333 callback(&callback_info, lparam);
335 info.Version = PROPSHEETUI_INFO_VERSION;
336 info.Flags = unicode ? PSUIINFO_UNICODE : 0;
337 info.hComPropSheet = cps_handle;
338 info.pfnComPropSheet = cps_callback;
339 callback_info = info;
340 callback_info.Reason = PROPSHEETUI_REASON_INIT;
341 ret = callback(&callback_info, lparam);
342 info.UserData = callback_info.UserData;
343 info.Result = callback_info.Result;
344 if (ret <= 0)
346 ret = ERR_CPSUI_GETLASTERROR;
347 goto destroy;
350 memset(&header, 0, sizeof(header));
351 header.size = sizeof(header);
352 header.parent = hwnd;
353 callback_info = info;
354 callback_info.Reason = PROPSHEETUI_REASON_GET_INFO_HEADER;
355 ret = callback(&callback_info, (LPARAM)&header);
356 info.UserData = callback_info.UserData;
357 info.Result = callback_info.Result;
358 if (ret <= 0)
360 ret = ERR_CPSUI_GETLASTERROR;
361 goto destroy;
364 ret = create_property_sheetW(cps_data->ps, &header);
366 destroy:
367 callback_info = info;
368 callback_info.Reason = PROPSHEETUI_REASON_DESTROY;
369 callback(&callback_info, ret < 0 ? 0 : 0x100);
371 for (i = 0; i < cps_data->ps->pages_cnt; i++)
372 free_handle(cps_data->ps->pages[i]);
373 free_handle(cps_handle);
375 if (res) *res = callback_info.Result;
376 return ret;
379 /******************************************************************
380 * CommonPropertySheetUIA (COMPSTUI.@)
383 LONG WINAPI CommonPropertySheetUIA(HWND hWnd, PFNPROPSHEETUI pfnPropSheetUI, LPARAM lparam, LPDWORD pResult)
385 FIXME("(%p, %p, 0x%Ix, %p)\n", hWnd, pfnPropSheetUI, lparam, pResult);
386 return CPSUI_CANCEL;
389 /******************************************************************
390 * CommonPropertySheetUIW (COMPSTUI.@)
393 LONG WINAPI CommonPropertySheetUIW(HWND hwnd, PFNPROPSHEETUI callback, LPARAM lparam, LPDWORD res)
395 TRACE("(%p, %p, 0x%Ix, %p)\n", hwnd, callback, lparam, res);
396 return create_prop_dlg(hwnd, callback, lparam, res, TRUE);
399 /******************************************************************
400 * GetCPSUIUserData (COMPSTUI.@)
403 ULONG_PTR WINAPI GetCPSUIUserData(HWND hDlg)
405 FIXME("(%p): stub\n", hDlg);
406 return 0;
409 /******************************************************************
410 * SetCPSUIUserData (COMPSTUI.@)
413 BOOL WINAPI SetCPSUIUserData(HWND hDlg, ULONG_PTR UserData )
415 FIXME("(%p, %08Ix): stub\n", hDlg, UserData);
416 return TRUE;
419 BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved)
421 if (reason == DLL_PROCESS_ATTACH)
422 compstui_hmod = hinst;
423 return TRUE;