Release 4.20.
[wine.git] / programs / dxdiag / output.c
blob50240fb286088f591e9f7c340aac946e99be74d8
1 /*
2 * DxDiag file information output
4 * Copyright 2011 Andrew Nguyen
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 #define COBJMACROS
22 #include <initguid.h>
23 #include <windows.h>
24 #include <msxml2.h>
25 #include <assert.h>
26 #include <stdio.h>
28 #include "wine/debug.h"
29 #include "dxdiag_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(dxdiag);
33 static char output_buffer[1024];
34 static const char crlf[2] = "\r\n";
36 static const WCHAR DxDiag[] = {'D','x','D','i','a','g',0};
38 static const WCHAR SystemInformation[] = {'S','y','s','t','e','m','I','n','f','o','r','m','a','t','i','o','n',0};
39 static const WCHAR Time[] = {'T','i','m','e',0};
40 static const WCHAR MachineName[] = {'M','a','c','h','i','n','e','N','a','m','e',0};
41 static const WCHAR OperatingSystem[] = {'O','p','e','r','a','t','i','n','g','S','y','s','t','e','m',0};
42 static const WCHAR Language[] = {'L','a','n','g','u','a','g','e',0};
43 static const WCHAR SystemManufacturer[] = {'S','y','s','t','e','m','M','a','n','u','f','a','c','t','u','r','e','r',0};
44 static const WCHAR SystemModel[] = {'S','y','s','t','e','m','M','o','d','e','l',0};
45 static const WCHAR BIOS[] = {'B','I','O','S',0};
46 static const WCHAR Processor[] = {'P','r','o','c','e','s','s','o','r',0};
47 static const WCHAR Memory[] = {'M','e','m','o','r','y',0};
48 static const WCHAR PageFile[] = {'P','a','g','e','F','i','l','e',0};
49 static const WCHAR WindowsDir[] = {'W','i','n','d','o','w','s','D','i','r',0};
50 static const WCHAR DirectXVersion[] = {'D','i','r','e','c','t','X','V','e','r','s','i','o','n',0};
51 static const WCHAR DXSetupParameters[] = {'D','X','S','e','t','u','p','P','a','r','a','m','e','t','e','r','s',0};
52 static const WCHAR DxDiagVersion[] = {'D','x','D','i','a','g','V','e','r','s','i','o','n',0};
53 static const WCHAR DxDiagUnicode[] = {'D','x','D','i','a','g','U','n','i','c','o','d','e',0};
54 static const WCHAR DxDiag64Bit[] = {'D','x','D','i','a','g','6','4','B','i','t',0};
56 struct text_information_field
58 const char *field_name;
59 const WCHAR *value;
62 struct xml_information_field
64 const WCHAR *tag_name;
65 const WCHAR *value;
68 static BOOL output_text_header(HANDLE hFile, const char *caption)
70 DWORD len = strlen(caption);
71 DWORD total_len = 3 * (len + sizeof(crlf));
72 char *ptr = output_buffer;
73 DWORD bytes_written;
75 assert(total_len <= sizeof(output_buffer));
77 memset(ptr, '-', len);
78 ptr += len;
80 memcpy(ptr, crlf, sizeof(crlf));
81 ptr += sizeof(crlf);
83 memcpy(ptr, caption, len);
84 ptr += len;
86 memcpy(ptr, crlf, sizeof(crlf));
87 ptr += sizeof(crlf);
89 memset(ptr, '-', len);
90 ptr += len;
92 memcpy(ptr, crlf, sizeof(crlf));
94 return WriteFile(hFile, output_buffer, total_len, &bytes_written, NULL);
97 static BOOL output_text_field(HANDLE hFile, const char *field_name, DWORD field_width, const WCHAR *value)
99 DWORD value_lenW = lstrlenW(value);
100 DWORD value_lenA = WideCharToMultiByte(CP_ACP, 0, value, value_lenW, NULL, 0, NULL, NULL);
101 DWORD total_len = field_width + sizeof(": ") - 1 + value_lenA + sizeof(crlf);
102 char sprintf_fmt[1 + 10 + 3 + 1];
103 char *ptr = output_buffer;
104 DWORD bytes_written;
106 assert(total_len <= sizeof(output_buffer));
108 sprintf(sprintf_fmt, "%%%us: ", field_width);
109 ptr += sprintf(ptr, sprintf_fmt, field_name);
111 ptr += WideCharToMultiByte(CP_ACP, 0, value, value_lenW, ptr, value_lenA, NULL, NULL);
112 memcpy(ptr, crlf, sizeof(crlf));
114 return WriteFile(hFile, output_buffer, total_len, &bytes_written, NULL);
117 static BOOL output_crlf(HANDLE hFile)
119 DWORD bytes_written;
120 return WriteFile(hFile, crlf, sizeof(crlf), &bytes_written, NULL);
123 static inline void fill_system_text_output_table(struct dxdiag_information *dxdiag_info, struct text_information_field *fields)
125 fields[0].field_name = "Time of this report";
126 fields[0].value = dxdiag_info->system_info.szTimeEnglish;
127 fields[1].field_name = "Machine name";
128 fields[1].value = dxdiag_info->system_info.szMachineNameEnglish;
129 fields[2].field_name = "Operating System";
130 fields[2].value = dxdiag_info->system_info.szOSExLongEnglish;
131 fields[3].field_name = "Language";
132 fields[3].value = dxdiag_info->system_info.szLanguagesEnglish;
133 fields[4].field_name = "System Manufacturer";
134 fields[4].value = dxdiag_info->system_info.szSystemManufacturerEnglish;
135 fields[5].field_name = "System Model";
136 fields[5].value = dxdiag_info->system_info.szSystemModelEnglish;
137 fields[6].field_name = "BIOS";
138 fields[6].value = dxdiag_info->system_info.szBIOSEnglish;
139 fields[7].field_name = "Processor";
140 fields[7].value = dxdiag_info->system_info.szProcessorEnglish;
141 fields[8].field_name = "Memory";
142 fields[8].value = dxdiag_info->system_info.szPhysicalMemoryEnglish;
143 fields[9].field_name = "Page File";
144 fields[9].value = dxdiag_info->system_info.szPageFileEnglish;
145 fields[10].field_name = "Windows Dir";
146 fields[10].value = dxdiag_info->system_info.szWindowsDir;
147 fields[11].field_name = "DirectX Version";
148 fields[11].value = dxdiag_info->system_info.szDirectXVersionLongEnglish;
149 fields[12].field_name = "DX Setup Parameters";
150 fields[12].value = dxdiag_info->system_info.szSetupParamEnglish;
151 fields[13].field_name = "DxDiag Version";
152 fields[13].value = dxdiag_info->system_info.szDxDiagVersion;
155 static BOOL output_text_information(struct dxdiag_information *dxdiag_info, const WCHAR *filename)
157 struct information_block
159 const char *caption;
160 const size_t field_width;
161 struct text_information_field fields[50];
162 } output_table[] =
164 {"System Information", 19},
167 HANDLE hFile;
168 size_t i;
170 fill_system_text_output_table(dxdiag_info, output_table[0].fields);
172 hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
173 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
174 if (hFile == INVALID_HANDLE_VALUE)
176 WINE_ERR("File creation failed, last error %u\n", GetLastError());
177 return FALSE;
180 for (i = 0; i < ARRAY_SIZE(output_table); i++)
182 const struct text_information_field *fields = output_table[i].fields;
183 unsigned int j;
185 output_text_header(hFile, output_table[i].caption);
186 for (j = 0; fields[j].field_name; j++)
187 output_text_field(hFile, fields[j].field_name, output_table[i].field_width, fields[j].value);
188 output_crlf(hFile);
191 CloseHandle(hFile);
192 return FALSE;
195 static IXMLDOMElement *xml_create_element(IXMLDOMDocument *xmldoc, const WCHAR *name)
197 BSTR bstr = SysAllocString(name);
198 IXMLDOMElement *ret;
199 HRESULT hr;
201 if (!bstr)
202 return NULL;
204 hr = IXMLDOMDocument_createElement(xmldoc, bstr, &ret);
205 SysFreeString(bstr);
207 return SUCCEEDED(hr) ? ret : NULL;
210 static HRESULT xml_put_element_text(IXMLDOMElement *element, const WCHAR *text)
212 BSTR bstr = SysAllocString(text);
213 HRESULT hr;
215 if (!bstr)
216 return E_OUTOFMEMORY;
218 hr = IXMLDOMElement_put_text(element, bstr);
219 SysFreeString(bstr);
221 return hr;
224 static HRESULT save_xml_document(IXMLDOMDocument *xmldoc, const WCHAR *filename)
226 BSTR bstr = SysAllocString(filename);
227 VARIANT destVar;
228 HRESULT hr;
230 if (!bstr)
231 return E_OUTOFMEMORY;
233 V_VT(&destVar) = VT_BSTR;
234 V_BSTR(&destVar) = bstr;
236 hr = IXMLDOMDocument_save(xmldoc, destVar);
237 VariantClear(&destVar);
239 return hr;
242 static inline void fill_system_xml_output_table(struct dxdiag_information *dxdiag_info, struct xml_information_field *fields)
244 static const WCHAR zeroW[] = {'0',0};
245 static const WCHAR oneW[] = {'1',0};
247 fields[0].tag_name = Time;
248 fields[0].value = dxdiag_info->system_info.szTimeEnglish;
249 fields[1].tag_name = MachineName;
250 fields[1].value = dxdiag_info->system_info.szMachineNameEnglish;
251 fields[2].tag_name = OperatingSystem;
252 fields[2].value = dxdiag_info->system_info.szOSExLongEnglish;
253 fields[3].tag_name = Language;
254 fields[3].value = dxdiag_info->system_info.szLanguagesEnglish;
255 fields[4].tag_name = SystemManufacturer;
256 fields[4].value = dxdiag_info->system_info.szSystemManufacturerEnglish;
257 fields[5].tag_name = SystemModel;
258 fields[5].value = dxdiag_info->system_info.szSystemModelEnglish;
259 fields[6].tag_name = BIOS;
260 fields[6].value = dxdiag_info->system_info.szBIOSEnglish;
261 fields[7].tag_name = Processor;
262 fields[7].value = dxdiag_info->system_info.szProcessorEnglish;
263 fields[8].tag_name = Memory;
264 fields[8].value = dxdiag_info->system_info.szPhysicalMemoryEnglish;
265 fields[9].tag_name = PageFile;
266 fields[9].value = dxdiag_info->system_info.szPageFileEnglish;
267 fields[10].tag_name = WindowsDir;
268 fields[10].value = dxdiag_info->system_info.szWindowsDir;
269 fields[11].tag_name = DirectXVersion;
270 fields[11].value = dxdiag_info->system_info.szDirectXVersionLongEnglish;
271 fields[12].tag_name = DXSetupParameters;
272 fields[12].value = dxdiag_info->system_info.szSetupParamEnglish;
273 fields[13].tag_name = DxDiagVersion;
274 fields[13].value = dxdiag_info->system_info.szDxDiagVersion;
275 fields[14].tag_name = DxDiagUnicode;
276 fields[14].value = oneW;
277 fields[15].tag_name = DxDiag64Bit;
278 fields[15].value = dxdiag_info->system_info.win64 ? oneW : zeroW;
281 static BOOL output_xml_information(struct dxdiag_information *dxdiag_info, const WCHAR *filename)
283 struct information_block
285 const WCHAR *tag_name;
286 struct xml_information_field fields[50];
287 } output_table[] =
289 {SystemInformation},
292 IXMLDOMDocument *xmldoc = NULL;
293 IXMLDOMElement *dxdiag_element = NULL;
294 HRESULT hr;
295 size_t i;
297 fill_system_xml_output_table(dxdiag_info, output_table[0].fields);
299 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
300 &IID_IXMLDOMDocument, (void **)&xmldoc);
301 if (FAILED(hr))
303 WINE_ERR("IXMLDOMDocument instance creation failed with 0x%08x\n", hr);
304 goto error;
307 if (!(dxdiag_element = xml_create_element(xmldoc, DxDiag)))
308 goto error;
310 hr = IXMLDOMDocument_appendChild(xmldoc, (IXMLDOMNode *)dxdiag_element, NULL);
311 if (FAILED(hr))
312 goto error;
314 for (i = 0; i < ARRAY_SIZE(output_table); i++)
316 IXMLDOMElement *info_element = xml_create_element(xmldoc, output_table[i].tag_name);
317 const struct xml_information_field *fields = output_table[i].fields;
318 unsigned int j = 0;
320 if (!info_element)
321 goto error;
323 hr = IXMLDOMElement_appendChild(dxdiag_element, (IXMLDOMNode *)info_element, NULL);
324 if (FAILED(hr))
326 IXMLDOMElement_Release(info_element);
327 goto error;
330 for (j = 0; fields[j].tag_name; j++)
332 IXMLDOMElement *field_element = xml_create_element(xmldoc, fields[j].tag_name);
334 if (!field_element)
336 IXMLDOMElement_Release(info_element);
337 goto error;
340 hr = xml_put_element_text(field_element, fields[j].value);
341 if (FAILED(hr))
343 IXMLDOMElement_Release(field_element);
344 IXMLDOMElement_Release(info_element);
345 goto error;
348 hr = IXMLDOMElement_appendChild(info_element, (IXMLDOMNode *)field_element, NULL);
349 if (FAILED(hr))
351 IXMLDOMElement_Release(field_element);
352 IXMLDOMElement_Release(info_element);
353 goto error;
356 IXMLDOMElement_Release(field_element);
359 IXMLDOMElement_Release(info_element);
362 hr = save_xml_document(xmldoc, filename);
363 if (FAILED(hr))
364 goto error;
366 IXMLDOMElement_Release(dxdiag_element);
367 IXMLDOMDocument_Release(xmldoc);
368 return TRUE;
369 error:
370 if (dxdiag_element) IXMLDOMElement_Release(dxdiag_element);
371 if (xmldoc) IXMLDOMDocument_Release(xmldoc);
372 return FALSE;
375 static struct output_backend
377 const WCHAR filename_ext[5];
378 BOOL (*output_handler)(struct dxdiag_information *, const WCHAR *filename);
379 } output_backends[] =
381 /* OUTPUT_TEXT */
383 {'.','t','x','t',0},
384 output_text_information,
386 /* OUTPUT_XML */
388 {'.','x','m','l',0},
389 output_xml_information,
393 const WCHAR *get_output_extension(enum output_type type)
395 assert(type > OUTPUT_NONE && type <= ARRAY_SIZE(output_backends));
397 return output_backends[type - 1].filename_ext;
400 BOOL output_dxdiag_information(struct dxdiag_information *dxdiag_info, const WCHAR *filename, enum output_type type)
402 assert(type > OUTPUT_NONE && type <= ARRAY_SIZE(output_backends));
404 return output_backends[type - 1].output_handler(dxdiag_info, filename);