Sync with trunk r58033.
[reactos.git] / base / applications / dxdiag / display.c
1 /*
2 * PROJECT: ReactX Diagnosis Application
3 * LICENSE: LGPL - See COPYING in the top level directory
4 * FILE: base/applications/dxdiag/display.c
5 * PURPOSE: ReactX diagnosis display page
6 * COPYRIGHT: Copyright 2008 Johannes Anderwald
7 *
8 */
9
10 #include "precomp.h"
11 #include <d3d9.h>
12
13 BOOL
14 GetFileModifyTime(LPCWSTR pFullPath, WCHAR * szTime, int szTimeSize)
15 {
16 HANDLE hFile;
17 FILETIME AccessTime;
18 SYSTEMTIME SysTime, LocalTime;
19 UINT Length;
20 TIME_ZONE_INFORMATION TimeInfo;
21
22 hFile = CreateFileW(pFullPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
23 if (!hFile)
24 return FALSE;
25
26 if (!GetFileTime(hFile, NULL, NULL, &AccessTime))
27 {
28 CloseHandle(hFile);
29 return FALSE;
30 }
31 CloseHandle(hFile);
32
33 if(!GetTimeZoneInformation(&TimeInfo))
34 return FALSE;
35
36 if (!FileTimeToSystemTime(&AccessTime, &SysTime))
37 return FALSE;
38
39 if (!SystemTimeToTzSpecificLocalTime(&TimeInfo, &SysTime, &LocalTime))
40 return FALSE;
41
42 Length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &LocalTime, NULL, szTime, szTimeSize);
43 szTime[Length-1] = L' ';
44 return GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_FORCE24HOURFORMAT, &LocalTime, NULL, &szTime[Length], szTimeSize-Length);
45 }
46
47
48
49 static UINT WINAPI
50 DriverFilesCallback(IN PVOID Context,
51 IN UINT Notification,
52 IN UINT_PTR Param1,
53 IN UINT_PTR Param2)
54 {
55 LPCWSTR pFile;
56 LPWSTR pBuffer;
57 LPCWSTR pFullPath = (LPCWSTR)Param1;
58 WCHAR szVer[60];
59 LRESULT Length, fLength;
60 HWND * hDlgCtrls = (HWND *)Context;
61
62 if (wcsstr(pFullPath, L"\\DRIVERS\\"))
63 {
64 /* exclude files from drivers dir to have failsafe file version/date information */
65 return NO_ERROR;
66 }
67
68 pFile = wcsrchr(pFullPath, L'\\');
69 if (!pFile)
70 return NO_ERROR;
71
72 pFile++;
73 fLength = wcslen(pFile) + 1;
74
75 Length = SendMessageW(hDlgCtrls[0], WM_GETTEXTLENGTH, 0, 0) + 1;
76 pBuffer = HeapAlloc(GetProcessHeap(), 0, (Length + fLength) * sizeof(WCHAR));
77 if (!pBuffer)
78 return ERROR_OUTOFMEMORY;
79
80 Length = SendMessageW(hDlgCtrls[0], WM_GETTEXT, Length, (LPARAM)pBuffer);
81 if (Length)
82 {
83 pBuffer[Length++] = L',';
84 }
85 else
86 {
87 /* set file version */
88 if (GetFileVersion(pFullPath, szVer, sizeof(szVer)/sizeof(WCHAR)))
89 SendMessageW(hDlgCtrls[1], WM_SETTEXT, 0, (LPARAM)szVer);
90 /* set file time */
91 if (GetFileModifyTime(pFullPath, szVer, sizeof(szVer)/sizeof(WCHAR)))
92 SendMessageW(hDlgCtrls[2], WM_SETTEXT, 0, (LPARAM)szVer);
93 }
94
95 wcscpy(&pBuffer[Length], pFile);
96 SendMessageW(hDlgCtrls[0], WM_SETTEXT, 0, (LPARAM)pBuffer);
97 HeapFree(GetProcessHeap(), 0, pBuffer);
98 return NO_ERROR;
99 }
100
101 VOID
102 EnumerateDrivers(PVOID Context, HDEVINFO hList, PSP_DEVINFO_DATA pInfoData)
103 {
104 HSPFILEQ hQueue;
105 SP_DEVINSTALL_PARAMS DeviceInstallParams = {0};
106 SP_DRVINFO_DATA DriverInfoData;
107 DWORD Result;
108
109 DeviceInstallParams.cbSize = sizeof(DeviceInstallParams);
110 if (!SetupDiGetDeviceInstallParamsW(hList, pInfoData, &DeviceInstallParams))
111 return;
112
113 DeviceInstallParams.FlagsEx |= (DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
114 if (!SetupDiSetDeviceInstallParams(hList, pInfoData, &DeviceInstallParams))
115 return;
116
117 if (!SetupDiBuildDriverInfoList(hList, pInfoData, SPDIT_CLASSDRIVER))
118 return;
119
120 DriverInfoData.cbSize = sizeof(DriverInfoData);
121 if (!SetupDiEnumDriverInfoW(hList, pInfoData, SPDIT_CLASSDRIVER, 0, &DriverInfoData))
122 return;
123
124 DriverInfoData.cbSize = sizeof(DriverInfoData);
125 if (!SetupDiSetSelectedDriverW(hList, pInfoData, &DriverInfoData))
126 return;
127
128 hQueue = SetupOpenFileQueue();
129 if (hQueue == (HSPFILEQ)INVALID_HANDLE_VALUE)
130 return;
131
132 DeviceInstallParams.cbSize = sizeof(DeviceInstallParams);
133 if (!SetupDiGetDeviceInstallParamsW(hList, pInfoData, &DeviceInstallParams))
134 {
135 SetupCloseFileQueue(hQueue);
136 return;
137 }
138
139 DeviceInstallParams.FileQueue = hQueue;
140 DeviceInstallParams.Flags |= DI_NOVCP;
141
142 if (!SetupDiSetDeviceInstallParamsW(hList, pInfoData, &DeviceInstallParams))
143 {
144 SetupCloseFileQueue(hQueue);
145 return;
146 }
147
148 if(!SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES, hList, pInfoData))
149 {
150 SetupCloseFileQueue(hQueue);
151 return;
152 }
153
154
155 /* enumerate the driver files */
156 SetupScanFileQueueW(hQueue, SPQ_SCAN_USE_CALLBACK, NULL, DriverFilesCallback, Context, &Result);
157 SetupCloseFileQueue(hQueue);
158 }
159
160 static
161 void
162 SetDeviceDetails(HWND * hDlgCtrls, LPCGUID classGUID, LPGUID * deviceGUID)
163 {
164 HDEVINFO hInfo;
165 DWORD dwIndex = 0;
166 SP_DEVINFO_DATA InfoData;
167 WCHAR szText[100];
168
169 /* create the setup list */
170 hInfo = SetupDiGetClassDevsW(classGUID, NULL, NULL, DIGCF_PRESENT|DIGCF_PROFILE);
171 if (hInfo == INVALID_HANDLE_VALUE)
172 return;
173
174 do
175 {
176 ZeroMemory(&InfoData, sizeof(InfoData));
177 InfoData.cbSize = sizeof(InfoData);
178
179 if (SetupDiEnumDeviceInfo(hInfo, dwIndex, &InfoData))
180 {
181 /* set device name */
182 if (SetupDiGetDeviceRegistryPropertyW(hInfo, &InfoData, SPDRP_DEVICEDESC, NULL, (PBYTE)szText, sizeof(szText), NULL))
183 SendMessageW(hDlgCtrls[0], WM_SETTEXT, 0, (LPARAM)szText);
184
185 /* set the manufacturer name */
186 if (SetupDiGetDeviceRegistryPropertyW(hInfo, &InfoData, SPDRP_MFG, NULL, (PBYTE)szText, sizeof(szText), NULL))
187 SendMessageW(hDlgCtrls[1], WM_SETTEXT, 0, (LPARAM)szText);
188
189 /* FIXME
190 * we currently enumerate only the first adapter
191 */
192 EnumerateDrivers(&hDlgCtrls[2], hInfo, &InfoData);
193 break;
194 }
195
196 if (GetLastError() == ERROR_NO_MORE_ITEMS)
197 break;
198
199 dwIndex++;
200 }while(TRUE);
201
202 /* destroy the setup list */
203 SetupDiDestroyDeviceInfoList(hInfo);
204 }
205
206
207 static
208 BOOL
209 InitializeDialog(HWND hwndDlg, PDISPLAY_DEVICEW pDispDevice)
210 {
211 WCHAR szText[100];
212 WCHAR szFormat[30];
213 HKEY hKey;
214 HWND hDlgCtrls[5];
215 DWORD dwMemory;
216 DEVMODE DevMode;
217 IDirect3D9 * ppObj;
218 D3DADAPTER_IDENTIFIER9 Identifier;
219 HRESULT hResult;
220
221 szText[0] = L'\0';
222 ppObj = Direct3DCreate9(D3D_SDK_VERSION);
223 if (ppObj)
224 {
225 hResult = IDirect3D9_GetAdapterIdentifier(ppObj, D3DADAPTER_DEFAULT , 2/*D3DENUM_WHQL_LEVEL*/, &Identifier);
226 if (hResult == D3D_OK)
227 {
228
229 if (Identifier.WHQLLevel)
230 {
231 /* adapter is WHQL certified */
232 LoadStringW(hInst, IDS_OPTION_YES, szText, sizeof(szText)/sizeof(WCHAR));
233 }
234 else
235 {
236 LoadStringW(hInst, IDS_OPTION_NO, szText, sizeof(szText)/sizeof(WCHAR));
237 }
238 }
239 IDirect3D9_Release(ppObj);
240 }
241 else
242 {
243 LoadStringW(hInst, IDS_DEVICE_STATUS_UNKNOWN, szText, sizeof(szText)/sizeof(WCHAR));
244 }
245 szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
246 SendDlgItemMessageW(hwndDlg, IDC_STATIC_ADAPTER_LOGO, WM_SETTEXT, 0, (LPARAM)szText);
247
248 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, &pDispDevice->DeviceKey[18], 0, KEY_READ, &hKey) != ERROR_SUCCESS)
249 return FALSE;
250
251 if (GetRegValue(hKey, NULL, L"HardwareInformation.ChipType", REG_BINARY, szText, sizeof(szText)))
252 {
253 /* set chip type */
254 SendDlgItemMessageW(hwndDlg, IDC_STATIC_ADAPTER_CHIP, WM_SETTEXT, 0, (LPARAM)szText);
255 }
256
257 if (GetRegValue(hKey, NULL, L"HardwareInformation.DacType", REG_BINARY, szText, sizeof(szText)))
258 {
259 /* set DAC type */
260 SendDlgItemMessageW(hwndDlg, IDC_STATIC_ADAPTER_DAC, WM_SETTEXT, 0, (LPARAM)szText);
261 }
262
263 if (GetRegValue(hKey, NULL, L"HardwareInformation.MemorySize", REG_BINARY, (LPWSTR)&dwMemory, sizeof(dwMemory)))
264 {
265 /* set chip memory size */
266 if (dwMemory > (1048576))
267 {
268 /* buggy ATI driver requires that */
269 dwMemory /= 1048576;
270 }
271 szFormat[0] = L'\0';
272 if (LoadStringW(hInst, IDS_FORMAT_ADAPTER_MEM, szFormat, sizeof(szFormat)/sizeof(WCHAR)))
273 szFormat[(sizeof(szFormat)/sizeof(WCHAR))-1] = L'\0';
274 wsprintfW(szText, szFormat, dwMemory);
275 SendDlgItemMessageW(hwndDlg, IDC_STATIC_ADAPTER_MEM, WM_SETTEXT, 0, (LPARAM)szText);
276 }
277
278 /* retrieve current display mode */
279 DevMode.dmSize = sizeof(DEVMODE);
280 if (EnumDisplaySettingsW(pDispDevice->DeviceName, ENUM_CURRENT_SETTINGS, &DevMode))
281 {
282 szFormat[0] = L'\0';
283 if (LoadStringW(hInst, IDS_FORMAT_ADAPTER_MODE, szFormat, sizeof(szFormat)/sizeof(WCHAR)))
284 szFormat[(sizeof(szFormat)/sizeof(WCHAR))-1] = L'\0';
285 wsprintfW(szText, szFormat, DevMode.dmPelsWidth, DevMode.dmPelsHeight, DevMode.dmBitsPerPel, DevMode.dmDisplayFrequency);
286 SendDlgItemMessageW(hwndDlg, IDC_STATIC_ADAPTER_MODE, WM_SETTEXT, 0, (LPARAM)szText);
287 }
288
289 /* query attached monitor */
290 wcscpy(szText, pDispDevice->DeviceName);
291 ZeroMemory(pDispDevice, sizeof(DISPLAY_DEVICEW));
292 pDispDevice->cb = sizeof(DISPLAY_DEVICEW);
293 if (EnumDisplayDevicesW(szText, 0, pDispDevice, 0))
294 {
295 /* set monitor name */
296 SendDlgItemMessageW(hwndDlg, IDC_STATIC_ADAPTER_MONITOR, WM_SETTEXT, 0, (LPARAM)pDispDevice->DeviceString);
297 }
298
299 hDlgCtrls[0] = GetDlgItem(hwndDlg, IDC_STATIC_ADAPTER_ID);
300 hDlgCtrls[1] = GetDlgItem(hwndDlg, IDC_STATIC_ADAPTER_VENDOR);
301 hDlgCtrls[2] = GetDlgItem(hwndDlg, IDC_STATIC_ADAPTER_DRIVER);
302 hDlgCtrls[3] = GetDlgItem(hwndDlg, IDC_STATIC_ADAPTER_VERSION);
303 hDlgCtrls[4] = GetDlgItem(hwndDlg, IDC_STATIC_ADAPTER_DATE);
304
305 SetDeviceDetails(hDlgCtrls, &GUID_DEVCLASS_DISPLAY, NULL);
306 return TRUE;
307 }
308
309 void InitializeDisplayAdapters(PDXDIAG_CONTEXT pContext)
310 {
311 DISPLAY_DEVICEW DispDevice;
312 HWND * hDlgs;
313 HWND hwndDlg;
314 WCHAR szDisplay[20];
315 WCHAR szText[30];
316 DWORD dwOffset = 0;
317
318 while(TRUE)
319 {
320 ZeroMemory(&DispDevice, sizeof(DISPLAY_DEVICEW));
321 DispDevice.cb = sizeof(DISPLAY_DEVICEW);
322 if (!EnumDisplayDevicesW(NULL, pContext->NumDisplayAdapter + dwOffset, &DispDevice, 0))
323 return;
324
325 /* skip devices not attached to the desktop and mirror drivers */
326 if (!(DispDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) || (DispDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
327 {
328 dwOffset++;
329 continue;
330 }
331 if (pContext->NumDisplayAdapter)
332 hDlgs = HeapReAlloc(GetProcessHeap(), 0, pContext->hDisplayWnd, (pContext->NumDisplayAdapter + 1) * sizeof(HWND));
333 else
334 hDlgs = HeapAlloc(GetProcessHeap(), 0, (pContext->NumDisplayAdapter + 1) * sizeof(HWND));
335
336 if (!hDlgs)
337 break;
338
339 pContext->hDisplayWnd = hDlgs;
340 hwndDlg = CreateDialogParamW(hInst, MAKEINTRESOURCEW(IDD_DISPLAY_DIALOG), pContext->hMainDialog, DisplayPageWndProc, (LPARAM)pContext);
341 if (!hwndDlg)
342 break;
343
344 /* initialize the dialog */
345 InitializeDialog(hwndDlg, &DispDevice);
346
347 szDisplay[0] = L'\0';
348 LoadStringW(hInst, IDS_DISPLAY_DIALOG, szDisplay, sizeof(szDisplay)/sizeof(WCHAR));
349 szDisplay[(sizeof(szDisplay)/sizeof(WCHAR))-1] = L'\0';
350
351 wsprintfW (szText, L"%s %u", szDisplay, pContext->NumDisplayAdapter + 1);
352 InsertTabCtrlItem(GetDlgItem(pContext->hMainDialog, IDC_TAB_CONTROL), pContext->NumDisplayAdapter + 1, szText);
353
354 hDlgs[pContext->NumDisplayAdapter] = hwndDlg;
355 pContext->NumDisplayAdapter++;
356 }
357
358
359 }
360
361
362 INT_PTR CALLBACK
363 DisplayPageWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
364 {
365 RECT rect;
366 PDXDIAG_CONTEXT pContext = (PDXDIAG_CONTEXT)GetWindowLongPtr(hDlg, DWLP_USER);
367 switch (message)
368 {
369 case WM_INITDIALOG:
370 {
371 pContext = (PDXDIAG_CONTEXT) lParam;
372 SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pContext);
373 SetWindowPos(hDlg, NULL, 10, 32, 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
374 return TRUE;
375 }
376 case WM_COMMAND:
377 {
378 switch(LOWORD(wParam))
379 {
380 case IDC_BUTTON_TESTDD:
381 case IDC_BUTTON_TEST3D:
382 GetWindowRect(pContext->hMainDialog, &rect);
383 /* FIXME log result errors */
384 if (IDC_BUTTON_TESTDD == LOWORD(wParam))
385 DDTests();
386 else if (IDC_BUTTON_TEST3D == LOWORD(wParam))
387 D3DTests();
388 SetWindowPos(pContext->hMainDialog, NULL, rect.left, rect.top, rect.right, rect.bottom, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
389 break;
390 }
391 break;
392 }
393 }
394
395 return FALSE;
396 }