dinput/tests: Add static asserts for arrays that have to match in size.
[wine.git] / programs / dxdiag / output.c
blob95941785c1ca2cfe1b07465e87f53b5fdab16e83
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 struct text_information_field
38 const char *field_name;
39 const WCHAR *value;
42 struct xml_information_field
44 const WCHAR *tag_name;
45 const WCHAR *value;
48 static BOOL output_text_header(HANDLE hFile, const char *caption)
50 DWORD len = strlen(caption);
51 DWORD total_len = 3 * (len + sizeof(crlf));
52 char *ptr = output_buffer;
53 DWORD bytes_written;
55 assert(total_len <= sizeof(output_buffer));
57 memset(ptr, '-', len);
58 ptr += len;
60 memcpy(ptr, crlf, sizeof(crlf));
61 ptr += sizeof(crlf);
63 memcpy(ptr, caption, len);
64 ptr += len;
66 memcpy(ptr, crlf, sizeof(crlf));
67 ptr += sizeof(crlf);
69 memset(ptr, '-', len);
70 ptr += len;
72 memcpy(ptr, crlf, sizeof(crlf));
74 return WriteFile(hFile, output_buffer, total_len, &bytes_written, NULL);
77 static BOOL output_text_field(HANDLE hFile, const char *field_name, DWORD field_width, const WCHAR *value)
79 DWORD value_lenW = lstrlenW(value);
80 DWORD value_lenA = WideCharToMultiByte(CP_ACP, 0, value, value_lenW, NULL, 0, NULL, NULL);
81 DWORD total_len = field_width + sizeof(": ") - 1 + value_lenA + sizeof(crlf);
82 char sprintf_fmt[1 + 10 + 3 + 1];
83 char *ptr = output_buffer;
84 DWORD bytes_written;
86 assert(total_len <= sizeof(output_buffer));
88 sprintf(sprintf_fmt, "%%%us: ", field_width);
89 ptr += sprintf(ptr, sprintf_fmt, field_name);
91 ptr += WideCharToMultiByte(CP_ACP, 0, value, value_lenW, ptr, value_lenA, NULL, NULL);
92 memcpy(ptr, crlf, sizeof(crlf));
94 return WriteFile(hFile, output_buffer, total_len, &bytes_written, NULL);
97 static BOOL output_crlf(HANDLE hFile)
99 DWORD bytes_written;
100 return WriteFile(hFile, crlf, sizeof(crlf), &bytes_written, NULL);
103 static inline void fill_system_text_output_table(struct dxdiag_information *dxdiag_info, struct text_information_field *fields)
105 fields[0].field_name = "Time of this report";
106 fields[0].value = dxdiag_info->system_info.szTimeEnglish;
107 fields[1].field_name = "Machine name";
108 fields[1].value = dxdiag_info->system_info.szMachineNameEnglish;
109 fields[2].field_name = "Operating System";
110 fields[2].value = dxdiag_info->system_info.szOSExLongEnglish;
111 fields[3].field_name = "Language";
112 fields[3].value = dxdiag_info->system_info.szLanguagesEnglish;
113 fields[4].field_name = "System Manufacturer";
114 fields[4].value = dxdiag_info->system_info.szSystemManufacturerEnglish;
115 fields[5].field_name = "System Model";
116 fields[5].value = dxdiag_info->system_info.szSystemModelEnglish;
117 fields[6].field_name = "BIOS";
118 fields[6].value = dxdiag_info->system_info.szBIOSEnglish;
119 fields[7].field_name = "Processor";
120 fields[7].value = dxdiag_info->system_info.szProcessorEnglish;
121 fields[8].field_name = "Memory";
122 fields[8].value = dxdiag_info->system_info.szPhysicalMemoryEnglish;
123 fields[9].field_name = "Page File";
124 fields[9].value = dxdiag_info->system_info.szPageFileEnglish;
125 fields[10].field_name = "Windows Dir";
126 fields[10].value = dxdiag_info->system_info.szWindowsDir;
127 fields[11].field_name = "DirectX Version";
128 fields[11].value = dxdiag_info->system_info.szDirectXVersionLongEnglish;
129 fields[12].field_name = "DX Setup Parameters";
130 fields[12].value = dxdiag_info->system_info.szSetupParamEnglish;
131 fields[13].field_name = "DxDiag Version";
132 fields[13].value = dxdiag_info->system_info.szDxDiagVersion;
135 static BOOL output_text_information(struct dxdiag_information *dxdiag_info, const WCHAR *filename)
137 struct information_block
139 const char *caption;
140 const size_t field_width;
141 struct text_information_field fields[50];
142 } output_table[] =
144 {"System Information", 19},
147 HANDLE hFile;
148 size_t i;
150 fill_system_text_output_table(dxdiag_info, output_table[0].fields);
152 hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
153 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
154 if (hFile == INVALID_HANDLE_VALUE)
156 WINE_ERR("File creation failed, last error %u\n", GetLastError());
157 return FALSE;
160 for (i = 0; i < ARRAY_SIZE(output_table); i++)
162 const struct text_information_field *fields = output_table[i].fields;
163 unsigned int j;
165 output_text_header(hFile, output_table[i].caption);
166 for (j = 0; fields[j].field_name; j++)
167 output_text_field(hFile, fields[j].field_name, output_table[i].field_width, fields[j].value);
168 output_crlf(hFile);
171 CloseHandle(hFile);
172 return FALSE;
175 static IXMLDOMElement *xml_create_element(IXMLDOMDocument *xmldoc, const WCHAR *name)
177 BSTR bstr = SysAllocString(name);
178 IXMLDOMElement *ret;
179 HRESULT hr;
181 if (!bstr)
182 return NULL;
184 hr = IXMLDOMDocument_createElement(xmldoc, bstr, &ret);
185 SysFreeString(bstr);
187 return SUCCEEDED(hr) ? ret : NULL;
190 static HRESULT xml_put_element_text(IXMLDOMElement *element, const WCHAR *text)
192 BSTR bstr = SysAllocString(text);
193 HRESULT hr;
195 if (!bstr)
196 return E_OUTOFMEMORY;
198 hr = IXMLDOMElement_put_text(element, bstr);
199 SysFreeString(bstr);
201 return hr;
204 static HRESULT save_xml_document(IXMLDOMDocument *xmldoc, const WCHAR *filename)
206 BSTR bstr = SysAllocString(filename);
207 VARIANT destVar;
208 HRESULT hr;
210 if (!bstr)
211 return E_OUTOFMEMORY;
213 V_VT(&destVar) = VT_BSTR;
214 V_BSTR(&destVar) = bstr;
216 hr = IXMLDOMDocument_save(xmldoc, destVar);
217 VariantClear(&destVar);
219 return hr;
222 static inline void fill_system_xml_output_table(struct dxdiag_information *dxdiag_info, struct xml_information_field *fields)
224 fields[0].tag_name = L"Time";
225 fields[0].value = dxdiag_info->system_info.szTimeEnglish;
226 fields[1].tag_name = L"MachineName";
227 fields[1].value = dxdiag_info->system_info.szMachineNameEnglish;
228 fields[2].tag_name = L"OperatingSystem";
229 fields[2].value = dxdiag_info->system_info.szOSExLongEnglish;
230 fields[3].tag_name = L"Language";
231 fields[3].value = dxdiag_info->system_info.szLanguagesEnglish;
232 fields[4].tag_name = L"SystemManufacturer";
233 fields[4].value = dxdiag_info->system_info.szSystemManufacturerEnglish;
234 fields[5].tag_name = L"SystemModel";
235 fields[5].value = dxdiag_info->system_info.szSystemModelEnglish;
236 fields[6].tag_name = L"BIOS";
237 fields[6].value = dxdiag_info->system_info.szBIOSEnglish;
238 fields[7].tag_name = L"Processor";
239 fields[7].value = dxdiag_info->system_info.szProcessorEnglish;
240 fields[8].tag_name = L"Memory";
241 fields[8].value = dxdiag_info->system_info.szPhysicalMemoryEnglish;
242 fields[9].tag_name = L"PageFile";
243 fields[9].value = dxdiag_info->system_info.szPageFileEnglish;
244 fields[10].tag_name = L"WindowsDir";
245 fields[10].value = dxdiag_info->system_info.szWindowsDir;
246 fields[11].tag_name = L"DirectXVersion";
247 fields[11].value = dxdiag_info->system_info.szDirectXVersionLongEnglish;
248 fields[12].tag_name = L"DXSetupParameters";
249 fields[12].value = dxdiag_info->system_info.szSetupParamEnglish;
250 fields[13].tag_name = L"DxDiagVersion";
251 fields[13].value = dxdiag_info->system_info.szDxDiagVersion;
252 fields[14].tag_name = L"DxDiagUnicode";
253 fields[14].value = L"1";
254 fields[15].tag_name = L"DxDiag64Bit";
255 fields[15].value = dxdiag_info->system_info.win64 ? L"1" : L"0";
258 static BOOL output_xml_information(struct dxdiag_information *dxdiag_info, const WCHAR *filename)
260 struct information_block
262 const WCHAR *tag_name;
263 struct xml_information_field fields[50];
264 } output_table[] =
266 {L"SystemInformation"},
269 IXMLDOMDocument *xmldoc = NULL;
270 IXMLDOMElement *dxdiag_element = NULL;
271 HRESULT hr;
272 size_t i;
274 fill_system_xml_output_table(dxdiag_info, output_table[0].fields);
276 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
277 &IID_IXMLDOMDocument, (void **)&xmldoc);
278 if (FAILED(hr))
280 WINE_ERR("IXMLDOMDocument instance creation failed with 0x%08x\n", hr);
281 goto error;
284 if (!(dxdiag_element = xml_create_element(xmldoc, L"DxDiag")))
285 goto error;
287 hr = IXMLDOMDocument_appendChild(xmldoc, (IXMLDOMNode *)dxdiag_element, NULL);
288 if (FAILED(hr))
289 goto error;
291 for (i = 0; i < ARRAY_SIZE(output_table); i++)
293 IXMLDOMElement *info_element = xml_create_element(xmldoc, output_table[i].tag_name);
294 const struct xml_information_field *fields = output_table[i].fields;
295 unsigned int j = 0;
297 if (!info_element)
298 goto error;
300 hr = IXMLDOMElement_appendChild(dxdiag_element, (IXMLDOMNode *)info_element, NULL);
301 if (FAILED(hr))
303 IXMLDOMElement_Release(info_element);
304 goto error;
307 for (j = 0; fields[j].tag_name; j++)
309 IXMLDOMElement *field_element = xml_create_element(xmldoc, fields[j].tag_name);
311 if (!field_element)
313 IXMLDOMElement_Release(info_element);
314 goto error;
317 hr = xml_put_element_text(field_element, fields[j].value);
318 if (FAILED(hr))
320 IXMLDOMElement_Release(field_element);
321 IXMLDOMElement_Release(info_element);
322 goto error;
325 hr = IXMLDOMElement_appendChild(info_element, (IXMLDOMNode *)field_element, NULL);
326 if (FAILED(hr))
328 IXMLDOMElement_Release(field_element);
329 IXMLDOMElement_Release(info_element);
330 goto error;
333 IXMLDOMElement_Release(field_element);
336 IXMLDOMElement_Release(info_element);
339 hr = save_xml_document(xmldoc, filename);
340 if (FAILED(hr))
341 goto error;
343 IXMLDOMElement_Release(dxdiag_element);
344 IXMLDOMDocument_Release(xmldoc);
345 return TRUE;
346 error:
347 if (dxdiag_element) IXMLDOMElement_Release(dxdiag_element);
348 if (xmldoc) IXMLDOMDocument_Release(xmldoc);
349 return FALSE;
352 static struct output_backend
354 const WCHAR filename_ext[5];
355 BOOL (*output_handler)(struct dxdiag_information *, const WCHAR *filename);
356 } output_backends[] =
358 /* OUTPUT_TEXT */
360 L".txt", output_text_information,
362 /* OUTPUT_XML */
364 L".xml", output_xml_information,
368 const WCHAR *get_output_extension(enum output_type type)
370 assert(type > OUTPUT_NONE && type <= ARRAY_SIZE(output_backends));
372 return output_backends[type - 1].filename_ext;
375 BOOL output_dxdiag_information(struct dxdiag_information *dxdiag_info, const WCHAR *filename, enum output_type type)
377 assert(type > OUTPUT_NONE && type <= ARRAY_SIZE(output_backends));
379 return output_backends[type - 1].output_handler(dxdiag_info, filename);