output.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  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. #define COBJMACROS
  21. #include <initguid.h>
  22. #include <windows.h>
  23. #include <msxml2.h>
  24. #include <assert.h>
  25. #include <stdio.h>
  26. #include "wine/debug.h"
  27. #include "dxdiag_private.h"
  28. WINE_DEFAULT_DEBUG_CHANNEL(dxdiag);
  29. static char output_buffer[1024];
  30. static const char crlf[2] = "\r\n";
  31. struct text_information_field
  32. {
  33. const char *field_name;
  34. const WCHAR *value;
  35. };
  36. struct xml_information_field
  37. {
  38. const WCHAR *tag_name;
  39. const WCHAR *value;
  40. };
  41. static BOOL output_text_header(HANDLE hFile, const char *caption)
  42. {
  43. DWORD len = strlen(caption);
  44. DWORD total_len = 3 * (len + sizeof(crlf));
  45. char *ptr = output_buffer;
  46. DWORD bytes_written;
  47. assert(total_len <= sizeof(output_buffer));
  48. memset(ptr, '-', len);
  49. ptr += len;
  50. memcpy(ptr, crlf, sizeof(crlf));
  51. ptr += sizeof(crlf);
  52. memcpy(ptr, caption, len);
  53. ptr += len;
  54. memcpy(ptr, crlf, sizeof(crlf));
  55. ptr += sizeof(crlf);
  56. memset(ptr, '-', len);
  57. ptr += len;
  58. memcpy(ptr, crlf, sizeof(crlf));
  59. return WriteFile(hFile, output_buffer, total_len, &bytes_written, NULL);
  60. }
  61. static BOOL output_text_field(HANDLE hFile, const char *field_name, DWORD field_width, const WCHAR *value)
  62. {
  63. DWORD value_lenW = lstrlenW(value);
  64. DWORD value_lenA = WideCharToMultiByte(CP_ACP, 0, value, value_lenW, NULL, 0, NULL, NULL);
  65. DWORD total_len = field_width + sizeof(": ") - 1 + value_lenA + sizeof(crlf);
  66. char sprintf_fmt[1 + 10 + 3 + 1];
  67. char *ptr = output_buffer;
  68. DWORD bytes_written;
  69. assert(total_len <= sizeof(output_buffer));
  70. sprintf(sprintf_fmt, "%%%us: ", field_width);
  71. ptr += sprintf(ptr, sprintf_fmt, field_name);
  72. ptr += WideCharToMultiByte(CP_ACP, 0, value, value_lenW, ptr, value_lenA, NULL, NULL);
  73. memcpy(ptr, crlf, sizeof(crlf));
  74. return WriteFile(hFile, output_buffer, total_len, &bytes_written, NULL);
  75. }
  76. static BOOL output_crlf(HANDLE hFile)
  77. {
  78. DWORD bytes_written;
  79. return WriteFile(hFile, crlf, sizeof(crlf), &bytes_written, NULL);
  80. }
  81. static inline void fill_system_text_output_table(struct dxdiag_information *dxdiag_info, struct text_information_field *fields)
  82. {
  83. fields[0].field_name = "Time of this report";
  84. fields[0].value = dxdiag_info->system_info.szTimeEnglish;
  85. fields[1].field_name = "Machine name";
  86. fields[1].value = dxdiag_info->system_info.szMachineNameEnglish;
  87. fields[2].field_name = "Operating System";
  88. fields[2].value = dxdiag_info->system_info.szOSExLongEnglish;
  89. fields[3].field_name = "Language";
  90. fields[3].value = dxdiag_info->system_info.szLanguagesEnglish;
  91. fields[4].field_name = "System Manufacturer";
  92. fields[4].value = dxdiag_info->system_info.szSystemManufacturerEnglish;
  93. fields[5].field_name = "System Model";
  94. fields[5].value = dxdiag_info->system_info.szSystemModelEnglish;
  95. fields[6].field_name = "BIOS";
  96. fields[6].value = dxdiag_info->system_info.szBIOSEnglish;
  97. fields[7].field_name = "Processor";
  98. fields[7].value = dxdiag_info->system_info.szProcessorEnglish;
  99. fields[8].field_name = "Memory";
  100. fields[8].value = dxdiag_info->system_info.szPhysicalMemoryEnglish;
  101. fields[9].field_name = "Page File";
  102. fields[9].value = dxdiag_info->system_info.szPageFileEnglish;
  103. fields[10].field_name = "Windows Dir";
  104. fields[10].value = dxdiag_info->system_info.szWindowsDir;
  105. fields[11].field_name = "DirectX Version";
  106. fields[11].value = dxdiag_info->system_info.szDirectXVersionLongEnglish;
  107. fields[12].field_name = "DX Setup Parameters";
  108. fields[12].value = dxdiag_info->system_info.szSetupParamEnglish;
  109. fields[13].field_name = "DxDiag Version";
  110. fields[13].value = dxdiag_info->system_info.szDxDiagVersion;
  111. }
  112. static BOOL output_text_information(struct dxdiag_information *dxdiag_info, const WCHAR *filename)
  113. {
  114. struct information_block
  115. {
  116. const char *caption;
  117. const size_t field_width;
  118. struct text_information_field fields[50];
  119. } output_table[] =
  120. {
  121. {"System Information", 19},
  122. };
  123. HANDLE hFile;
  124. size_t i;
  125. fill_system_text_output_table(dxdiag_info, output_table[0].fields);
  126. hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
  127. NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  128. if (hFile == INVALID_HANDLE_VALUE)
  129. {
  130. WINE_ERR("File creation failed, last error %u\n", GetLastError());
  131. return FALSE;
  132. }
  133. for (i = 0; i < ARRAY_SIZE(output_table); i++)
  134. {
  135. const struct text_information_field *fields = output_table[i].fields;
  136. unsigned int j;
  137. output_text_header(hFile, output_table[i].caption);
  138. for (j = 0; fields[j].field_name; j++)
  139. output_text_field(hFile, fields[j].field_name, output_table[i].field_width, fields[j].value);
  140. output_crlf(hFile);
  141. }
  142. CloseHandle(hFile);
  143. return FALSE;
  144. }
  145. static IXMLDOMElement *xml_create_element(IXMLDOMDocument *xmldoc, const WCHAR *name)
  146. {
  147. BSTR bstr = SysAllocString(name);
  148. IXMLDOMElement *ret;
  149. HRESULT hr;
  150. if (!bstr)
  151. return NULL;
  152. hr = IXMLDOMDocument_createElement(xmldoc, bstr, &ret);
  153. SysFreeString(bstr);
  154. return SUCCEEDED(hr) ? ret : NULL;
  155. }
  156. static HRESULT xml_put_element_text(IXMLDOMElement *element, const WCHAR *text)
  157. {
  158. BSTR bstr = SysAllocString(text);
  159. HRESULT hr;
  160. if (!bstr)
  161. return E_OUTOFMEMORY;
  162. hr = IXMLDOMElement_put_text(element, bstr);
  163. SysFreeString(bstr);
  164. return hr;
  165. }
  166. static HRESULT save_xml_document(IXMLDOMDocument *xmldoc, const WCHAR *filename)
  167. {
  168. BSTR bstr = SysAllocString(filename);
  169. VARIANT destVar;
  170. HRESULT hr;
  171. if (!bstr)
  172. return E_OUTOFMEMORY;
  173. V_VT(&destVar) = VT_BSTR;
  174. V_BSTR(&destVar) = bstr;
  175. hr = IXMLDOMDocument_save(xmldoc, destVar);
  176. VariantClear(&destVar);
  177. return hr;
  178. }
  179. static inline void fill_system_xml_output_table(struct dxdiag_information *dxdiag_info, struct xml_information_field *fields)
  180. {
  181. fields[0].tag_name = L"Time";
  182. fields[0].value = dxdiag_info->system_info.szTimeEnglish;
  183. fields[1].tag_name = L"MachineName";
  184. fields[1].value = dxdiag_info->system_info.szMachineNameEnglish;
  185. fields[2].tag_name = L"OperatingSystem";
  186. fields[2].value = dxdiag_info->system_info.szOSExLongEnglish;
  187. fields[3].tag_name = L"Language";
  188. fields[3].value = dxdiag_info->system_info.szLanguagesEnglish;
  189. fields[4].tag_name = L"SystemManufacturer";
  190. fields[4].value = dxdiag_info->system_info.szSystemManufacturerEnglish;
  191. fields[5].tag_name = L"SystemModel";
  192. fields[5].value = dxdiag_info->system_info.szSystemModelEnglish;
  193. fields[6].tag_name = L"BIOS";
  194. fields[6].value = dxdiag_info->system_info.szBIOSEnglish;
  195. fields[7].tag_name = L"Processor";
  196. fields[7].value = dxdiag_info->system_info.szProcessorEnglish;
  197. fields[8].tag_name = L"Memory";
  198. fields[8].value = dxdiag_info->system_info.szPhysicalMemoryEnglish;
  199. fields[9].tag_name = L"PageFile";
  200. fields[9].value = dxdiag_info->system_info.szPageFileEnglish;
  201. fields[10].tag_name = L"WindowsDir";
  202. fields[10].value = dxdiag_info->system_info.szWindowsDir;
  203. fields[11].tag_name = L"DirectXVersion";
  204. fields[11].value = dxdiag_info->system_info.szDirectXVersionLongEnglish;
  205. fields[12].tag_name = L"DXSetupParameters";
  206. fields[12].value = dxdiag_info->system_info.szSetupParamEnglish;
  207. fields[13].tag_name = L"DxDiagVersion";
  208. fields[13].value = dxdiag_info->system_info.szDxDiagVersion;
  209. fields[14].tag_name = L"DxDiagUnicode";
  210. fields[14].value = L"1";
  211. fields[15].tag_name = L"DxDiag64Bit";
  212. fields[15].value = dxdiag_info->system_info.win64 ? L"1" : L"0";
  213. }
  214. static BOOL output_xml_information(struct dxdiag_information *dxdiag_info, const WCHAR *filename)
  215. {
  216. struct information_block
  217. {
  218. const WCHAR *tag_name;
  219. struct xml_information_field fields[50];
  220. } output_table[] =
  221. {
  222. {L"SystemInformation"},
  223. };
  224. IXMLDOMDocument *xmldoc = NULL;
  225. IXMLDOMElement *dxdiag_element = NULL;
  226. HRESULT hr;
  227. size_t i;
  228. fill_system_xml_output_table(dxdiag_info, output_table[0].fields);
  229. hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
  230. &IID_IXMLDOMDocument, (void **)&xmldoc);
  231. if (FAILED(hr))
  232. {
  233. WINE_ERR("IXMLDOMDocument instance creation failed with 0x%08x\n", hr);
  234. goto error;
  235. }
  236. if (!(dxdiag_element = xml_create_element(xmldoc, L"DxDiag")))
  237. goto error;
  238. hr = IXMLDOMDocument_appendChild(xmldoc, (IXMLDOMNode *)dxdiag_element, NULL);
  239. if (FAILED(hr))
  240. goto error;
  241. for (i = 0; i < ARRAY_SIZE(output_table); i++)
  242. {
  243. IXMLDOMElement *info_element = xml_create_element(xmldoc, output_table[i].tag_name);
  244. const struct xml_information_field *fields = output_table[i].fields;
  245. unsigned int j = 0;
  246. if (!info_element)
  247. goto error;
  248. hr = IXMLDOMElement_appendChild(dxdiag_element, (IXMLDOMNode *)info_element, NULL);
  249. if (FAILED(hr))
  250. {
  251. IXMLDOMElement_Release(info_element);
  252. goto error;
  253. }
  254. for (j = 0; fields[j].tag_name; j++)
  255. {
  256. IXMLDOMElement *field_element = xml_create_element(xmldoc, fields[j].tag_name);
  257. if (!field_element)
  258. {
  259. IXMLDOMElement_Release(info_element);
  260. goto error;
  261. }
  262. hr = xml_put_element_text(field_element, fields[j].value);
  263. if (FAILED(hr))
  264. {
  265. IXMLDOMElement_Release(field_element);
  266. IXMLDOMElement_Release(info_element);
  267. goto error;
  268. }
  269. hr = IXMLDOMElement_appendChild(info_element, (IXMLDOMNode *)field_element, NULL);
  270. if (FAILED(hr))
  271. {
  272. IXMLDOMElement_Release(field_element);
  273. IXMLDOMElement_Release(info_element);
  274. goto error;
  275. }
  276. IXMLDOMElement_Release(field_element);
  277. }
  278. IXMLDOMElement_Release(info_element);
  279. }
  280. hr = save_xml_document(xmldoc, filename);
  281. if (FAILED(hr))
  282. goto error;
  283. IXMLDOMElement_Release(dxdiag_element);
  284. IXMLDOMDocument_Release(xmldoc);
  285. return TRUE;
  286. error:
  287. if (dxdiag_element) IXMLDOMElement_Release(dxdiag_element);
  288. if (xmldoc) IXMLDOMDocument_Release(xmldoc);
  289. return FALSE;
  290. }
  291. static struct output_backend
  292. {
  293. const WCHAR filename_ext[5];
  294. BOOL (*output_handler)(struct dxdiag_information *, const WCHAR *filename);
  295. } output_backends[] =
  296. {
  297. /* OUTPUT_TEXT */
  298. {
  299. L".txt", output_text_information,
  300. },
  301. /* OUTPUT_XML */
  302. {
  303. L".xml", output_xml_information,
  304. },
  305. };
  306. const WCHAR *get_output_extension(enum output_type type)
  307. {
  308. assert(type > OUTPUT_NONE && type <= ARRAY_SIZE(output_backends));
  309. return output_backends[type - 1].filename_ext;
  310. }
  311. BOOL output_dxdiag_information(struct dxdiag_information *dxdiag_info, const WCHAR *filename, enum output_type type)
  312. {
  313. assert(type > OUTPUT_NONE && type <= ARRAY_SIZE(output_backends));
  314. return output_backends[type - 1].output_handler(dxdiag_info, filename);
  315. }