module.c 14.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Unit tests for module/DLL/library API
 *
 * Copyright (c) 2004 Eric Pouech
 *
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20 21 22 23
 */

#include "wine/test.h"
#include <windows.h>

24 25
static BOOL is_unicode_enabled = TRUE;

26
static BOOL cmpStrAW(const char* a, const WCHAR* b, DWORD lenA, DWORD lenB)
27 28 29
{
    WCHAR       aw[1024];

30 31 32
    DWORD len = MultiByteToWideChar( AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0,
                                     a, lenA, aw, sizeof(aw) / sizeof(aw[0]) );
    if (len != lenB) return FALSE;
33 34 35 36 37 38 39 40
    return memcmp(aw, b, len * sizeof(WCHAR)) == 0;
}

static void testGetModuleFileName(const char* name)
{
    HMODULE     hMod;
    char        bufA[MAX_PATH];
    WCHAR       bufW[MAX_PATH];
41
    DWORD       len1A, len1W = 0, len2A, len2W = 0;
42 43 44 45 46 47 48

    hMod = (name) ? GetModuleHandle(name) : NULL;

    /* first test, with enough space in buffer */
    memset(bufA, '-', sizeof(bufA));
    len1A = GetModuleFileNameA(hMod, bufA, sizeof(bufA));
    ok(len1A > 0, "Getting module filename for handle %p\n", hMod);
49 50 51 52 53 54 55 56

    if (is_unicode_enabled)
    {
        memset(bufW, '-', sizeof(bufW));
        len1W = GetModuleFileNameW(hMod, bufW, sizeof(bufW) / sizeof(WCHAR));
        ok(len1W > 0, "Getting module filename for handle %p\n", hMod);
    }

57
    ok(len1A == strlen(bufA), "Unexpected length of GetModuleFilenameA (%d/%d)\n", len1A, lstrlenA(bufA));
58 59 60

    if (is_unicode_enabled)
    {
61
        ok(len1W == lstrlenW(bufW), "Unexpected length of GetModuleFilenameW (%d/%d)\n", len1W, lstrlenW(bufW));
62 63
        ok(cmpStrAW(bufA, bufW, len1A, len1W), "Comparing GetModuleFilenameAW results\n");
    }
64 65 66 67 68

    /* second test with a buffer too small */
    memset(bufA, '-', sizeof(bufA));
    len2A = GetModuleFileNameA(hMod, bufA, len1A / 2);
    ok(len2A > 0, "Getting module filename for handle %p\n", hMod);
69 70 71 72 73 74 75

    if (is_unicode_enabled)
    {
        memset(bufW, '-', sizeof(bufW));
        len2W = GetModuleFileNameW(hMod, bufW, len1W / 2);
        ok(len2W > 0, "Getting module filename for handle %p\n", hMod);
        ok(cmpStrAW(bufA, bufW, len2A, len2W), "Comparing GetModuleFilenameAW results with buffer too small\n" );
76
        ok(len1W / 2 == len2W, "Correct length in GetModuleFilenameW with buffer too small (%d/%d)\n", len1W / 2, len2W);
77 78
    }

79 80
    ok(len1A / 2 == len2A || 
       len1A / 2 == len2A + 1, /* Win9x */
81
       "Correct length in GetModuleFilenameA with buffer too small (%d/%d)\n", len1A / 2, len2A);
82 83 84 85 86 87 88 89
}

static void testGetModuleFileName_Wrong(void)
{
    char        bufA[MAX_PATH];
    WCHAR       bufW[MAX_PATH];

    /* test wrong handle */
90 91 92 93 94 95
    if (is_unicode_enabled)
    {
        bufW[0] = '*';
        ok(GetModuleFileNameW((void*)0xffffffff, bufW, sizeof(bufW) / sizeof(WCHAR)) == 0, "Unexpected success in module handle\n");
        ok(bufW[0] == '*', "When failing, buffer shouldn't be written to\n");
    }
96 97 98

    bufA[0] = '*';
    ok(GetModuleFileNameA((void*)0xffffffff, bufA, sizeof(bufA)) == 0, "Unexpected success in module handle\n");
99 100 101
    ok(bufA[0] == '*' ||
       bufA[0] == 0 /* Win9x */,
       "When failing, buffer shouldn't be written to\n");
102 103
}

