xref: /reactos/dll/win32/setupapi/dialog.c (revision 9393fc32)
1 /*
2  * SetupAPI dialog functions
3  *
4  * Copyright 2009 Ricardo Filipe
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 #include "setupapi_private.h"
22 
23 struct promptdisk_params {
24     PCWSTR DialogTitle;
25     PCWSTR DiskName;
26     PCWSTR PathToSource;
27     PCWSTR FileSought;
28     PCWSTR TagFile;
29     DWORD DiskPromptStyle;
30     PWSTR PathBuffer;
31     DWORD PathBufferSize;
32     PDWORD PathRequiredSize;
33 };
34 
35 /* initiates the fields of the SetupPromptForDisk dialog according to the parameters
36 */
37 static void promptdisk_init(HWND hwnd, struct promptdisk_params *params)
38 {
39     SetWindowLongPtrW(hwnd, DWLP_USER, (LONG_PTR)params);
40 
41     if(params->DialogTitle)
42         SetWindowTextW(hwnd, params->DialogTitle);
43     if(params->PathToSource)
44         SetDlgItemTextW(hwnd, IDC_PATH, params->PathToSource);
45 
46     if(!(params->DiskPromptStyle & IDF_OEMDISK))
47     {
48         WCHAR message[256+2*MAX_PATH];
49         WCHAR format[256];
50         WCHAR unknown[256];
51         DWORD_PTR args[2];
52         LoadStringW(hInstance, IDS_PROMPTDISK, format,
53             sizeof(format)/sizeof(format[0]));
54 
55         args[0] = (DWORD_PTR)params->FileSought;
56         if(params->DiskName)
57             args[1] = (DWORD_PTR)params->DiskName;
58         else
59         {
60             LoadStringW(hInstance, IDS_UNKNOWN, unknown,
61                 sizeof(unknown)/sizeof(unknown[0]));
62             args[1] = (DWORD_PTR)unknown;
63         }
64         FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
65                        format, 0, 0, message, sizeof(message)/sizeof(*message),
66                        (__ms_va_list*)args);
67         SetDlgItemTextW(hwnd, IDC_FILENEEDED, message);
68 
69         LoadStringW(hInstance, IDS_INFO, message,
70             sizeof(message)/sizeof(message[0]));
71         SetDlgItemTextW(hwnd, IDC_INFO, message);
72         LoadStringW(hInstance, IDS_COPYFROM, message,
73             sizeof(message)/sizeof(message[0]));
74         SetDlgItemTextW(hwnd, IDC_COPYFROM, message);
75     }
76     if(params->DiskPromptStyle & IDF_NOBROWSE)
77         ShowWindow(GetDlgItem(hwnd, IDC_RUNDLG_BROWSE), SW_HIDE);
78 }
79 
80 /* When the user clicks in the Ok button in SetupPromptForDisk dialog
81  * if the parameters are good it copies the path from the dialog to the output buffer
82  * saves the required size for the buffer if PathRequiredSize is given
83  * returns NO_ERROR if there is no PathBuffer to copy too
84  * returns DPROMPT_BUFFERTOOSMALL if the path is too big to fit in PathBuffer
85  */
86 static void promptdisk_ok(HWND hwnd, struct promptdisk_params *params)
87 {
88     int requiredSize;
89     WCHAR aux[MAX_PATH];
90     GetWindowTextW(GetDlgItem(hwnd, IDC_PATH), aux, MAX_PATH);
91     requiredSize = strlenW(aux)+1;
92 
93     if(params->PathRequiredSize)
94     {
95         *params->PathRequiredSize = requiredSize;
96         TRACE("returning PathRequiredSize=%d\n",*params->PathRequiredSize);
97     }
98     if(!params->PathBuffer)
99     {
100         EndDialog(hwnd, NO_ERROR);
101         return;
102     }
103     if(requiredSize > params->PathBufferSize)
104     {
105         EndDialog(hwnd, DPROMPT_BUFFERTOOSMALL);
106         return;
107     }
108     strcpyW(params->PathBuffer, aux);
109     TRACE("returning PathBuffer=%s\n", debugstr_w(params->PathBuffer));
110     EndDialog(hwnd, DPROMPT_SUCCESS);
111 }
112 
113 /* When the user clicks the browse button in SetupPromptForDisk dialog
114  * it copies the path of the selected file to the dialog path field
115  */
116 static void promptdisk_browse(HWND hwnd, struct promptdisk_params *params)
117 {
118     OPENFILENAMEW ofn;
119     ZeroMemory(&ofn, sizeof(ofn));
120 
121     ofn.lStructSize = sizeof(ofn);
122     ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
123     ofn.hwndOwner = hwnd;
124     ofn.nMaxFile = MAX_PATH;
125     ofn.lpstrFile = HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(WCHAR));
126     strcpyW(ofn.lpstrFile, params->FileSought);
127 
128     if(GetOpenFileNameW(&ofn))
129     {
130         WCHAR* last_slash = strrchrW(ofn.lpstrFile, '\\');
131         if (last_slash) *last_slash = 0;
132         SetDlgItemTextW(hwnd, IDC_PATH, ofn.lpstrFile);
133     }
134     HeapFree(GetProcessHeap(), 0, ofn.lpstrFile);
135 }
136 
137 /* Handles the messages sent to the SetupPromptForDisk dialog
138 */
139 static INT_PTR CALLBACK promptdisk_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
140 {
141     switch(msg)
142     {
143         case WM_INITDIALOG:
144             promptdisk_init(hwnd, (struct promptdisk_params *)lParam);
145             return TRUE;
146         case WM_COMMAND:
147             switch(wParam)
148             {
149                 case IDOK:
150                 {
151                     struct promptdisk_params *params =
152                         (struct promptdisk_params *)GetWindowLongPtrW(hwnd, DWLP_USER);
153                     promptdisk_ok(hwnd, params);
154                     return TRUE;
155                 }
156                 case IDCANCEL:
157                     EndDialog(hwnd, DPROMPT_CANCEL);
158                     return TRUE;
159                 case IDC_RUNDLG_BROWSE:
160                 {
161                     struct promptdisk_params *params =
162                         (struct promptdisk_params *)GetWindowLongPtrW(hwnd, DWLP_USER);
163                     promptdisk_browse(hwnd, params);
164                     return TRUE;
165                 }
166             }
167     }
168     return FALSE;
169 }
170 
171 /***********************************************************************
172  *      SetupPromptForDiskA (SETUPAPI.@)
173  */
174 UINT WINAPI SetupPromptForDiskA(HWND hwndParent, PCSTR DialogTitle, PCSTR DiskName,
175         PCSTR PathToSource, PCSTR FileSought, PCSTR TagFile, DWORD DiskPromptStyle,
176         PSTR PathBuffer, DWORD PathBufferSize, PDWORD PathRequiredSize)
177 {
178     WCHAR *DialogTitleW, *DiskNameW, *PathToSourceW;
179     WCHAR *FileSoughtW, *TagFileW, PathBufferW[MAX_PATH];
180     UINT ret, length;
181 
182     TRACE("%p, %s, %s, %s, %s, %s, 0x%08x, %p, %d, %p\n", hwndParent, debugstr_a(DialogTitle),
183           debugstr_a(DiskName), debugstr_a(PathToSource), debugstr_a(FileSought),
184           debugstr_a(TagFile), DiskPromptStyle, PathBuffer, PathBufferSize,
185           PathRequiredSize);
186 
187     DialogTitleW = strdupAtoW(DialogTitle);
188     DiskNameW = strdupAtoW(DiskName);
189     PathToSourceW = strdupAtoW(PathToSource);
190     FileSoughtW = strdupAtoW(FileSought);
191     TagFileW = strdupAtoW(TagFile);
192 
193     ret = SetupPromptForDiskW(hwndParent, DialogTitleW, DiskNameW, PathToSourceW,
194             FileSoughtW, TagFileW, DiskPromptStyle, PathBufferW, MAX_PATH, PathRequiredSize);
195 
196     HeapFree(GetProcessHeap(), 0, DialogTitleW);
197     HeapFree(GetProcessHeap(), 0, DiskNameW);
198     HeapFree(GetProcessHeap(), 0, PathToSourceW);
199     HeapFree(GetProcessHeap(), 0, FileSoughtW);
200     HeapFree(GetProcessHeap(), 0, TagFileW);
201 
202     if(ret == DPROMPT_SUCCESS)
203     {
204         length = WideCharToMultiByte(CP_ACP, 0, PathBufferW, -1, NULL, 0, NULL, NULL);
205         if(PathRequiredSize) *PathRequiredSize = length;
206         if(PathBuffer)
207         {
208             if(length > PathBufferSize)
209                 return DPROMPT_BUFFERTOOSMALL;
210             WideCharToMultiByte(CP_ACP, 0, PathBufferW, -1, PathBuffer, length, NULL, NULL);
211         }
212     }
213     return ret;
214 }
215 
216 /***********************************************************************
217  *      SetupPromptForDiskW (SETUPAPI.@)
218  */
219 UINT WINAPI SetupPromptForDiskW(HWND hwndParent, PCWSTR DialogTitle, PCWSTR DiskName,
220         PCWSTR PathToSource, PCWSTR FileSought, PCWSTR TagFile, DWORD DiskPromptStyle,
221         PWSTR PathBuffer, DWORD PathBufferSize, PDWORD PathRequiredSize)
222 {
223     struct promptdisk_params params;
224     UINT ret;
225 
226     TRACE("%p, %s, %s, %s, %s, %s, 0x%08x, %p, %d, %p\n", hwndParent, debugstr_w(DialogTitle),
227           debugstr_w(DiskName), debugstr_w(PathToSource), debugstr_w(FileSought),
228           debugstr_w(TagFile), DiskPromptStyle, PathBuffer, PathBufferSize,
229           PathRequiredSize);
230 
231     if(!FileSought)
232     {
233         SetLastError(ERROR_INVALID_PARAMETER);
234         return DPROMPT_CANCEL;
235     }
236 
237     if (PathToSource && (DiskPromptStyle & IDF_CHECKFIRST))
238     {
239         static const WCHAR format[] = {'%', 's', '\\', '%', 's', '\0'};
240         WCHAR filepath[MAX_PATH];
241 
242         if (strlenW(PathToSource) + 1 + strlenW(FileSought) < sizeof(filepath))
243         {
244             snprintfW(filepath, MAX_PATH, format, PathToSource, FileSought);
245 
246             if (GetFileAttributesW(filepath) != INVALID_FILE_ATTRIBUTES)
247             {
248                 if (PathRequiredSize)
249                     *PathRequiredSize = strlenW(PathToSource) + 1;
250 
251                 if (!PathBuffer)
252                     return DPROMPT_SUCCESS;
253 
254                 if (PathBufferSize >= strlenW(PathToSource) + 1)
255                 {
256                     strcpyW(PathBuffer, PathToSource);
257                     return DPROMPT_SUCCESS;
258                 }
259                 else
260                     return DPROMPT_BUFFERTOOSMALL;
261             }
262         }
263     }
264 
265     params.DialogTitle = DialogTitle;
266     params.DiskName = DiskName;
267     params.PathToSource = PathToSource;
268     params.FileSought = FileSought;
269     params.TagFile = TagFile;
270     params.DiskPromptStyle = DiskPromptStyle;
271     params.PathBuffer = PathBuffer;
272     params.PathBufferSize = PathBufferSize;
273     params.PathRequiredSize = PathRequiredSize;
274 
275     ret = DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDPROMPTFORDISK),
276         hwndParent, promptdisk_proc, (LPARAM)&params);
277 
278     if(ret == DPROMPT_CANCEL)
279         SetLastError(ERROR_CANCELLED);
280     return ret;
281 }
282