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