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