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 }
218