[SHELL32_APITEST] Follow-up to #6796 (25e2f5f)
[reactos.git] / modules / rostests / apitests / shell32 / OpenAs_RunDLL.cpp
1 /*
2 * PROJECT: ReactOS API tests
3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Test for OpenAs_RunDLL
5 * PROGRAMMERS: Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6 */
7
8 #include "shelltest.h"
9 #include <stdio.h>
10 #include <process.h>
11
12 // OpenAs_RunDLLA
13 typedef void (WINAPI *OPENAS_RUNDLLA)(HWND, HINSTANCE, LPCSTR, int);
14 // OpenAs_RunDLLW
15 typedef void (WINAPI *OPENAS_RUNDLLW)(HWND, HINSTANCE, LPCWSTR, int);
16
17 static OPENAS_RUNDLLA pOpenAs_RunDLLA = NULL;
18 static OPENAS_RUNDLLW pOpenAs_RunDLLW = NULL;
19
20 struct TEST_ENTRY
21 {
22 int nLine;
23 BOOL bWide;
24 HINSTANCE hInst;
25 int nRet;
26 BOOL bCreateFile;
27 LPCSTR pszFileA;
28 LPCWSTR pszFileW;
29 DWORD dwError;
30 };
31
32 #define COUNT 5
33 #define INTERVAL 200
34
35 #define DEATH 999
36 #define OPENED 1
37 #define NOT_OPENED 0
38
39 #define BAD_INST ((HINSTANCE)0xDEAD)
40 #define BAD_SZ_A ((LPCSTR)0xDEAD)
41 #define BAD_SZ_W ((LPCWSTR)0xDEAD)
42
43 static const TEST_ENTRY s_TestEntries[] =
44 {
45 // ANSI
46 {__LINE__, FALSE, NULL, OPENED, FALSE, NULL, NULL, 0 },
47 {__LINE__, FALSE, NULL, OPENED, FALSE, "", NULL, 0 },
48 {__LINE__, FALSE, NULL, OPENED, FALSE, "invalid file name.txt", NULL, 0 },
49 {__LINE__, FALSE, NULL, DEATH, FALSE, BAD_SZ_A, NULL, 0 },
50 {__LINE__, FALSE, NULL, OPENED, TRUE, "created file.txt", NULL, 0 },
51 {__LINE__, FALSE, BAD_INST, OPENED, FALSE, NULL, NULL, 0 },
52 {__LINE__, FALSE, BAD_INST, OPENED, FALSE, "invalid file name.txt", NULL, 0 },
53 {__LINE__, FALSE, BAD_INST, DEATH, FALSE, BAD_SZ_A, NULL, 0xDEADFACE },
54 {__LINE__, FALSE, BAD_INST, OPENED, TRUE, "created file.txt", NULL, 0 },
55 // WIDE
56 {__LINE__, TRUE, NULL, OPENED, FALSE, NULL, NULL, 0x80070490 },
57 {__LINE__, TRUE, NULL, OPENED, FALSE, NULL, L"", ERROR_NO_SCROLLBARS },
58 {__LINE__, TRUE, NULL, OPENED, FALSE, NULL, L"invalid file name.txt", ERROR_NO_SCROLLBARS },
59 {__LINE__, TRUE, NULL, OPENED, FALSE, NULL, BAD_SZ_W, 0xDEADFACE },
60 {__LINE__, TRUE, NULL, OPENED, TRUE, NULL, L"created file.txt", ERROR_NO_SCROLLBARS },
61 {__LINE__, TRUE, BAD_INST, OPENED, FALSE, NULL, NULL, 0x80070490 },
62 {__LINE__, TRUE, BAD_INST, OPENED, FALSE, NULL, L"invalid file name.txt", ERROR_NO_SCROLLBARS },
63 {__LINE__, TRUE, BAD_INST, OPENED, FALSE, NULL, BAD_SZ_W, 0xDEADFACE },
64 {__LINE__, TRUE, BAD_INST, OPENED, TRUE, NULL, L"created file.txt", ERROR_NO_SCROLLBARS },
65 };
66
67 static HANDLE s_hThread = NULL;
68 static INT s_nRet = NOT_OPENED;
69
70 static unsigned __stdcall
71 watch_thread_proc(void *arg)
72 {
73 for (int i = 0; i < COUNT; ++i)
74 {
75 Sleep(INTERVAL);
76
77 HWND hwnd = FindWindowA("#32770", "Open With");
78 if (hwnd == NULL)
79 continue;
80
81 if (!IsWindowVisible(hwnd))
82 {
83 trace("not visible\n");
84 continue;
85 }
86
87 s_nRet = OPENED;
88 PostMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDCANCEL, BN_CLICKED), 0);
89 break;
90 }
91 return 0;
92 }
93
94 static void StartWatchGUI(const TEST_ENTRY *pEntry)
95 {
96 s_nRet = NOT_OPENED;
97 s_hThread = (HANDLE)_beginthreadex(NULL, 0, watch_thread_proc, NULL, 0, NULL);
98 }
99
100 static void DoEntry(const TEST_ENTRY *pEntry)
101 {
102 if (pEntry->bWide)
103 {
104 if (pEntry->bCreateFile)
105 {
106 FILE *fp = _wfopen(pEntry->pszFileW, L"wb");
107 ok(fp != NULL, "Line %d: Unable to create file '%s'\n", pEntry->nLine, wine_dbgstr_w(pEntry->pszFileW));
108 fclose(fp);
109 }
110
111 StartWatchGUI(pEntry);
112 SetLastError(0xDEADFACE);
113
114 _SEH2_TRY
115 {
116 (*pOpenAs_RunDLLW)(NULL, pEntry->hInst, pEntry->pszFileW, SW_SHOWDEFAULT);
117 }
118 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
119 {
120 s_nRet = DEATH;
121 }
122 _SEH2_END;
123
124 DWORD dwError = GetLastError();
125 ok(pEntry->dwError == dwError, "Line %d: error expected %ld, was %ld\n", pEntry->nLine, pEntry->dwError, dwError);
126
127 WaitForSingleObject(s_hThread, INFINITE);
128 CloseHandle(s_hThread);
129
130 if (pEntry->bCreateFile)
131 {
132 ok(DeleteFileW(pEntry->pszFileW), "Line %d: DeleteFileA failed\n", pEntry->nLine);
133 }
134 }
135 else
136 {
137 if (pEntry->bCreateFile)
138 {
139 FILE *fp = fopen(pEntry->pszFileA, "wb");
140 ok(fp != NULL, "Line %d: Unable to create file '%s'\n", pEntry->nLine, pEntry->pszFileA);
141 fclose(fp);
142 }
143
144 StartWatchGUI(pEntry);
145 SetLastError(0xDEADFACE);
146
147 _SEH2_TRY
148 {
149 (*pOpenAs_RunDLLA)(NULL, pEntry->hInst, pEntry->pszFileA, SW_SHOWDEFAULT);
150 }
151 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
152 {
153 s_nRet = DEATH;
154 }
155 _SEH2_END;
156
157 DWORD dwError = GetLastError();
158 ok(pEntry->dwError == dwError, "Line %d: error expected %ld, was %ld\n", pEntry->nLine, pEntry->dwError, dwError);
159
160 WaitForSingleObject(s_hThread, INFINITE);
161 CloseHandle(s_hThread);
162
163 if (pEntry->bCreateFile)
164 {
165 ok(DeleteFileA(pEntry->pszFileA), "Line %d: DeleteFileA failed\n", pEntry->nLine);
166 }
167 }
168
169 // FIXME: This function probably returns void
170 //ok(pEntry->nRet == s_nRet, "Line %d: s_nRet expected %d, was %d\n", pEntry->nLine, pEntry->nRet, s_nRet);
171 }
172
173 START_TEST(OpenAs_RunDLL)
174 {
175 HINSTANCE hShell32 = LoadLibraryA("shell32.dll");
176 if (hShell32 == NULL)
177 {
178 skip("Unable to load shell32.dll\n");
179 return;
180 }
181
182 pOpenAs_RunDLLA = (OPENAS_RUNDLLA)GetProcAddress(hShell32, "OpenAs_RunDLLA");
183 if (pOpenAs_RunDLLA == NULL)
184 {
185 skip("Unable to get OpenAs_RunDLLA\n");
186 return;
187 }
188
189 pOpenAs_RunDLLW = (OPENAS_RUNDLLW)GetProcAddress(hShell32, "OpenAs_RunDLLW");
190 if (pOpenAs_RunDLLW == NULL)
191 {
192 skip("Unable to get OpenAs_RunDLLW\n");
193 return;
194 }
195
196 TCHAR szCurDir[MAX_PATH], szTempDir[MAX_PATH];
197
198 ok(GetCurrentDirectory(_countof(szCurDir), szCurDir), "GetCurrentDirectory failed\n");
199 ok(GetTempPath(_countof(szTempDir), szTempDir), "GetTempPath failed\n");
200
201 if (!SetCurrentDirectory(szTempDir))
202 {
203 skip("SetCurrentDirectory failed\n");
204 }
205 else
206 {
207 for (size_t i = 0; i < _countof(s_TestEntries); ++i)
208 {
209 const TEST_ENTRY *pEntry = &s_TestEntries[i];
210 DoEntry(pEntry);
211 }
212
213 ok(SetCurrentDirectory(szCurDir), "SetCurrentDirectory failed\n");
214 }
215
216 FreeLibrary(hShell32);
217 }