📄 main.c
字号:
/*
* Wine Conformance Test EXE
*
* Copyright 2003, 2004 Jakob Eriksson (for Solid Form Sweden AB)
* Copyright 2003 Dimitrie O. Paun
* Copyright 2003 Ferenc Wagner
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* This program is dedicated to Anna Lindh,
* Swedish Minister of Foreign Affairs.
* Anna was murdered September 11, 2003.
*
*/
#include "config.h"
#include "wine/port.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <windows.h>
#include "winetest.h"
#include "resource.h"
struct wine_test
{
char *name;
int resource;
int subtest_count;
char **subtests;
char *exename;
};
struct rev_info
{
const char* file;
const char* rev;
};
char *tag = NULL;
static struct wine_test *wine_tests;
static struct rev_info *rev_infos = NULL;
static const char whitespace[] = " \t\r\n";
static int running_under_wine (void)
{
HMODULE module = GetModuleHandleA("ntdll.dll");
if (!module) return 0;
return (GetProcAddress(module, "wine_server_call") != NULL);
}
static int running_on_visible_desktop (void)
{
HWND desktop;
HMODULE huser32 = GetModuleHandle("user32.dll");
FARPROC pGetProcessWindowStation = GetProcAddress(huser32, "GetProcessWindowStation");
FARPROC pGetUserObjectInformationA = GetProcAddress(huser32, "GetUserObjectInformationA");
desktop = GetDesktopWindow();
if (!GetWindowLongPtrW(desktop, GWLP_WNDPROC)) /* Win9x */
return IsWindowVisible(desktop);
if (pGetProcessWindowStation && pGetUserObjectInformationA)
{
DWORD len;
HWINSTA wstation;
USEROBJECTFLAGS uoflags;
wstation = (HWINSTA)pGetProcessWindowStation();
assert(pGetUserObjectInformationA(wstation, UOI_FLAGS, &uoflags, sizeof(uoflags), &len));
return (uoflags.dwFlags & WSF_VISIBLE) != 0;
}
return IsWindowVisible(desktop);
}
static void print_version (void)
{
OSVERSIONINFOEX ver;
BOOL ext;
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if (!(ext = GetVersionEx ((OSVERSIONINFO *) &ver)))
{
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!GetVersionEx ((OSVERSIONINFO *) &ver))
report (R_FATAL, "Can't get OS version.");
}
xprintf (" bRunningUnderWine=%d\n", running_under_wine ());
xprintf (" bRunningOnVisibleDesktop=%d\n", running_on_visible_desktop ());
xprintf (" dwMajorVersion=%ld\n dwMinorVersion=%ld\n"
" dwBuildNumber=%ld\n PlatformId=%ld\n szCSDVersion=%s\n",
ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
ver.dwPlatformId, ver.szCSDVersion);
if (!ext) return;
xprintf (" wServicePackMajor=%d\n wServicePackMinor=%d\n"
" wSuiteMask=%d\n wProductType=%d\n wReserved=%d\n",
ver.wServicePackMajor, ver.wServicePackMinor, ver.wSuiteMask,
ver.wProductType, ver.wReserved);
}
static inline int is_dot_dir(const char* x)
{
return ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))));
}
static void remove_dir (const char *dir)
{
HANDLE hFind;
WIN32_FIND_DATA wfd;
char path[MAX_PATH];
size_t dirlen = strlen (dir);
/* Make sure the directory exists before going further */
memcpy (path, dir, dirlen);
strcpy (path + dirlen++, "\\*");
hFind = FindFirstFile (path, &wfd);
if (hFind == INVALID_HANDLE_VALUE) return;
do {
char *lp = wfd.cFileName;
if (!lp[0]) lp = wfd.cAlternateFileName; /* ? FIXME not (!lp) ? */
if (is_dot_dir (lp)) continue;
strcpy (path + dirlen, lp);
if (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
remove_dir(path);
else if (!DeleteFile (path))
report (R_WARNING, "Can't delete file %s: error %d",
path, GetLastError ());
} while (FindNextFile (hFind, &wfd));
FindClose (hFind);
if (!RemoveDirectory (dir))
report (R_WARNING, "Can't remove directory %s: error %d",
dir, GetLastError ());
}
static const char* get_test_source_file(const char* test, const char* subtest)
{
static const char* special_dirs[][2] = {
{ "gdi32", "gdi"}, { "kernel32", "kernel" },
{ "msacm32", "msacm" },
{ "user32", "user" }, { "winspool.drv", "winspool" },
{ "ws2_32", "winsock" }, { 0, 0 }
};
static char buffer[MAX_PATH];
int i;
for (i = 0; special_dirs[i][0]; i++) {
if (strcmp(test, special_dirs[i][0]) == 0) {
test = special_dirs[i][1];
break;
}
}
snprintf(buffer, sizeof(buffer), "dlls/%s/tests/%s.c", test, subtest);
return buffer;
}
static const char* get_file_rev(const char* file)
{
const struct rev_info* rev;
for(rev = rev_infos; rev->file; rev++) {
if (strcmp(rev->file, file) == 0) return rev->rev;
}
return "-";
}
static void extract_rev_infos (void)
{
char revinfo[256], *p;
int size = 0, i;
unsigned int len;
HMODULE module = GetModuleHandle (NULL);
for (i = 0; TRUE; i++) {
if (i >= size) {
size += 100;
rev_infos = xrealloc (rev_infos, size * sizeof (*rev_infos));
}
memset(rev_infos + i, 0, sizeof(rev_infos[i]));
len = LoadStringA (module, REV_INFO+i, revinfo, sizeof(revinfo));
if (len == 0) break; /* end of revision info */
if (len >= sizeof(revinfo) - 1)
report (R_FATAL, "Revision info too long.");
if(!(p = strrchr(revinfo, ':')))
report (R_FATAL, "Revision info malformed (i=%d)", i);
*p = 0;
rev_infos[i].file = strdup(revinfo);
rev_infos[i].rev = strdup(p + 1);
}
}
static void* extract_rcdata (int id, int type, DWORD* size)
{
HRSRC rsrc;
HGLOBAL hdl;
LPVOID addr;
if (!(rsrc = FindResource (NULL, (LPTSTR)id, MAKEINTRESOURCE(type))) ||
!(*size = SizeofResource (0, rsrc)) ||
!(hdl = LoadResource (0, rsrc)) ||
!(addr = LockResource (hdl)))
return NULL;
return addr;
}
/* Fills in the name and exename fields */
static void
extract_test (struct wine_test *test, const char *dir, int id)
{
BYTE* code;
DWORD size;
FILE* fout;
int strlen, bufflen = 128;
char *exepos;
code = extract_rcdata (id, TESTRES, &size);
if (!code) report (R_FATAL, "Can't find test resource %d: %d",
id, GetLastError ());
test->name = xmalloc (bufflen);
while ((strlen = LoadStringA (NULL, id, test->name, bufflen))
== bufflen - 1) {
bufflen *= 2;
test->name = xrealloc (test->name, bufflen);
}
if (!strlen) report (R_FATAL, "Can't read name of test %d.", id);
test->exename = strmake (NULL, "%s/%s", dir, test->name);
exepos = strstr (test->name, "_test.exe");
if (!exepos) report (R_FATAL, "Not an .exe file: %s", test->name);
*exepos = 0;
test->name = xrealloc (test->name, exepos - test->name + 1);
report (R_STEP, "Extracting: %s", test->name);
if (!(fout = fopen (test->exename, "wb")) ||
(fwrite (code, size, 1, fout) != 1) ||
fclose (fout)) report (R_FATAL, "Failed to write file %s.",
test->exename);
}
/* Run a command for MS milliseconds. If OUT != NULL, also redirect
stdout to there.
Return the exit status, -2 if can't create process or the return
value of WaitForSingleObject.
*/
static int
run_ex (char *cmd, const char *out, DWORD ms)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
int fd, oldstdout = -1;
DWORD wait, status;
GetStartupInfo (&si);
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW;
if (out) {
fd = open (out, O_WRONLY | O_CREAT, 0666);
if (-1 == fd)
report (R_FATAL, "Can't open '%s': %d", out, errno);
oldstdout = dup (1);
if (-1 == oldstdout)
report (R_FATAL, "Can't save stdout: %d", errno);
if (-1 == dup2 (fd, 1))
report (R_FATAL, "Can't redirect stdout: %d", errno);
close (fd);
}
if (!CreateProcessA (NULL, cmd, NULL, NULL, TRUE, 0,
NULL, NULL, &si, &pi)) {
status = -2;
} else {
CloseHandle (pi.hThread);
wait = WaitForSingleObject (pi.hProcess, ms);
if (wait == WAIT_OBJECT_0) {
GetExitCodeProcess (pi.hProcess, &status);
} else {
switch (wait) {
case WAIT_FAILED:
report (R_ERROR, "Wait for '%s' failed: %d", cmd,
GetLastError ());
break;
case WAIT_TIMEOUT:
report (R_ERROR, "Process '%s' timed out.", cmd);
break;
default:
report (R_ERROR, "Wait returned %d", wait);
}
status = wait;
if (!TerminateProcess (pi.hProcess, 257))
report (R_ERROR, "TerminateProcess failed: %d",
GetLastError ());
wait = WaitForSingleObject (pi.hProcess, 5000);
switch (wait) {
case WAIT_FAILED:
report (R_ERROR,
"Wait for termination of '%s' failed: %d",
cmd, GetLastError ());
break;
case WAIT_OBJECT_0:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -