Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/programs/dxdiag/output.c
4388 views
1
/*
2
* DxDiag file information output
3
*
4
* Copyright 2011 Andrew Nguyen
5
*
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.
10
*
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.
15
*
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
19
*/
20
21
#define COBJMACROS
22
#include <initguid.h>
23
#include <windows.h>
24
#include <msxml2.h>
25
#include <assert.h>
26
#include <stdio.h>
27
28
#include "wine/debug.h"
29
#include "dxdiag_private.h"
30
31
WINE_DEFAULT_DEBUG_CHANNEL(dxdiag);
32
33
static char output_buffer[1024];
34
static const char crlf[2] = "\r\n";
35
36
struct text_information_field
37
{
38
const char *field_name;
39
const WCHAR *value;
40
};
41
42
struct xml_information_field
43
{
44
const WCHAR *tag_name;
45
const WCHAR *value;
46
};
47
48
static BOOL output_text_header(HANDLE hFile, const char *caption)
49
{
50
DWORD len = strlen(caption);
51
DWORD total_len = 3 * (len + sizeof(crlf));
52
char *ptr = output_buffer;
53
DWORD bytes_written;
54
55
assert(total_len <= sizeof(output_buffer));
56
57
memset(ptr, '-', len);
58
ptr += len;
59
60
memcpy(ptr, crlf, sizeof(crlf));
61
ptr += sizeof(crlf);
62
63
memcpy(ptr, caption, len);
64
ptr += len;
65
66
memcpy(ptr, crlf, sizeof(crlf));
67
ptr += sizeof(crlf);
68
69
memset(ptr, '-', len);
70
ptr += len;
71
72
memcpy(ptr, crlf, sizeof(crlf));
73
74
return WriteFile(hFile, output_buffer, total_len, &bytes_written, NULL);
75
}
76
77
static BOOL output_text_field(HANDLE hFile, const char *field_name, DWORD field_width, const WCHAR *value)
78
{
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;
85
86
assert(total_len <= sizeof(output_buffer));
87
88
sprintf(sprintf_fmt, "%%%lus: ", field_width);
89
ptr += sprintf(ptr, sprintf_fmt, field_name);
90
91
ptr += WideCharToMultiByte(CP_ACP, 0, value, value_lenW, ptr, value_lenA, NULL, NULL);
92
memcpy(ptr, crlf, sizeof(crlf));
93
94
return WriteFile(hFile, output_buffer, total_len, &bytes_written, NULL);
95
}
96
97
static BOOL output_crlf(HANDLE hFile)
98
{
99
DWORD bytes_written;
100
return WriteFile(hFile, crlf, sizeof(crlf), &bytes_written, NULL);
101
}
102
103
static inline void fill_system_text_output_table(struct dxdiag_information *dxdiag_info, struct text_information_field *fields)
104
{
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;
133
}
134
135
static BOOL output_text_information(struct dxdiag_information *dxdiag_info, const WCHAR *filename)
136
{
137
struct information_block
138
{
139
const char *caption;
140
const size_t field_width;
141
struct text_information_field fields[50];
142
} output_table[] =
143
{
144
{"System Information", 19},
145
};
146
147
HANDLE hFile;
148
size_t i;
149
150
fill_system_text_output_table(dxdiag_info, output_table[0].fields);
151
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)
155
{
156
WINE_ERR("File creation failed, last error %lu\n", GetLastError());
157
return FALSE;
158
}
159
160
for (i = 0; i < ARRAY_SIZE(output_table); i++)
161
{
162
const struct text_information_field *fields = output_table[i].fields;
163
unsigned int j;
164
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);
169
}
170
171
CloseHandle(hFile);
172
return FALSE;
173
}
174
175
static IXMLDOMElement *xml_create_element(IXMLDOMDocument *xmldoc, const WCHAR *name)
176
{
177
BSTR bstr = SysAllocString(name);
178
IXMLDOMElement *ret;
179
HRESULT hr;
180
181
if (!bstr)
182
return NULL;
183
184
hr = IXMLDOMDocument_createElement(xmldoc, bstr, &ret);
185
SysFreeString(bstr);
186
187
return SUCCEEDED(hr) ? ret : NULL;
188
}
189
190
static HRESULT xml_put_element_text(IXMLDOMElement *element, const WCHAR *text)
191
{
192
BSTR bstr = SysAllocString(text);
193
HRESULT hr;
194
195
if (!bstr)
196
return E_OUTOFMEMORY;
197
198
hr = IXMLDOMElement_put_text(element, bstr);
199
SysFreeString(bstr);
200
201
return hr;
202
}
203
204
static HRESULT save_xml_document(IXMLDOMDocument *xmldoc, const WCHAR *filename)
205
{
206
BSTR bstr = SysAllocString(filename);
207
VARIANT destVar;
208
HRESULT hr;
209
210
if (!bstr)
211
return E_OUTOFMEMORY;
212
213
V_VT(&destVar) = VT_BSTR;
214
V_BSTR(&destVar) = bstr;
215
216
hr = IXMLDOMDocument_save(xmldoc, destVar);
217
VariantClear(&destVar);
218
219
return hr;
220
}
221
222
static inline void fill_system_xml_output_table(struct dxdiag_information *dxdiag_info, struct xml_information_field *fields)
223
{
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";
256
}
257
258
static BOOL output_xml_information(struct dxdiag_information *dxdiag_info, const WCHAR *filename)
259
{
260
struct information_block
261
{
262
const WCHAR *tag_name;
263
struct xml_information_field fields[50];
264
} output_table[] =
265
{
266
{L"SystemInformation"},
267
};
268
269
IXMLDOMDocument *xmldoc = NULL;
270
IXMLDOMElement *dxdiag_element = NULL;
271
HRESULT hr;
272
size_t i;
273
274
fill_system_xml_output_table(dxdiag_info, output_table[0].fields);
275
276
hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
277
&IID_IXMLDOMDocument, (void **)&xmldoc);
278
if (FAILED(hr))
279
{
280
WINE_ERR("IXMLDOMDocument instance creation failed with 0x%08lx\n", hr);
281
goto error;
282
}
283
284
if (!(dxdiag_element = xml_create_element(xmldoc, L"DxDiag")))
285
goto error;
286
287
hr = IXMLDOMDocument_appendChild(xmldoc, (IXMLDOMNode *)dxdiag_element, NULL);
288
if (FAILED(hr))
289
goto error;
290
291
for (i = 0; i < ARRAY_SIZE(output_table); i++)
292
{
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;
296
297
if (!info_element)
298
goto error;
299
300
hr = IXMLDOMElement_appendChild(dxdiag_element, (IXMLDOMNode *)info_element, NULL);
301
if (FAILED(hr))
302
{
303
IXMLDOMElement_Release(info_element);
304
goto error;
305
}
306
307
for (j = 0; fields[j].tag_name; j++)
308
{
309
IXMLDOMElement *field_element = xml_create_element(xmldoc, fields[j].tag_name);
310
311
if (!field_element)
312
{
313
IXMLDOMElement_Release(info_element);
314
goto error;
315
}
316
317
hr = xml_put_element_text(field_element, fields[j].value);
318
if (FAILED(hr))
319
{
320
IXMLDOMElement_Release(field_element);
321
IXMLDOMElement_Release(info_element);
322
goto error;
323
}
324
325
hr = IXMLDOMElement_appendChild(info_element, (IXMLDOMNode *)field_element, NULL);
326
if (FAILED(hr))
327
{
328
IXMLDOMElement_Release(field_element);
329
IXMLDOMElement_Release(info_element);
330
goto error;
331
}
332
333
IXMLDOMElement_Release(field_element);
334
}
335
336
IXMLDOMElement_Release(info_element);
337
}
338
339
hr = save_xml_document(xmldoc, filename);
340
if (FAILED(hr))
341
goto error;
342
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;
350
}
351
352
static struct output_backend
353
{
354
const WCHAR filename_ext[5];
355
BOOL (*output_handler)(struct dxdiag_information *, const WCHAR *filename);
356
} output_backends[] =
357
{
358
/* OUTPUT_TEXT */
359
{
360
L".txt", output_text_information,
361
},
362
/* OUTPUT_XML */
363
{
364
L".xml", output_xml_information,
365
},
366
};
367
368
const WCHAR *get_output_extension(enum output_type type)
369
{
370
assert(type > OUTPUT_NONE && type <= ARRAY_SIZE(output_backends));
371
372
return output_backends[type - 1].filename_ext;
373
}
374
375
BOOL output_dxdiag_information(struct dxdiag_information *dxdiag_info, const WCHAR *filename, enum output_type type)
376
{
377
assert(type > OUTPUT_NONE && type <= ARRAY_SIZE(output_backends));
378
379
return output_backends[type - 1].output_handler(dxdiag_info, filename);
380
}
381
382