https://git.reactos.org/?p=reactos.git;a=commitdiff;h=2318bda651ee1a8a17585…
commit 2318bda651ee1a8a175859e3e05ee3f821404151
Author: Mark Jansen <mark.jansen(a)reactos.org>
AuthorDate: Sun Oct 20 00:37:05 2019 +0200
Commit: Mark Jansen <mark.jansen(a)reactos.org>
CommitDate: Sun Oct 20 17:10:11 2019 +0200
[SHELL32_APITEST] Show that SHCreateDataObject behaves exactly like
CIDLData_CreateFromIDArray
---
modules/rostests/apitests/shell32/CMakeLists.txt | 1 +
.../apitests/shell32/SHCreateDataObject.cpp | 466 +++++++++++++++++++++
modules/rostests/apitests/shell32/testlist.c | 2 +
3 files changed, 469 insertions(+)
diff --git a/modules/rostests/apitests/shell32/CMakeLists.txt
b/modules/rostests/apitests/shell32/CMakeLists.txt
index df1e6cf8af2..02b28625d63 100644
--- a/modules/rostests/apitests/shell32/CMakeLists.txt
+++ b/modules/rostests/apitests/shell32/CMakeLists.txt
@@ -20,6 +20,7 @@ list(APPEND SOURCE
IShellFolderViewCB.cpp
OpenAs_RunDLL.cpp
PathResolve.cpp
+ SHCreateDataObject.cpp
SHCreateFileExtractIconW.cpp
SHParseDisplayName.cpp
ShellExecCmdLine.cpp
diff --git a/modules/rostests/apitests/shell32/SHCreateDataObject.cpp
b/modules/rostests/apitests/shell32/SHCreateDataObject.cpp
new file mode 100644
index 00000000000..186134f33ea
--- /dev/null
+++ b/modules/rostests/apitests/shell32/SHCreateDataObject.cpp
@@ -0,0 +1,466 @@
+/*
+ * PROJECT: ReactOS api tests
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Test for SHCreateDataObject
+ * COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen(a)reactos.org)
+ */
+
+#include "shelltest.h"
+#include <ndk/rtlfuncs.h>
+#include <stdio.h>
+#include <shellutils.h>
+#include <shlwapi.h>
+
+static DWORD g_WinVersion;
+
+typedef HRESULT (WINAPI *tSHCreateDataObject)(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl,
PCUITEMID_CHILD_ARRAY apidl, IDataObject *pdtInner, REFIID riid, void **ppv);
+static tSHCreateDataObject pSHCreateDataObject;
+
+
+static void TestAdviseAndCanonical(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl,
PCUIDLIST_RELATIVE_ARRAY apidl)
+{
+ CComPtr<IDataObject> spDataObj;
+ HRESULT hr = pSHCreateDataObject(pidlFolder, cidl, apidl, NULL,
IID_PPV_ARG(IDataObject, &spDataObj));
+
+ ok_hex(hr, S_OK);
+ if (!SUCCEEDED(hr))
+ return;
+
+ hr = spDataObj->DAdvise(NULL, 0, NULL, NULL);
+ ok_hex(hr, OLE_E_ADVISENOTSUPPORTED);
+
+ hr = spDataObj->DUnadvise(0);
+ ok_hex(hr, OLE_E_ADVISENOTSUPPORTED);
+
+ hr = spDataObj->EnumDAdvise(NULL);
+ ok_hex(hr, OLE_E_ADVISENOTSUPPORTED);
+
+
+ FORMATETC in = {1, (DVTARGETDEVICE*)2, 3, 4, 5};
+ FORMATETC out = {6, (DVTARGETDEVICE*)7, 8, 9, 10};
+
+ hr = spDataObj->GetCanonicalFormatEtc(&in, &out);
+ ok_hex(hr, DATA_S_SAMEFORMATETC);
+
+ if (g_WinVersion < _WIN32_WINNT_VISTA)
+ {
+ ok_int(out.cfFormat, 6);
+ ok_ptr(out.ptd, (void*)7);
+ ok_int(out.dwAspect, 8);
+ ok_int(out.lindex, 9);
+ ok_int(out.tymed, 10);
+ trace("out unmodified\n");
+ }
+ else
+ {
+ ok_int(out.cfFormat, in.cfFormat);
+ ok_ptr(out.ptd, NULL);
+ ok_int(out.dwAspect, (int)in.dwAspect);
+ ok_int(out.lindex, in.lindex);
+ ok_int(out.tymed, (int)in.tymed);
+ trace("in copied to out\n");
+ }
+}
+
+
+static inline PCUIDLIST_ABSOLUTE HIDA_GetPIDLFolder(CIDA const* pida)
+{
+ return (PCUIDLIST_ABSOLUTE)(((LPBYTE)pida) + (pida)->aoffset[0]);
+}
+
+static inline PCUIDLIST_RELATIVE HIDA_GetPIDLItem(CIDA const* pida, SIZE_T i)
+{
+ return (PCUIDLIST_RELATIVE)(((LPBYTE)pida) + (pida)->aoffset[i + 1]);
+}
+
+#define ok_wstri(x, y) \
+ ok(wcsicmp(x, y) == 0, "Wrong string. Expected '%S', got
'%S'\n", y, x)
+
+static void TestHIDA(PVOID pData, SIZE_T Size, LPCWSTR ExpectRoot, LPCWSTR ExpectPath1,
LPCWSTR ExpectPath2)
+{
+ LPIDA pida = (LPIDA)pData;
+
+ ok_int(pida->cidl, 2);
+ if (pida->cidl != 2)
+ return;
+
+ WCHAR FolderPath[MAX_PATH], Item1[MAX_PATH], Item2[MAX_PATH];
+ BOOL bRet = SHGetPathFromIDListW(HIDA_GetPIDLFolder(pida), FolderPath);
+ ok_int(bRet, TRUE);
+ if (!bRet)
+ return;
+ ok_wstri(FolderPath, ExpectRoot);
+
+ CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidl1(ILCombine(HIDA_GetPIDLFolder(pida),
HIDA_GetPIDLItem(pida, 0)));
+ CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidl2(ILCombine(HIDA_GetPIDLFolder(pida),
HIDA_GetPIDLItem(pida, 1)));
+
+ bRet = SHGetPathFromIDListW(pidl1, Item1);
+ ok_int(bRet, TRUE);
+ if (!bRet)
+ return;
+ ok_wstri(Item1, ExpectPath1);
+
+ bRet = SHGetPathFromIDListW(pidl2, Item2);
+ ok_int(bRet, TRUE);
+ if (!bRet)
+ return;
+ ok_wstri(Item2, ExpectPath2);
+}
+
+static void TestHDROP(PVOID pData, SIZE_T Size, LPCWSTR ExpectRoot, LPCWSTR ExpectPath1,
LPCWSTR ExpectPath2)
+{
+ DROPFILES* pDropFiles = (DROPFILES*)pData;
+ ok_int(pDropFiles->fWide, TRUE);
+
+ LPCWSTR Expected[2] = { ExpectPath1, ExpectPath2 };
+
+ DWORD offset = pDropFiles->pFiles;
+ UINT Count = 0;
+ for (;;Count++)
+ {
+ LPCWSTR ptr = (LPCWSTR)(((BYTE*)pDropFiles) + offset);
+ if (!*ptr)
+ break;
+
+ if (Count < _countof(Expected))
+ ok_wstri(Expected[Count], ptr);
+
+ offset += (wcslen(ptr) + 1) * sizeof(WCHAR);
+ }
+ ok_int(Count, 2);
+}
+
+static void TestFilenameA(PVOID pData, SIZE_T Size, LPCWSTR ExpectRoot, LPCWSTR
ExpectPath1, LPCWSTR ExpectPath2)
+{
+ LPCSTR FirstFile = (LPCSTR)pData;
+ LPWSTR FirstFileW;
+
+ HRESULT hr = SHStrDupA(FirstFile, &FirstFileW);
+ ok_hex(hr, S_OK);
+ if (!SUCCEEDED(hr))
+ return;
+
+ ok_wstri(ExpectPath1, FirstFileW);
+ CoTaskMemFree(FirstFileW);
+}
+
+static void TestFilenameW(PVOID pData, SIZE_T Size, LPCWSTR ExpectRoot, LPCWSTR
ExpectPath1, LPCWSTR ExpectPath2)
+{
+ LPCWSTR FirstFile = (LPCWSTR)pData;
+ ok_wstri(ExpectPath1, FirstFile);
+}
+
+
+static void TestDefaultFormat(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl,
PCUIDLIST_RELATIVE_ARRAY apidl)
+{
+ CComPtr<IDataObject> spDataObj;
+ HRESULT hr = pSHCreateDataObject(pidlFolder, cidl, apidl, NULL,
IID_PPV_ARG(IDataObject, &spDataObj));
+
+ ok_hex(hr, S_OK);
+ if (!SUCCEEDED(hr))
+ return;
+
+ CComPtr<IEnumFORMATETC> pEnumFmt;
+ hr = spDataObj->EnumFormatEtc(DATADIR_GET, &pEnumFmt);
+
+ ok_hex(hr, S_OK);
+ if (!SUCCEEDED(hr))
+ return;
+
+ UINT Expected[4] = {
+ RegisterClipboardFormatA(CFSTR_SHELLIDLISTA),
+ CF_HDROP,
+ RegisterClipboardFormatA(CFSTR_FILENAMEA),
+ RegisterClipboardFormatA("FileNameW"),
+ };
+
+ UINT Count = 0;
+ FORMATETC fmt;
+ while (S_OK == (hr=pEnumFmt->Next(1, &fmt, NULL)))
+ {
+ char szGot[512], szExpected[512];
+ GetClipboardFormatNameA(fmt.cfFormat, szGot, sizeof(szGot));
+ ok(Count < _countof(Expected), "%u\n", Count);
+ if (Count < _countof(Expected))
+ {
+ GetClipboardFormatNameA(Expected[Count], szExpected, sizeof(szExpected));
+ ok(fmt.cfFormat == Expected[Count], "Got 0x%x(%s), expected 0x%x(%s) for
%u\n",
+ fmt.cfFormat, szGot, Expected[Count], szExpected, Count);
+ }
+
+ ok(fmt.ptd == NULL, "Got 0x%p, expected 0x%p for [%u].ptd\n", fmt.ptd,
(void*)NULL, Count);
+ ok(fmt.dwAspect == DVASPECT_CONTENT, "Got 0x%lu, expected 0x%d for
[%u].dwAspect\n", fmt.dwAspect, DVASPECT_CONTENT, Count);
+ ok(fmt.lindex == -1, "Got 0x%lx, expected 0x%x for [%u].lindex\n",
fmt.lindex, -1, Count);
+ ok(fmt.tymed == TYMED_HGLOBAL, "Got 0x%lu, expected 0x%d for
[%u].tymed\n", fmt.tymed, TYMED_HGLOBAL, Count);
+
+ Count++;
+ }
+ trace("Got %u formats\n", Count);
+ ULONG ExpectedCount = (g_WinVersion < _WIN32_WINNT_WIN8) ? 1 : 4;
+ ok_int(Count, (int)ExpectedCount);
+ ok_hex(hr, S_FALSE);
+
+ typedef void (*TestFunction)(PVOID pData, SIZE_T Size, LPCWSTR ExpectRoot, LPCWSTR
ExpectPath1, LPCWSTR ExpectPath2);
+ TestFunction TestFormats[] = {
+ TestHIDA,
+ TestHDROP,
+ TestFilenameA,
+ TestFilenameW,
+ };
+
+ WCHAR ExpectRoot[MAX_PATH], ExpectItem1[MAX_PATH], ExpectItem2[MAX_PATH];
+
+ hr = SHGetFolderPathW(NULL, CSIDL_WINDOWS, NULL, 0, ExpectRoot);
+ ok_hex(hr, S_OK);
+ if (!SUCCEEDED(hr))
+ return;
+
+ hr = SHGetFolderPathW(NULL, CSIDL_SYSTEM, NULL, 0, ExpectItem1);
+ ok_hex(hr, S_OK);
+ if (!SUCCEEDED(hr))
+ return;
+
+ hr = SHGetFolderPathW(NULL, CSIDL_RESOURCES, NULL, 0, ExpectItem2);
+ ok_hex(hr, S_OK);
+ if (!SUCCEEDED(hr))
+ return;
+
+
+ /* The formats are not synthesized on request */
+ for (Count = 0; Count < _countof(Expected); ++Count)
+ {
+ STGMEDIUM medium = {0};
+ FORMATETC etc = { (CLIPFORMAT)Expected[Count], NULL, DVASPECT_CONTENT, -1,
TYMED_HGLOBAL };
+ char szExpected[512];
+
+ GetClipboardFormatNameA(etc.cfFormat, szExpected, sizeof(szExpected));
+ hr = spDataObj->GetData(&etc, &medium);
+ HRESULT hr2 = spDataObj->QueryGetData(&etc);
+ ok_hex(hr2, SUCCEEDED(hr) ? S_OK : S_FALSE);
+
+ if (Count < ExpectedCount)
+ {
+ ok(hr == S_OK, "0x%x (0x%x(%s))\n", (unsigned int)hr,
Expected[Count], szExpected);
+ ok(medium.tymed == TYMED_HGLOBAL, "0x%lx (0x%x(%s))\n",
medium.tymed, Expected[Count], szExpected);
+ if (hr == S_OK && medium.tymed == TYMED_HGLOBAL)
+ {
+ PVOID pData = GlobalLock(medium.hGlobal);
+ SIZE_T Size = GlobalSize(medium.hGlobal);
+ TestFormats[Count](pData, Size, ExpectRoot, ExpectItem1, ExpectItem2);
+ GlobalUnlock(medium.hGlobal);
+ }
+ }
+ else
+ {
+ if (g_WinVersion < _WIN32_WINNT_VISTA)
+ ok(hr == E_INVALIDARG, "0x%x (0x%x(%s))\n", (unsigned int)hr,
Expected[Count], szExpected);
+ else
+ ok(hr == DV_E_FORMATETC, "0x%x (0x%x(%s))\n", (unsigned int)hr,
Expected[Count], szExpected);
+ }
+
+ if (SUCCEEDED(hr))
+ ReleaseStgMedium(&medium);
+ }
+
+ CLIPFORMAT Format = RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECTW);
+ FORMATETC formatetc = { Format, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+ STGMEDIUM medium;
+
+ hr = spDataObj->GetData(&formatetc, &medium);
+ if (g_WinVersion < _WIN32_WINNT_VISTA)
+ ok_hex(hr, E_INVALIDARG);
+ else
+ ok_hex(hr, DV_E_FORMATETC);
+}
+
+
+static void TestSetAndGetExtraFormat(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl,
PCUIDLIST_RELATIVE_ARRAY apidl)
+{
+ CComPtr<IDataObject> spDataObj;
+ HRESULT hr = pSHCreateDataObject(pidlFolder, cidl, apidl, NULL,
IID_PPV_ARG(IDataObject, &spDataObj));
+
+ ok_hex(hr, S_OK);
+ if (!SUCCEEDED(hr))
+ return;
+
+ STGMEDIUM medium = {0};
+ medium.tymed = TYMED_HGLOBAL;
+ medium.hGlobal = GlobalAlloc(GHND, sizeof(DWORD));
+ ok(medium.hGlobal != NULL, "Download more ram\n");
+ PDWORD data = (PDWORD)GlobalLock(medium.hGlobal);
+ *data = 12345;
+ GlobalUnlock(medium.hGlobal);
+
+ UINT flags = GlobalFlags(medium.hGlobal);
+ SIZE_T size = GlobalSize(medium.hGlobal);
+ ok_hex(flags, 0);
+ ok_size_t(size, sizeof(DWORD));
+
+ FORMATETC etc = { (CLIPFORMAT)RegisterClipboardFormatA(CFSTR_INDRAGLOOPA), NULL,
DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+ FORMATETC etc2 = etc;
+
+ /* Not supported! */
+ hr = spDataObj->SetData(&etc, &medium, FALSE);
+ if (g_WinVersion < _WIN32_WINNT_WIN8)
+ ok_hex(hr, E_INVALIDARG);
+ else
+ ok_hex(hr, E_NOTIMPL);
+
+ /* Object takes ownership! */
+ hr = spDataObj->SetData(&etc, &medium, TRUE);
+ ok_hex(hr, S_OK);
+ if (!SUCCEEDED(hr))
+ return;
+
+ /* Does not touch the hGlobal! */
+ flags = GlobalFlags(medium.hGlobal);
+ size = GlobalSize(medium.hGlobal);
+ ok_hex(flags, 0);
+ ok_size_t(size, sizeof(DWORD));
+
+ STGMEDIUM medium2 = {0};
+
+ /* No conversion */
+ etc2.dwAspect = DVASPECT_DOCPRINT;
+ hr = spDataObj->GetData(&etc2, &medium2);
+ HRESULT hr2 = spDataObj->QueryGetData(&etc2);
+ ok_hex(hr2, SUCCEEDED(hr) ? S_OK : S_FALSE);
+ if (g_WinVersion < _WIN32_WINNT_VISTA)
+ ok_hex(hr, E_INVALIDARG);
+ else
+ ok_hex(hr, DV_E_FORMATETC);
+
+ etc2.dwAspect = DVASPECT_CONTENT;
+ etc2.tymed = TYMED_NULL;
+ hr = spDataObj->GetData(&etc2, &medium2);
+ hr2 = spDataObj->QueryGetData(&etc2);
+ ok_hex(hr2, SUCCEEDED(hr) ? S_OK : S_FALSE);
+ if (g_WinVersion < _WIN32_WINNT_VISTA)
+ ok_hex(hr, E_INVALIDARG);
+ else
+ ok_hex(hr, DV_E_FORMATETC);
+ etc2.tymed = TYMED_HGLOBAL;
+
+ ok_ptr(medium2.pUnkForRelease, NULL);
+ hr = spDataObj->GetData(&etc2, &medium2);
+ hr2 = spDataObj->QueryGetData(&etc2);
+ ok_hex(hr2, SUCCEEDED(hr) ? S_OK : S_FALSE);
+ ok_hex(hr, S_OK);
+ if (hr == S_OK)
+ {
+ ok_hex(medium2.tymed, TYMED_HGLOBAL);
+ if (g_WinVersion < _WIN32_WINNT_VISTA)
+ {
+ /* The IDataObject is set as pUnkForRelease */
+ ok(medium2.pUnkForRelease == (IUnknown*)spDataObj, "Expected the data
object (0x%p), got 0x%p\n",
+ (IUnknown*)spDataObj, medium2.pUnkForRelease);
+ ok(medium.hGlobal == medium2.hGlobal, "Pointers are not the same!, got
0x%p and 0x%p\n", medium.hGlobal, medium2.hGlobal);
+ }
+ else
+ {
+ ok_ptr(medium2.pUnkForRelease, NULL);
+ ok(medium.hGlobal != medium2.hGlobal, "Pointers are the same!\n");
+ }
+
+ flags = GlobalFlags(medium2.hGlobal);
+ size = GlobalSize(medium2.hGlobal);
+ ok_hex(flags, 0);
+ ok_size_t(size, sizeof(DWORD));
+
+ data = (PDWORD)GlobalLock(medium2.hGlobal);
+ if (data)
+ ok_int(*data, 12345);
+ else
+ ok(0, "GlobalLock: %lu\n", GetLastError());
+ GlobalUnlock(medium2.hGlobal);
+
+ HGLOBAL backup = medium2.hGlobal;
+ ReleaseStgMedium(&medium2);
+
+ flags = GlobalFlags(backup);
+ size = GlobalSize(backup);
+ if (g_WinVersion < _WIN32_WINNT_VISTA)
+ {
+ /* Same object! just the pUnkForRelease was set, so original hGlobal is still
valid */
+ ok_hex(flags, 0);
+ ok_size_t(size, sizeof(DWORD));
+ }
+ else
+ {
+ ok_hex(flags, GMEM_INVALID_HANDLE);
+ ok_size_t(size, 0);
+ }
+
+ /* Original is still intact (but no longer ours!) */
+ flags = GlobalFlags(medium.hGlobal);
+ size = GlobalSize(medium.hGlobal);
+ ok_hex(flags, 0);
+ ok_size_t(size, sizeof(DWORD));
+ }
+
+ HGLOBAL backup = medium.hGlobal;
+ spDataObj.Release();
+
+ /* Now our hGlobal is deleted */
+ flags = GlobalFlags(backup);
+ size = GlobalSize(backup);
+ ok_hex(flags, GMEM_INVALID_HANDLE);
+ ok_size_t(size, 0);
+}
+
+START_TEST(SHCreateDataObject)
+{
+ HRESULT hr;
+
+ pSHCreateDataObject =
(tSHCreateDataObject)GetProcAddress(GetModuleHandleA("shell32.dll"),
"SHCreateDataObject");
+ if (!pSHCreateDataObject)
+ {
+ skip("shell32!SHCreateDataObject not exported\n");
+ }
+
+
+ CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+
+ RTL_OSVERSIONINFOEXW rtlinfo = {0};
+
+ rtlinfo.dwOSVersionInfoSize = sizeof(rtlinfo);
+ RtlGetVersion((PRTL_OSVERSIONINFOW)&rtlinfo);
+ g_WinVersion = (rtlinfo.dwMajorVersion << 8) | rtlinfo.dwMinorVersion;
+
+ CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlWindows;
+ CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlSystem32;
+ CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlResources;
+
+ hr = SHGetFolderLocation(NULL, CSIDL_WINDOWS, NULL, 0, &pidlWindows);
+ ok_hex(hr, S_OK);
+ if (!SUCCEEDED(hr))
+ return;
+
+ hr = SHGetFolderLocation(NULL, CSIDL_SYSTEM, NULL, 0, &pidlSystem32);
+ ok_hex(hr, S_OK);
+ if (!SUCCEEDED(hr))
+ return;
+
+ hr = SHGetFolderLocation(NULL, CSIDL_RESOURCES, NULL, 0, &pidlResources);
+ ok_hex(hr, S_OK);
+ if (!SUCCEEDED(hr))
+ return;
+
+ CComPtr<IShellFolder> shellFolder;
+ PCUITEMID_CHILD child1;
+ hr = SHBindToParent(pidlSystem32, IID_PPV_ARG(IShellFolder, &shellFolder),
&child1);
+ ok_hex(hr, S_OK);
+ if (!SUCCEEDED(hr))
+ return;
+
+ PCUITEMID_CHILD child2 = ILFindLastID(pidlResources);
+
+ UINT cidl = 2;
+ PCUIDLIST_RELATIVE apidl[2] = {
+ child1, child2
+ };
+
+ TestAdviseAndCanonical(pidlWindows, cidl, apidl);
+ TestDefaultFormat(pidlWindows, cidl, apidl);
+ TestSetAndGetExtraFormat(pidlWindows, cidl, apidl);
+}
diff --git a/modules/rostests/apitests/shell32/testlist.c
b/modules/rostests/apitests/shell32/testlist.c
index ffd832f0ba2..7b603dff147 100644
--- a/modules/rostests/apitests/shell32/testlist.c
+++ b/modules/rostests/apitests/shell32/testlist.c
@@ -15,6 +15,7 @@ extern void func_IShellFolderViewCB(void);
extern void func_menu(void);
extern void func_OpenAs_RunDLL(void);
extern void func_PathResolve(void);
+extern void func_SHCreateDataObject(void);
extern void func_SHCreateFileExtractIconW(void);
extern void func_ShellExecCmdLine(void);
extern void func_ShellExecuteEx(void);
@@ -35,6 +36,7 @@ const struct test winetest_testlist[] =
{ "menu", func_menu },
{ "OpenAs_RunDLL", func_OpenAs_RunDLL },
{ "PathResolve", func_PathResolve },
+ { "SHCreateDataObject", func_SHCreateDataObject },
{ "SHCreateFileExtractIconW", func_SHCreateFileExtractIconW },
{ "ShellExecCmdLine", func_ShellExecCmdLine },
{ "ShellExecuteEx", func_ShellExecuteEx },