104 105
static void testLoadLibraryA(void)
{
106
    HMODULE hModule, hModule1;
107 108 109
    FARPROC fp;

    SetLastError(0xdeadbeef);
110 111
    hModule = LoadLibraryA("kernel32.dll");
    ok( hModule != NULL, "kernel32.dll should be loadable\n");
112
    ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %d\n", GetLastError());
113

114 115
    fp = GetProcAddress(hModule, "CreateFileA");
    ok( fp != NULL, "CreateFileA should be there\n");
116
    ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %d\n", GetLastError());
117

118 119 120 121 122 123
    SetLastError(0xdeadbeef);
    hModule1 = LoadLibraryA("kernel32   ");
    /* Only winNT does this */
    if (GetLastError() != ERROR_DLL_NOT_FOUND)
    {
        ok( hModule1 != NULL, "\"kernel32   \" should be loadable\n");
124
        ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %d\n", GetLastError());
125 126 127
        ok( hModule == hModule1, "Loaded wrong module\n");
        FreeLibrary(hModule1);
    }
128 129 130
    FreeLibrary(hModule);
}

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
static void testNestedLoadLibraryA(void)
{
    static const char dllname[] = "shell32.dll";
    char path1[MAX_PATH], path2[MAX_PATH];
    HMODULE hModule1, hModule2, hModule3;

    /* This is not really a Windows conformance test, but more a Wine
     * regression test. Wine's builtin dlls can be loaded from multiple paths,
     * and this test tries to make sure that Wine does not get confused and
     * really unloads the Unix .so file at the right time. Failure to do so
     * will result in the dll being unloadable.
     * This test must be done with a dll that can be unloaded, which means:
     * - it must not already be loaded
     * - it must not have a 16-bit counterpart
     */
    GetWindowsDirectory(path1, sizeof(path1));
    strcat(path1, "\\system\\");
    strcat(path1, dllname);
    hModule1 = LoadLibraryA(path1);
    if (!hModule1)
    {
        /* We must be on Windows NT, so we cannot test */
        return;
    }

    GetWindowsDirectory(path2, sizeof(path2));
    strcat(path2, "\\system32\\");
    strcat(path2, dllname);
    hModule2 = LoadLibraryA(path2);
    if (!hModule2)
    {
        /* We must be on Windows 9x, so we cannot test */
        ok(FreeLibrary(hModule1), "FreeLibrary() failed\n");
        return;
    }

    /* The first LoadLibrary() call may have registered the dll under the
     * system32 path. So load it, again, under the '...\system\...' path so
     * Wine does not immediately notice that it is already loaded.
     */
    hModule3 = LoadLibraryA(path1);
    ok(hModule3 != NULL, "LoadLibrary(%s) failed\n", path1);

    /* Now fully unload the dll */
    ok(FreeLibrary(hModule3), "FreeLibrary() failed\n");
    ok(FreeLibrary(hModule2), "FreeLibrary() failed\n");
    ok(FreeLibrary(hModule1), "FreeLibrary() failed\n");
178
    ok(GetModuleHandle(dllname) == NULL, "%s was not fully unloaded\n", dllname);
179 180 181

    /* Try to load the dll again, if refcounting is ok, this should work */
    hModule1 = LoadLibraryA(path1);
182
    ok(hModule1 != NULL, "LoadLibrary(%s) failed\n", path1);
183 184 185 186
    if (hModule1 != NULL)
        ok(FreeLibrary(hModule1), "FreeLibrary() failed\n");
}

187 188 189 190
static void testLoadLibraryA_Wrong(void)
{
    HMODULE hModule;

191
    /* Try to load a nonexistent dll */
192 193 194
    SetLastError(0xdeadbeef);
    hModule = LoadLibraryA("non_ex_pv.dll");
    ok( !hModule, "non_ex_pv.dll should be not loadable\n");
195
    ok( GetLastError() == ERROR_MOD_NOT_FOUND || GetLastError() == ERROR_DLL_NOT_FOUND, 
196
        "Expected ERROR_MOD_NOT_FOUND or ERROR_DLL_NOT_FOUND (win9x), got %d\n", GetLastError());
197 198 199 200 201 202 203 204 205 206 207 208

    /* Just in case */
    FreeLibrary(hModule);
}

