1 /*
2 * PROJECT: ReactOS API Test GUI
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE:
5 * PURPOSE: browse dialog implementation
6 * COPYRIGHT: Copyright 2008 Ged Murphy <gedmurphy@reactos.org>
7 *
8 */
9
10 #include <precomp.h>
11
12 #define EXE_SEARCH_DIR L"\\Debug\\testexes\\*"
13 #define IL_MAIN 0
14 #define IL_TEST 1
15
16 #define HAS_NO_CHILD 0
17 #define HAS_CHILD 1
18
19
20 static INT
GetNumberOfExesInFolder(LPWSTR lpFolder)21 GetNumberOfExesInFolder(LPWSTR lpFolder)
22 {
23 HANDLE hFind;
24 WIN32_FIND_DATAW findFileData;
25 INT numFiles = 0;
26
27 hFind = FindFirstFileW(lpFolder,
28 &findFileData);
29 if (hFind == INVALID_HANDLE_VALUE)
30 {
31 DisplayError(GetLastError());
32 return 0;
33 }
34
35 do
36 {
37 if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
38 {
39 numFiles++;
40 }
41 } while (FindNextFile(hFind, &findFileData) != 0);
42
43 return numFiles;
44 }
45
46 static INT
GetListOfTestExes(PMAIN_WND_INFO pInfo)47 GetListOfTestExes(PMAIN_WND_INFO pInfo)
48 {
49 HANDLE hFind;
50 WIN32_FIND_DATAW findFileData;
51 WCHAR szExePath[MAX_PATH];
52 LPWSTR ptr;
53 INT numFiles = 0;
54 INT len;
55
56 len = GetCurrentDirectoryW(MAX_PATH, szExePath);
57 if (!len) return 0;
58
59 wcsncat(szExePath, EXE_SEARCH_DIR, MAX_PATH - (len + 1));
60
61 numFiles = GetNumberOfExesInFolder(szExePath);
62 if (!numFiles) return 0;
63
64 pInfo->lpExeList = HeapAlloc(GetProcessHeap(),
65 0,
66 numFiles * (MAX_PATH * sizeof(WCHAR)));
67 if (!pInfo->lpExeList)
68 return 0;
69
70 hFind = FindFirstFileW(szExePath,
71 &findFileData);
72 if (hFind == INVALID_HANDLE_VALUE)
73 {
74 DisplayError(GetLastError());
75 HeapFree(GetProcessHeap(), 0, pInfo->lpExeList);
76 return 0;
77 }
78
79 /* remove the glob */
80 ptr = wcschr(szExePath, L'*');
81 if (ptr)
82 *ptr = L'\0';
83
84 /* don't modify our base pointer */
85 ptr = pInfo->lpExeList;
86
87 do
88 {
89 if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
90 {
91 /* set the path */
92 wcscpy(ptr, szExePath);
93
94 /* tag the file onto the path */
95 len = MAX_PATH - (wcslen(ptr) + 1);
96 wcsncat(ptr, findFileData.cFileName, len);
97
98 /* move the pointer along by MAX_PATH */
99 ptr += MAX_PATH;
100 }
101 } while (FindNextFile(hFind, &findFileData) != 0);
102
103 return numFiles;
104 }
105
106 static BOOL
NodeHasChild(PMAIN_WND_INFO pInfo,HTREEITEM hItem)107 NodeHasChild(PMAIN_WND_INFO pInfo,
108 HTREEITEM hItem)
109 {
110 TV_ITEM tvItem;
111
112 tvItem.hItem = hItem;
113 tvItem.mask = TVIF_CHILDREN;
114
115 (void)TreeView_GetItem(pInfo->hBrowseTV, &tvItem);
116
117 return (tvItem.cChildren == 1);
118 }
119
120 static VOID
FreeItemTag(PMAIN_WND_INFO pInfo,HTREEITEM hItem)121 FreeItemTag(PMAIN_WND_INFO pInfo,
122 HTREEITEM hItem)
123 {
124 TV_ITEM tvItem;
125
126 tvItem.hItem = hItem;
127 tvItem.mask = TVIF_PARAM;
128
129 (void)TreeView_GetItem(pInfo->hBrowseTV, &tvItem);
130
131 HeapFree(GetProcessHeap(),
132 0,
133 (PTEST_ITEM)tvItem.lParam);
134 }
135
136 static VOID
TraverseTreeView(PMAIN_WND_INFO pInfo,HTREEITEM hItem)137 TraverseTreeView(PMAIN_WND_INFO pInfo,
138 HTREEITEM hItem)
139 {
140 while (NodeHasChild(pInfo, hItem))
141 {
142 HTREEITEM hChildItem;
143
144 FreeItemTag(pInfo, hItem);
145
146 hChildItem = TreeView_GetChild(pInfo->hBrowseTV,
147 hItem);
148
149 TraverseTreeView(pInfo,
150 hChildItem);
151
152 hItem = TreeView_GetNextSibling(pInfo->hBrowseTV,
153 hItem);
154 }
155
156 if (hItem)
157 {
158 /* loop the child items and free the tags */
159 while (TRUE)
160 {
161 HTREEITEM hOldItem;
162
163 FreeItemTag(pInfo, hItem);
164 hOldItem = hItem;
165 hItem = TreeView_GetNextSibling(pInfo->hBrowseTV,
166 hItem);
167 if (hItem == NULL)
168 {
169 hItem = hOldItem;
170 break;
171 }
172 }
173
174 hItem = TreeView_GetParent(pInfo->hBrowseTV,
175 hItem);
176 }
177 }
178
179 static HTREEITEM
InsertIntoTreeView(HWND hTreeView,HTREEITEM hRoot,LPWSTR lpLabel,LPARAM Tag,INT Image,INT Child)180 InsertIntoTreeView(HWND hTreeView,
181 HTREEITEM hRoot,
182 LPWSTR lpLabel,
183 LPARAM Tag,
184 INT Image,
185 INT Child)
186 {
187 TV_ITEM tvi;
188 TV_INSERTSTRUCT tvins;
189
190 ZeroMemory(&tvi, sizeof(tvi));
191 ZeroMemory(&tvins, sizeof(tvins));
192
193 tvi.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_CHILDREN | TVIF_SELECTEDIMAGE;
194 tvi.pszText = lpLabel;
195 tvi.cchTextMax = lstrlen(lpLabel);
196 tvi.lParam = Tag;
197 tvi.iImage = Image;
198 tvi.iSelectedImage = Image;
199 tvi.cChildren = Child;
200
201 tvins.item = tvi;
202 tvins.hParent = hRoot;
203
204 return TreeView_InsertItem(hTreeView, &tvins);
205 }
206
207 static PTEST_ITEM
BuildTestItemData(LPWSTR lpName,LPWSTR lpRunCmd)208 BuildTestItemData(LPWSTR lpName,
209 LPWSTR lpRunCmd)
210 {
211 PTEST_ITEM pItem;
212
213 pItem = (PTEST_ITEM)HeapAlloc(GetProcessHeap(),
214 0,
215 sizeof(TEST_ITEM));
216 if (pItem)
217 {
218 if (lpName)
219 {
220 wcsncpy(pItem->szName, lpName, MAX_PATH);
221 }
222 if (lpRunCmd)
223 {
224 wcsncpy(pItem->szRunCmd, lpRunCmd, MAX_RUN_CMD);
225 }
226 }
227
228 return pItem;
229 }
230
231 static VOID
PopulateTreeView(PMAIN_WND_INFO pInfo)232 PopulateTreeView(PMAIN_WND_INFO pInfo)
233 {
234 HTREEITEM hRoot;
235 HIMAGELIST hImgList;
236 PTEST_ITEM pTestItem;
237 LPWSTR lpExePath;
238 LPWSTR lpTestName;
239 INT i;
240
241 pInfo->hBrowseTV = GetDlgItem(pInfo->hBrowseDlg, IDC_TREEVIEW);
242
243 (void)TreeView_DeleteAllItems(pInfo->hBrowseTV);
244
245 hImgList = InitImageList(IDI_ICON,
246 IDI_TESTS,
247 16,
248 16);
249 if (!hImgList) return;
250
251 (void)TreeView_SetImageList(pInfo->hBrowseTV,
252 hImgList,
253 TVSIL_NORMAL);
254
255 pTestItem = BuildTestItemData(L"Full", L"runall");
256
257 /* insert the root item into the tree */
258 hRoot = InsertIntoTreeView(pInfo->hBrowseTV,
259 NULL,
260 L"Full",
261 (LPARAM)pTestItem,
262 IL_MAIN,
263 HAS_CHILD);
264
265 for (i = 0; i < pInfo->numExes; i++)
266 {
267 HTREEITEM hParent;
268 LPWSTR lpStr;
269
270 lpExePath = pInfo->lpExeList + (MAX_PATH * i);
271
272 lpTestName = wcsrchr(lpExePath, L'\\');
273 if (lpTestName)
274 {
275 lpTestName++;
276
277 lpStr = wcschr(lpTestName, L'_');
278 if (lpStr)
279 {
280 //FIXME: Query the test name from the exe directly
281
282 pTestItem = BuildTestItemData(lpTestName, lpExePath);
283
284 hParent = InsertIntoTreeView(pInfo->hBrowseTV,
285 hRoot,
286 lpTestName,
287 (LPARAM)pTestItem,
288 IL_TEST,
289 HAS_CHILD);
290 }
291 }
292 }
293
294 if (hRoot)
295 {
296 TreeView_Expand(pInfo->hBrowseTV,
297 hRoot,
298 TVE_EXPAND);
299 }
300 }
301
302 static VOID
PopulateTestList(PMAIN_WND_INFO pInfo)303 PopulateTestList(PMAIN_WND_INFO pInfo)
304 {
305 pInfo->numExes = GetListOfTestExes(pInfo);
306 if (pInfo->numExes)
307 {
308 PopulateTreeView(pInfo);
309 }
310 }
311
312 static BOOL
OnInitBrowseDialog(HWND hDlg,LPARAM lParam)313 OnInitBrowseDialog(HWND hDlg,
314 LPARAM lParam)
315 {
316 PMAIN_WND_INFO pInfo;
317
318 pInfo = (PMAIN_WND_INFO)lParam;
319
320 pInfo->hBrowseDlg = hDlg;
321
322 SetWindowLongPtr(hDlg,
323 GWLP_USERDATA,
324 (LONG_PTR)pInfo);
325
326 PopulateTestList(pInfo);
327
328 return TRUE;
329 }
330
331 BOOL CALLBACK
BrowseDlgProc(HWND hDlg,UINT Message,WPARAM wParam,LPARAM lParam)332 BrowseDlgProc(HWND hDlg,
333 UINT Message,
334 WPARAM wParam,
335 LPARAM lParam)
336 {
337 PMAIN_WND_INFO pInfo;
338
339 /* Get the window context */
340 pInfo = (PMAIN_WND_INFO)GetWindowLongPtr(hDlg,
341 GWLP_USERDATA);
342 if (pInfo == NULL && Message != WM_INITDIALOG)
343 {
344 goto HandleDefaultMessage;
345 }
346
347 switch(Message)
348 {
349 case WM_INITDIALOG:
350 return OnInitBrowseDialog(hDlg, lParam);
351
352 case WM_COMMAND:
353 {
354 switch (LOWORD(wParam))
355 {
356 case IDOK:
357 {
358 TV_ITEM tvItem;
359
360 tvItem.hItem = TreeView_GetSelection(pInfo->hBrowseTV);
361 tvItem.mask = TVIF_PARAM;
362
363 if (TreeView_GetItem(pInfo->hBrowseTV, &tvItem))
364 {
365 PTEST_ITEM pItem;
366
367 pItem = (PTEST_ITEM)tvItem.lParam;
368 if (pItem)
369 CopyMemory(&pInfo->SelectedTest, pItem, sizeof(TEST_ITEM));
370
371 EndDialog(hDlg,
372 LOWORD(wParam));
373 }
374 else
375 {
376 DisplayMessage(L"Please select an item");
377 }
378
379 return TRUE;
380 }
381
382 case IDCANCEL:
383 {
384 HeapFree(GetProcessHeap(), 0, pInfo->lpExeList);
385 pInfo->lpExeList = NULL;
386
387 EndDialog(hDlg,
388 LOWORD(wParam));
389
390 return TRUE;
391 }
392 }
393
394 break;
395 }
396
397 case WM_DESTROY:
398 {
399 HTREEITEM hItem = TreeView_GetRoot(pInfo->hBrowseTV);
400
401 TraverseTreeView(pInfo, hItem);
402
403 pInfo->hBrowseDlg = NULL;
404
405 break;
406 }
407
408 HandleDefaultMessage:
409 default:
410 return FALSE;
411 }
412
413 return FALSE;
414 }
415