1 /*
2  * PROJECT:     ReactOS api tests
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Tests for SHLoadIndirectString
5  * COPYRIGHT:   Copyright 2020 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #include <apitest.h>
9 #include <shlwapi.h>
10 #include "resource.h"
11 
12 #include <pseh/pseh2.h>
13 
14 static void execute_test(LPCWSTR DllFile)
15 {
16     WCHAR DllBuffer[MAX_PATH + 20];
17     WCHAR Buffer[MAX_PATH * 2] = {0};
18     HRESULT hr;
19     HANDLE hEvent;
20     DWORD dwRet;
21     HMODULE mod;
22 
23     hEvent = CreateEventA(NULL, TRUE, FALSE, "Local\\shlwapi_apitest_evt");
24 
25     // Show that it is not signaled
26     dwRet = WaitForSingleObject(hEvent, 1);
27     ok_hex(dwRet, WAIT_TIMEOUT);
28 
29     // Ensure the module is not loaded yet...
30     mod = GetModuleHandleW(DllFile);
31     if (mod != NULL)
32     {
33         CloseHandle(hEvent);
34         skip("%S loaded, cannot continue\n", DllFile);
35         return;
36     }
37 
38     wsprintfW(DllBuffer, L"@%s,-3", DllFile);
39 
40     // Load a string from the dll
41     hr = SHLoadIndirectString(DllBuffer, Buffer, _countof(Buffer), NULL);
42     ok_hex(hr, S_OK);
43     if (SUCCEEDED(hr))
44     {
45         // Module should still not be loaded
46         mod = GetModuleHandleW(DllFile);
47         ok_ptr(mod, 0);
48 
49         ok_wstr(Buffer, L"Test string one.");
50 
51         // DllMain not called..
52         dwRet = WaitForSingleObject(hEvent, 1);
53         ok_hex(dwRet, WAIT_TIMEOUT);
54 
55         // Show that calling DllMain will set the event
56         mod = LoadLibraryW(DllFile);
57         ok(mod != NULL, "Failed to load %S\n", DllFile);
58 
59         if (mod)
60         {
61             dwRet = WaitForSingleObject(hEvent, 1);
62             ok_hex(dwRet, WAIT_OBJECT_0);
63             FreeLibrary(mod);
64         }
65     }
66     CloseHandle(hEvent);
67 }
68 
69 
70 BOOL extract_resource(const WCHAR* Filename, LPCWSTR ResourceName)
71 {
72     BOOL Success;
73     DWORD dwWritten, Size;
74     HGLOBAL hGlobal;
75     LPVOID pData;
76     HANDLE Handle;
77     HRSRC hRsrc = FindResourceW(GetModuleHandleW(NULL), ResourceName, (LPCWSTR)10);
78     ok(!!hRsrc, "Unable to find %s\n", wine_dbgstr_w(ResourceName));
79     if (!hRsrc)
80         return FALSE;
81 
82     hGlobal = LoadResource(GetModuleHandleW(NULL), hRsrc);
83     Size = SizeofResource(GetModuleHandleW(NULL), hRsrc);
84     pData = LockResource(hGlobal);
85 
86     ok(Size && !!pData, "Unable to load %s\n", wine_dbgstr_w(ResourceName));
87     if (!Size || !pData)
88         return FALSE;
89 
90     Handle = CreateFileW(Filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
91 
92     if (Handle == INVALID_HANDLE_VALUE)
93     {
94         skip("Failed to create temp file %ls, error %lu\n", Filename, GetLastError());
95         return FALSE;
96     }
97     Success = WriteFile(Handle, pData, Size, &dwWritten, NULL);
98     ok(Success == TRUE, "WriteFile failed with %lu\n", GetLastError());
99     ok(dwWritten == Size, "WriteFile wrote %lu bytes instead of %lu\n", dwWritten, Size);
100     CloseHandle(Handle);
101     Success = Success && (dwWritten == Size);
102 
103     UnlockResource(pData);
104     return Success;
105 }
106 
107 START_TEST(SHLoadIndirectString)
108 {
109     WCHAR workdir[MAX_PATH], dllpath[MAX_PATH];
110     BOOL ret;
111     UINT Length;
112 
113     ret = GetTempPathW(_countof(workdir), workdir);
114     ok(ret, "GetTempPathW error: %lu\n", GetLastError());
115 
116     Length = GetTempFileNameW(workdir, L"ntdll", 0, dllpath);
117     ok(Length != 0, "GetTempFileNameW failed with %lu\n", GetLastError());
118 
119     if (extract_resource(dllpath, (LPCWSTR)101))
120     {
121         _SEH2_TRY
122         {
123             execute_test(dllpath);
124         }
125             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
126         {
127             ok(0, "Ldr didnt handle exception\n");
128         }
129         _SEH2_END;
130     }
131     else
132     {
133         ok(0, "Failed to extract resource\n");
134     }
135 
136     DeleteFileW(dllpath);
137 }
138