2009-08-24 18:18:26 +02:00
|
|
|
/*
|
|
|
|
* DxDiag Implementation
|
|
|
|
*
|
|
|
|
* Copyright 2009 Austin English
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
|
|
#include <windows.h>
|
2011-06-14 15:02:05 +02:00
|
|
|
#include <dxdiag.h>
|
|
|
|
|
2009-08-26 22:38:02 +02:00
|
|
|
#include "wine/debug.h"
|
2011-06-14 15:01:37 +02:00
|
|
|
#include "dxdiag_private.h"
|
|
|
|
|
2009-08-26 22:38:02 +02:00
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(dxdiag);
|
|
|
|
|
2011-06-14 15:01:45 +02:00
|
|
|
HINSTANCE hInstance;
|
|
|
|
|
2011-06-13 14:13:12 +02:00
|
|
|
struct command_line_info
|
|
|
|
{
|
|
|
|
WCHAR outfile[MAX_PATH];
|
2011-06-14 15:01:37 +02:00
|
|
|
enum output_type output_type;
|
2011-06-13 14:13:12 +02:00
|
|
|
BOOL whql_check;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void usage(void)
|
|
|
|
{
|
2011-06-14 15:01:45 +02:00
|
|
|
WCHAR title[MAX_STRING_LEN];
|
|
|
|
WCHAR usage[MAX_STRING_LEN];
|
|
|
|
|
2018-08-21 23:10:19 +02:00
|
|
|
LoadStringW(hInstance, STRING_DXDIAG_TOOL, title, ARRAY_SIZE(title));
|
|
|
|
LoadStringW(hInstance, STRING_USAGE, usage, ARRAY_SIZE(usage));
|
2011-06-14 15:01:45 +02:00
|
|
|
|
|
|
|
MessageBoxW(NULL, usage, title, MB_OK | MB_ICONWARNING);
|
|
|
|
|
2011-06-13 14:13:12 +02:00
|
|
|
ExitProcess(0);
|
|
|
|
}
|
|
|
|
|
2011-06-14 15:01:37 +02:00
|
|
|
static BOOL process_file_name(const WCHAR *cmdline, enum output_type output_type, WCHAR *filename, size_t filename_len)
|
2011-06-13 14:13:12 +02:00
|
|
|
{
|
|
|
|
const WCHAR *endptr;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
/* Skip any intervening spaces. */
|
|
|
|
while (*cmdline == ' ')
|
|
|
|
cmdline++;
|
|
|
|
|
|
|
|
/* Ignore filename quoting, if any. */
|
2019-04-29 11:52:43 +02:00
|
|
|
if (*cmdline == '"' && (endptr = wcsrchr(cmdline, '"')))
|
2011-06-13 14:13:12 +02:00
|
|
|
{
|
|
|
|
/* Reject a string with only one quote. */
|
|
|
|
if (cmdline == endptr)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
cmdline++;
|
|
|
|
}
|
|
|
|
else
|
2019-04-29 11:52:43 +02:00
|
|
|
endptr = cmdline + lstrlenW(cmdline);
|
2011-06-13 14:13:12 +02:00
|
|
|
|
|
|
|
len = endptr - cmdline;
|
|
|
|
if (len == 0 || len >= filename_len)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
memcpy(filename, cmdline, len * sizeof(WCHAR));
|
|
|
|
filename[len] = '\0';
|
|
|
|
|
2011-06-14 15:01:37 +02:00
|
|
|
/* Append an extension appropriate for the output type if the filename does not have one. */
|
2019-04-29 11:52:43 +02:00
|
|
|
if (!wcsrchr(filename, '.'))
|
2011-06-14 15:01:37 +02:00
|
|
|
{
|
|
|
|
const WCHAR *filename_ext = get_output_extension(output_type);
|
|
|
|
|
2019-04-29 11:52:43 +02:00
|
|
|
if (len + lstrlenW(filename_ext) >= filename_len)
|
2011-06-14 15:01:37 +02:00
|
|
|
return FALSE;
|
|
|
|
|
2019-04-29 11:52:43 +02:00
|
|
|
lstrcatW(filename, filename_ext);
|
2011-06-14 15:01:37 +02:00
|
|
|
}
|
|
|
|
|
2011-06-13 14:13:12 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2009-08-26 22:38:02 +02:00
|
|
|
/*
|
2011-06-13 14:13:12 +02:00
|
|
|
Process options [/WHQL:ON|OFF][/X outfile|/T outfile]
|
2009-08-26 22:38:02 +02:00
|
|
|
Returns TRUE if options were present, FALSE otherwise
|
|
|
|
Only one of /X and /T is allowed, /WHQL must come before /X and /T,
|
2011-06-13 14:13:12 +02:00
|
|
|
and the rest of the command line after /X or /T is interpreted as a
|
|
|
|
filename. If a non-option portion of the command line is encountered,
|
|
|
|
dxdiag assumes that the string is a filename for the /T option.
|
|
|
|
|
|
|
|
Native does not interpret quotes, but quotes are parsed here because of how
|
|
|
|
Wine handles the command line.
|
2009-08-26 22:38:02 +02:00
|
|
|
*/
|
|
|
|
|
2011-06-13 14:13:12 +02:00
|
|
|
static BOOL process_command_line(const WCHAR *cmdline, struct command_line_info *info)
|
2009-08-26 22:38:02 +02:00
|
|
|
{
|
2011-06-13 14:13:12 +02:00
|
|
|
static const WCHAR whql_colonW[] = {'w','h','q','l',':',0};
|
|
|
|
static const WCHAR offW[] = {'o','f','f',0};
|
|
|
|
static const WCHAR onW[] = {'o','n',0};
|
2017-12-08 21:15:39 +01:00
|
|
|
static const WCHAR dontskipW[] = {'d','o','n','t','s','k','i','p',0};
|
2011-06-13 14:13:12 +02:00
|
|
|
|
|
|
|
info->whql_check = FALSE;
|
2011-06-14 15:01:37 +02:00
|
|
|
info->output_type = OUTPUT_NONE;
|
2011-06-13 14:13:12 +02:00
|
|
|
|
|
|
|
while (*cmdline)
|
|
|
|
{
|
2009-08-26 22:38:02 +02:00
|
|
|
/* Skip whitespace before arg */
|
2011-06-13 14:13:12 +02:00
|
|
|
while (*cmdline == ' ')
|
|
|
|
cmdline++;
|
|
|
|
|
|
|
|
/* If no option is specified, treat the command line as a filename. */
|
|
|
|
if (*cmdline != '-' && *cmdline != '/')
|
2011-06-14 15:01:37 +02:00
|
|
|
{
|
|
|
|
info->output_type = OUTPUT_TEXT;
|
|
|
|
return process_file_name(cmdline, OUTPUT_TEXT, info->outfile,
|
2018-08-21 23:10:19 +02:00
|
|
|
ARRAY_SIZE(info->outfile));
|
2011-06-14 15:01:37 +02:00
|
|
|
}
|
2011-06-13 14:13:12 +02:00
|
|
|
|
|
|
|
cmdline++;
|
|
|
|
|
|
|
|
switch (*cmdline)
|
|
|
|
{
|
2009-08-26 22:38:02 +02:00
|
|
|
case 'T':
|
2011-06-13 14:13:12 +02:00
|
|
|
case 't':
|
2011-06-14 15:01:37 +02:00
|
|
|
info->output_type = OUTPUT_TEXT;
|
|
|
|
return process_file_name(cmdline + 1, OUTPUT_TEXT, info->outfile,
|
2018-08-21 23:10:19 +02:00
|
|
|
ARRAY_SIZE(info->outfile));
|
2009-08-26 22:38:02 +02:00
|
|
|
case 'X':
|
2011-06-13 14:13:12 +02:00
|
|
|
case 'x':
|
2011-06-14 15:01:37 +02:00
|
|
|
info->output_type = OUTPUT_XML;
|
|
|
|
return process_file_name(cmdline + 1, OUTPUT_XML, info->outfile,
|
2018-08-21 23:10:19 +02:00
|
|
|
ARRAY_SIZE(info->outfile));
|
2009-08-26 22:38:02 +02:00
|
|
|
case 'W':
|
|
|
|
case 'w':
|
2019-04-29 11:52:43 +02:00
|
|
|
if (wcsnicmp(cmdline, whql_colonW, 5))
|
2011-06-13 14:13:12 +02:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
cmdline += 5;
|
|
|
|
|
2019-04-29 11:52:43 +02:00
|
|
|
if (!wcsnicmp(cmdline, offW, 3))
|
2011-06-13 14:13:12 +02:00
|
|
|
{
|
|
|
|
info->whql_check = FALSE;
|
|
|
|
cmdline += 2;
|
|
|
|
}
|
2019-04-29 11:52:43 +02:00
|
|
|
else if (!wcsnicmp(cmdline, onW, 2))
|
2011-06-13 14:13:12 +02:00
|
|
|
{
|
|
|
|
info->whql_check = TRUE;
|
|
|
|
cmdline++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
|
2009-08-26 22:38:02 +02:00
|
|
|
break;
|
2017-12-08 21:15:39 +01:00
|
|
|
|
|
|
|
case 'd':
|
|
|
|
case 'D':
|
2019-04-29 11:52:43 +02:00
|
|
|
if (wcsnicmp(cmdline, dontskipW, 8))
|
2017-12-08 21:15:39 +01:00
|
|
|
return FALSE;
|
|
|
|
cmdline += 8;
|
|
|
|
break;
|
|
|
|
|
2011-06-13 14:13:12 +02:00
|
|
|
default:
|
|
|
|
return FALSE;
|
2009-08-26 22:38:02 +02:00
|
|
|
}
|
2011-06-13 14:13:12 +02:00
|
|
|
|
|
|
|
cmdline++;
|
2009-08-26 22:38:02 +02:00
|
|
|
}
|
2011-06-13 14:13:12 +02:00
|
|
|
|
|
|
|
return TRUE;
|
2009-08-26 22:38:02 +02:00
|
|
|
}
|
|
|
|
|
2009-08-26 22:40:40 +02:00
|
|
|
int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cmdshow)
|
2009-08-24 18:18:26 +02:00
|
|
|
{
|
2011-06-13 14:13:12 +02:00
|
|
|
struct command_line_info info;
|
2011-06-14 15:01:51 +02:00
|
|
|
struct dxdiag_information *dxdiag_info;
|
2011-06-13 14:13:12 +02:00
|
|
|
|
2011-06-14 15:01:45 +02:00
|
|
|
hInstance = hInst;
|
|
|
|
|
2011-06-13 14:13:12 +02:00
|
|
|
if (!process_command_line(cmdline, &info))
|
|
|
|
usage();
|
|
|
|
|
|
|
|
WINE_TRACE("WHQL check: %s\n", info.whql_check ? "TRUE" : "FALSE");
|
2011-06-14 15:01:37 +02:00
|
|
|
WINE_TRACE("Output type: %d\n", info.output_type);
|
|
|
|
if (info.output_type != OUTPUT_NONE)
|
|
|
|
WINE_TRACE("Output filename: %s\n", debugstr_output_type(info.output_type));
|
|
|
|
|
2011-06-14 15:02:05 +02:00
|
|
|
CoInitialize(NULL);
|
|
|
|
|
2011-06-14 15:01:51 +02:00
|
|
|
dxdiag_info = collect_dxdiag_information(info.whql_check);
|
|
|
|
if (!dxdiag_info)
|
|
|
|
{
|
|
|
|
WINE_ERR("DxDiag information collection failed\n");
|
2011-06-14 15:02:05 +02:00
|
|
|
CoUninitialize();
|
2011-06-14 15:01:51 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-06-14 15:01:37 +02:00
|
|
|
if (info.output_type != OUTPUT_NONE)
|
2011-06-14 15:01:51 +02:00
|
|
|
output_dxdiag_information(dxdiag_info, info.outfile, info.output_type);
|
2011-06-14 15:01:37 +02:00
|
|
|
else
|
|
|
|
WINE_FIXME("Information dialog is not implemented\n");
|
2009-08-26 22:38:02 +02:00
|
|
|
|
2011-06-14 15:01:51 +02:00
|
|
|
free_dxdiag_information(dxdiag_info);
|
|
|
|
|
2011-06-14 15:02:05 +02:00
|
|
|
CoUninitialize();
|
2009-08-24 18:18:26 +02:00
|
|
|
return 0;
|
|
|
|
}
|