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