main.c 5.86 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * 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>
23 24
#include <dxdiag.h>

25
#include "wine/debug.h"
26
#include "wine/unicode.h"
27

28 29
#include "dxdiag_private.h"

30 31
WINE_DEFAULT_DEBUG_CHANNEL(dxdiag);

32 33
HINSTANCE hInstance;

34 35 36
struct command_line_info
{
    WCHAR outfile[MAX_PATH];
37
    enum output_type output_type;
38 39 40 41 42
    BOOL whql_check;
};

static void usage(void)
{
43 44 45 46 47 48 49 50
    WCHAR title[MAX_STRING_LEN];
    WCHAR usage[MAX_STRING_LEN];

    LoadStringW(hInstance, STRING_DXDIAG_TOOL, title, sizeof(title)/sizeof(WCHAR));
    LoadStringW(hInstance, STRING_USAGE, usage, sizeof(usage)/sizeof(WCHAR));

    MessageBoxW(NULL, usage, title, MB_OK | MB_ICONWARNING);

51 52 53
    ExitProcess(0);
}

54
static BOOL process_file_name(const WCHAR *cmdline, enum output_type output_type, WCHAR *filename, size_t filename_len)
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
{
    const WCHAR *endptr;
    size_t len;

    /* Skip any intervening spaces. */
    while (*cmdline == ' ')
        cmdline++;

    /* Ignore filename quoting, if any. */
    if (*cmdline == '"' && (endptr = strrchrW(cmdline, '"')))
    {
        /* Reject a string with only one quote. */
        if (cmdline == endptr)
            return FALSE;

        cmdline++;
    }
    else
        endptr = cmdline + strlenW(cmdline);

    len = endptr - cmdline;
    if (len == 0 || len >= filename_len)
        return FALSE;

    memcpy(filename, cmdline, len * sizeof(WCHAR));
    filename[len] = '\0';

82
    /* Append an extension appropriate for the output type if the filename does not have one. */
83
    if (!strrchrW(filename, '.'))
84 85 86 87 88 89 90 91 92
    {
        const WCHAR *filename_ext = get_output_extension(output_type);

        if (len + strlenW(filename_ext) >= filename_len)
            return FALSE;

        strcatW(filename, filename_ext);
    }

93 94 95
    return TRUE;
}

96
/*
97
    Process options [/WHQL:ON|OFF][/X outfile|/T outfile]
98 99
    Returns TRUE if options were present, FALSE otherwise
    Only one of /X and /T is allowed, /WHQL must come before /X and /T,
100 101 102 103 104 105
    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.
106 107
*/

108
static BOOL process_command_line(const WCHAR *cmdline, struct command_line_info *info)
109
{
110 111 112 113 114
    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};

    info->whql_check = FALSE;
115
    info->output_type = OUTPUT_NONE;
116 117 118

    while (*cmdline)
    {
119
        /* Skip whitespace before arg */
120 121 122 123 124
        while (*cmdline == ' ')
            cmdline++;

        /* If no option is specified, treat the command line as a filename. */
        if (*cmdline != '-' && *cmdline != '/')
125 126 127 128 129
        {
            info->output_type = OUTPUT_TEXT;
            return process_file_name(cmdline, OUTPUT_TEXT, info->outfile,
                                     sizeof(info->outfile)/sizeof(WCHAR));
        }
130 131 132 133 134

        cmdline++;

        switch (*cmdline)
        {
135
        case 'T':
136
        case 't':
137 138 139
            info->output_type = OUTPUT_TEXT;
            return process_file_name(cmdline + 1, OUTPUT_TEXT, info->outfile,
                                     sizeof(info->outfile)/sizeof(WCHAR));
140
        case 'X':
141
        case 'x':
142 143 144
            info->output_type = OUTPUT_XML;
            return process_file_name(cmdline + 1, OUTPUT_XML, info->outfile,
                                     sizeof(info->outfile)/sizeof(WCHAR));
145 146
        case 'W':
        case 'w':
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
            if (strncmpiW(cmdline, whql_colonW, 5))
                return FALSE;

            cmdline += 5;

            if (!strncmpiW(cmdline, offW, 3))
            {
                info->whql_check = FALSE;
                cmdline += 2;
            }
            else if (!strncmpiW(cmdline, onW, 2))
            {
                info->whql_check = TRUE;
                cmdline++;
            }
            else
                return FALSE;

165
            break;
166 167
        default:
            return FALSE;
168
        }
169 170

        cmdline++;
171
    }
172 173

    return TRUE;
174 175
}

176
int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cmdshow)
177
{
178
    struct command_line_info info;
179
    struct dxdiag_information *dxdiag_info;
180

181 182
    hInstance = hInst;

183 184 185 186
    if (!process_command_line(cmdline, &info))
        usage();

    WINE_TRACE("WHQL check: %s\n", info.whql_check ? "TRUE" : "FALSE");
187 188 189 190
    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));

191 192
    CoInitialize(NULL);

193 194 195 196
    dxdiag_info = collect_dxdiag_information(info.whql_check);
    if (!dxdiag_info)
    {
        WINE_ERR("DxDiag information collection failed\n");
197
        CoUninitialize();
198 199 200
        return 1;
    }

201
    if (info.output_type != OUTPUT_NONE)
202
        output_dxdiag_information(dxdiag_info, info.outfile, info.output_type);
203 204
    else
        WINE_FIXME("Information dialog is not implemented\n");
205

206 207
    free_dxdiag_information(dxdiag_info);

208
    CoUninitialize();
209 210
    return 0;
}