static void testGetProcAddress_Wrong(void)
{
    FARPROC fp;

    SetLastError(0xdeadbeef);
    fp = GetProcAddress(NULL, "non_ex_call");
    ok( !fp, "non_ex_call should not be found\n");
209
    ok( GetLastError() == ERROR_PROC_NOT_FOUND || GetLastError() == ERROR_INVALID_HANDLE,
210
        "Expected ERROR_PROC_NOT_FOUND or ERROR_INVALID_HANDLE(win9x), got %d\n", GetLastError());
211 212

    SetLastError(0xdeadbeef);
213 214
    fp = GetProcAddress((HMODULE)0xdeadbeef, "non_ex_call");
    ok( !fp, "non_ex_call should not be found\n");
215
    ok( GetLastError() == ERROR_MOD_NOT_FOUND || GetLastError() == ERROR_INVALID_HANDLE,
216
        "Expected ERROR_MOD_NOT_FOUND or ERROR_INVALID_HANDLE(win9x), got %d\n", GetLastError());
217 218
}

219 220 221 222 223 224 225
static void testLoadLibraryEx(void)
{
    CHAR path[MAX_PATH];
    HMODULE hmodule;
    HANDLE hfile;

    hfile = CreateFileA("testfile.dll", GENERIC_READ | GENERIC_WRITE,
226
                        FILE_SHARE_READ | FILE_SHARE_WRITE,
227 228 229 230
                        NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
    ok(hfile != INVALID_HANDLE_VALUE, "Expected a valid file handle\n");

    /* NULL lpFileName */
231 232 233 234 235 236 237 238 239 240 241 242
    if (is_unicode_enabled)
    {
        SetLastError(0xdeadbeef);
        hmodule = LoadLibraryExA(NULL, NULL, 0);
        ok(hmodule == 0, "Expected 0, got %p\n", hmodule);
        ok(GetLastError() == ERROR_MOD_NOT_FOUND ||
           GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */
           "Expected ERROR_MOD_NOT_FOUND or ERROR_INVALID_PARAMETER, got %d\n",
           GetLastError());
    }
    else
        win_skip("NULL filename crashes on WinMe\n");
243 244 245 246 247

    /* empty lpFileName */
    SetLastError(0xdeadbeef);
    hmodule = LoadLibraryExA("", NULL, 0);
    ok(hmodule == 0, "Expected 0, got %p\n", hmodule);
248 249 250 251
    ok(GetLastError() == ERROR_MOD_NOT_FOUND ||
       GetLastError() == ERROR_DLL_NOT_FOUND, /* win9x */
       "Expected ERROR_MOD_NOT_FOUND or ERROR_DLL_NOT_FOUND, got %d\n",
       GetLastError());
252 253 254 255 256

    /* hFile is non-NULL */
    SetLastError(0xdeadbeef);
    hmodule = LoadLibraryExA("testfile.dll", hfile, 0);
    ok(hmodule == 0, "Expected 0, got %p\n", hmodule);
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
    todo_wine
    {
        ok(GetLastError() == ERROR_SHARING_VIOLATION ||
           GetLastError() == ERROR_INVALID_PARAMETER || /* win2k3 */
           GetLastError() == ERROR_FILE_NOT_FOUND, /* win9x */
           "Unexpected last error, got %d\n", GetLastError());
    }

    SetLastError(0xdeadbeef);
    hmodule = LoadLibraryExA("testfile.dll", (HANDLE)0xdeadbeef, 0);
    ok(hmodule == 0, "Expected 0, got %p\n", hmodule);
    todo_wine
    {
        ok(GetLastError() == ERROR_SHARING_VIOLATION ||
           GetLastError() == ERROR_INVALID_PARAMETER || /* win2k3 */
           GetLastError() == ERROR_FILE_NOT_FOUND, /* win9x */
           "Unexpected last error, got %d\n", GetLastError());
    }
275

276
    /* try to open a file that is locked */
277 278 279 280 281
    SetLastError(0xdeadbeef);
    hmodule = LoadLibraryExA("testfile.dll", NULL, 0);
    ok(hmodule == 0, "Expected 0, got %p\n", hmodule);
    todo_wine
    {
282 283 284 285
        ok(GetLastError() == ERROR_SHARING_VIOLATION ||
           GetLastError() == ERROR_FILE_NOT_FOUND, /* win9x */
           "Expected ERROR_SHARING_VIOLATION or ERROR_FILE_NOT_FOUND, got %d\n",
           GetLastError());
286 287
    }

288
    /* lpFileName does not matter */
289 290 291 292 293 294 295 296 297 298
    if (is_unicode_enabled)
    {
        SetLastError(0xdeadbeef);
        hmodule = LoadLibraryExA(NULL, hfile, 0);
        ok(hmodule == 0, "Expected 0, got %p\n", hmodule);
        ok(GetLastError() == ERROR_MOD_NOT_FOUND ||
           GetLastError() == ERROR_INVALID_PARAMETER, /* win2k3 */
           "Expected ERROR_MOD_NOT_FOUND or ERROR_INVALID_PARAMETER, got %d\n",
           GetLastError());
    }
299 300 301 302 303 304 305 306 307

    CloseHandle(hfile);

    /* load empty file */
    SetLastError(0xdeadbeef);
    hmodule = LoadLibraryExA("testfile.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
    ok(hmodule == 0, "Expected 0, got %p\n", hmodule);
    todo_wine
    {
308 309 310 311
        ok(GetLastError() == ERROR_FILE_INVALID ||
           GetLastError() == ERROR_BAD_FORMAT, /* win9x */
           "Expected ERROR_FILE_INVALID or ERROR_BAD_FORMAT, got %d\n",
           GetLastError());
312 313 314 315 316 317 318 319 320 321 322 323 324
    }

    DeleteFileA("testfile.dll");

    GetSystemDirectoryA(path, MAX_PATH);
    if (path[lstrlenA(path) - 1] != '\\')
        lstrcatA(path, "\\");
    lstrcatA(path, "kernel32.dll");

    /* load kernel32.dll with an absolute path */
    SetLastError(0xdeadbeef);
    hmodule = LoadLibraryExA(path, NULL, LOAD_LIBRARY_AS_DATAFILE);
    ok(hmodule != 0, "Expected valid module handle\n");
325 326 327
    ok(GetLastError() == 0xdeadbeef ||
       GetLastError() == ERROR_SUCCESS, /* win9x */
       "Expected 0xdeadbeef or ERROR_SUCCESS, got %d\n", GetLastError());
328

329 330 331 332 333 334
    /* try invalid file handle */
    SetLastError(0xdeadbeef);
    hmodule = LoadLibraryExA(path, (HANDLE)0xdeadbeef, 0);
    if (!hmodule)  /* succeeds on xp and older */
        ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());

335 336 337 338 339 340
    CloseHandle(hmodule);

    /* load kernel32.dll with no path */
    SetLastError(0xdeadbeef);
    hmodule = LoadLibraryExA("kernel32.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
    ok(hmodule != 0, "Expected valid module handle\n");
341 342 343
    ok(GetLastError() == 0xdeadbeef ||
       GetLastError() == ERROR_SUCCESS, /* win9x */
       "Expected 0xdeadbeef or ERROR_SUCCESS, got %d\n", GetLastError());
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358

    CloseHandle(hmodule);

    GetCurrentDirectoryA(MAX_PATH, path);
    if (path[lstrlenA(path) - 1] != '\\')
        lstrcatA(path, "\\");
    lstrcatA(path, "kernel32.dll");

    /* load kernel32.dll with an absolute path that does not exist */
    SetLastError(0xdeadbeef);
    hmodule = LoadLibraryExA(path, NULL, LOAD_LIBRARY_AS_DATAFILE);
    todo_wine
    {
        ok(hmodule == 0, "Expected 0, got %p\n", hmodule);
    }
359 360
    ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
       broken(GetLastError() == ERROR_INVALID_HANDLE),  /* nt4 */
361
       "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379

    /* Free the loaded dll when its the first time this dll is loaded
       in process - First time should pass, second fail */
    SetLastError(0xdeadbeef);
    hmodule = LoadLibraryExA("comctl32.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
    ok(hmodule != 0, "Expected valid module handle\n");

    SetLastError(0xdeadbeef);
    ok(FreeLibrary(hmodule),
       "Expected to be able to free the module, failed with %d\n",
       GetLastError());
    SetLastError(0xdeadbeef);
    ok(!FreeLibrary(hmodule),
       "Unexpected ability to free the module, failed with %d\n",
       GetLastError());

    CloseHandle(hmodule);

380 381
}

382 383
START_TEST(module)
{
384 385 386 387 388 389 390 391
    WCHAR filenameW[MAX_PATH];

    /* Test if we can use GetModuleFileNameW */

    SetLastError(0xdeadbeef);
    GetModuleFileNameW(NULL, filenameW, MAX_PATH);
    if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
    {
392
        win_skip("GetModuleFileNameW not existing on this platform, skipping W-calls\n");
393 394 395
        is_unicode_enabled = FALSE;
    }

396 397 398
    testGetModuleFileName(NULL);
    testGetModuleFileName("kernel32.dll");
    testGetModuleFileName_Wrong();
399 400

    testLoadLibraryA();
401
    testNestedLoadLibraryA();
402 403
    testLoadLibraryA_Wrong();
    testGetProcAddress_Wrong();
404
    testLoadLibraryEx();
405
}