--- /dev/null
- Names[count] = HeapAlloc(GetProcessHeap(), 0, strlenW(szValue) + 1);
+/*
+ * Copyright (C) 2003 Michael Günnewig
+ * Copyright (C) 2003 CodeWeavers Inc. (Ulrich Czekalla)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "precomp.h"
+
+#include <winuser.h>
+#include <winreg.h>
+#include <wine/unicode.h>
+#include <dmo.h>
+
+#define MSDMO_MAJOR_VERSION 6
+
+static const WCHAR szDMORootKey[] =
+{
+ 'D','i','r','e','c','t','S','h','o','w','\\',
+ 'M','e','d','i','a','O','b','j','e','c','t','s',0
+};
+
+static const WCHAR szDMOInputType[] =
+{
+ 'I','n','p','u','t','T','y','p','e','s',0
+};
+
+static const WCHAR szDMOOutputType[] =
+{
+ 'O','u','t','p','u','t','T','y','p','e','s',0
+};
+
+static const WCHAR szDMOKeyed[] =
+{
+ 'K','e','y','e','d',0
+};
+
+static const WCHAR szDMOCategories[] =
+{
+ 'C','a','t','e','g','o','r','i','e','s',0
+};
+
+static const WCHAR szGUIDFmt[] =
+{
+ '%','0','8','X','-','%','0','4','X','-','%','0','4','X','-','%','0',
+ '2','X','%','0','2','X','-','%','0','2','X','%','0','2','X','%','0','2',
+ 'X','%','0','2','X','%','0','2','X','%','0','2','X',0
+};
+
+static const WCHAR szCat3Fmt[] =
+{
+ '%','s','\\','%','s','\\','%','s',0
+};
+
+static const WCHAR szCat2Fmt[] =
+{
+ '%','s','\\','%','s',0
+};
+
+static const WCHAR szToGuidFmt[] =
+{
+ '{','%','s','}',0
+};
+
+
+typedef struct
+{
+ IEnumDMO IEnumDMO_iface;
+ LONG ref;
+ DWORD index;
+ const GUID* guidCategory;
+ DWORD dwFlags;
+ DWORD cInTypes;
+ DMO_PARTIAL_MEDIATYPE *pInTypes;
+ DWORD cOutTypes;
+ DMO_PARTIAL_MEDIATYPE *pOutTypes;
+ HKEY hkey;
+} IEnumDMOImpl;
+
+static inline IEnumDMOImpl *impl_from_IEnumDMO(IEnumDMO *iface)
+{
+ return CONTAINING_RECORD(iface, IEnumDMOImpl, IEnumDMO_iface);
+}
+
+static HRESULT read_types(HKEY root, LPCWSTR key, ULONG *supplied, ULONG requested, DMO_PARTIAL_MEDIATYPE* types);
+
+static const IEnumDMOVtbl edmovt;
+
+static LPWSTR GUIDToString(LPWSTR lpwstr, REFGUID lpcguid)
+{
+ wsprintfW(lpwstr, szGUIDFmt, lpcguid->Data1, lpcguid->Data2,
+ lpcguid->Data3, lpcguid->Data4[0], lpcguid->Data4[1],
+ lpcguid->Data4[2], lpcguid->Data4[3], lpcguid->Data4[4],
+ lpcguid->Data4[5], lpcguid->Data4[6], lpcguid->Data4[7]);
+
+ return lpwstr;
+}
+
+static BOOL IsMediaTypeEqual(const DMO_PARTIAL_MEDIATYPE* mt1, const DMO_PARTIAL_MEDIATYPE* mt2)
+{
+
+ return (IsEqualCLSID(&mt1->type, &mt2->type) ||
+ IsEqualCLSID(&mt2->type, &GUID_NULL) ||
+ IsEqualCLSID(&mt1->type, &GUID_NULL)) &&
+ (IsEqualCLSID(&mt1->subtype, &mt2->subtype) ||
+ IsEqualCLSID(&mt2->subtype, &GUID_NULL) ||
+ IsEqualCLSID(&mt1->subtype, &GUID_NULL));
+}
+
+static HRESULT write_types(HKEY hkey, LPCWSTR name, const DMO_PARTIAL_MEDIATYPE* types, DWORD count)
+{
+ HRESULT hres = S_OK;
+ if (MSDMO_MAJOR_VERSION > 5)
+ {
+ hres = RegSetValueExW(hkey, name, 0, REG_BINARY, (const BYTE*) types,
+ count* sizeof(DMO_PARTIAL_MEDIATYPE));
+ }
+ else
+ {
+ HKEY skey1,skey2,skey3;
+ DWORD index = 0;
+ WCHAR szGuidKey[64];
+
+ hres = RegCreateKeyExW(hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
+ KEY_WRITE, NULL, &skey1, NULL);
+ while (index < count)
+ {
+ GUIDToString(szGuidKey,&types[index].type);
+ hres = RegCreateKeyExW(skey1, szGuidKey, 0, NULL,
+ REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &skey2, NULL);
+ GUIDToString(szGuidKey,&types[index].subtype);
+ hres = RegCreateKeyExW(skey2, szGuidKey, 0, NULL,
+ REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &skey3, NULL);
+ RegCloseKey(skey3);
+ RegCloseKey(skey2);
+ index ++;
+ }
+ RegCloseKey(skey1);
+ }
+
+ return hres;
+}
+
+/***************************************************************
+ * DMORegister (MSDMO.@)
+ *
+ * Register a DirectX Media Object.
+ */
+HRESULT WINAPI DMORegister(
+ LPCWSTR szName,
+ REFCLSID clsidDMO,
+ REFGUID guidCategory,
+ DWORD dwFlags,
+ DWORD cInTypes,
+ const DMO_PARTIAL_MEDIATYPE *pInTypes,
+ DWORD cOutTypes,
+ const DMO_PARTIAL_MEDIATYPE *pOutTypes
+)
+{
+ WCHAR szguid[64];
+ HRESULT hres;
+ HKEY hrkey = 0;
+ HKEY hkey = 0;
+ HKEY hckey = 0;
+ HKEY hclskey = 0;
+
+ TRACE("%s\n", debugstr_w(szName));
+
+ hres = RegCreateKeyExW(HKEY_CLASSES_ROOT, szDMORootKey, 0, NULL,
+ REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hrkey, NULL);
+ if (ERROR_SUCCESS != hres)
+ goto lend;
+
+ /* Create clsidDMO key under MediaObjects */
+ hres = RegCreateKeyExW(hrkey, GUIDToString(szguid, clsidDMO), 0, NULL,
+ REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, NULL);
+ if (ERROR_SUCCESS != hres)
+ goto lend;
+
+ /* Set default Name value */
+ hres = RegSetValueExW(hkey, NULL, 0, REG_SZ, (const BYTE*) szName,
+ (strlenW(szName) + 1) * sizeof(WCHAR));
+
+ /* Set InputTypes */
+ hres = write_types(hkey, szDMOInputType, pInTypes, cInTypes);
+
+ /* Set OutputTypes */
+ hres = write_types(hkey, szDMOOutputType, pOutTypes, cOutTypes);
+
+ if (dwFlags & DMO_REGISTERF_IS_KEYED)
+ {
+ /* Create Keyed key */
+ hres = RegCreateKeyExW(hkey, szDMOKeyed, 0, NULL,
+ REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hckey, NULL);
+ if (ERROR_SUCCESS != hres)
+ goto lend;
+ RegCloseKey(hckey);
+ }
+
+ /* Register the category */
+ hres = RegCreateKeyExW(hrkey, szDMOCategories, 0, NULL,
+ REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hckey, NULL);
+ if (ERROR_SUCCESS != hres)
+ goto lend;
+
+ RegCloseKey(hkey);
+
+ hres = RegCreateKeyExW(hckey, GUIDToString(szguid, guidCategory), 0, NULL,
+ REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, NULL);
+ if (ERROR_SUCCESS != hres)
+ goto lend;
+ hres = RegCreateKeyExW(hkey, GUIDToString(szguid, clsidDMO), 0, NULL,
+ REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hclskey, NULL);
+ if (ERROR_SUCCESS != hres)
+ goto lend;
+
+lend:
+ if (hkey)
+ RegCloseKey(hkey);
+ if (hckey)
+ RegCloseKey(hckey);
+ if (hclskey)
+ RegCloseKey(hclskey);
+ if (hrkey)
+ RegCloseKey(hrkey);
+
+ TRACE(" hresult=0x%08x\n", hres);
+ return hres;
+}
+
+
+/***************************************************************
+ * DMOUnregister (MSDMO.@)
+ *
+ * Unregister a DirectX Media Object.
+ */
+HRESULT WINAPI DMOUnregister(REFCLSID clsidDMO, REFGUID guidCategory)
+{
+ HRESULT hres;
+ WCHAR szguid[64];
+ HKEY hrkey = 0;
+ HKEY hckey = 0;
+
+ GUIDToString(szguid, clsidDMO);
+
+ TRACE("%s %p\n", debugstr_w(szguid), guidCategory);
+
+ hres = RegOpenKeyExW(HKEY_CLASSES_ROOT, szDMORootKey, 0, KEY_WRITE, &hrkey);
+ if (ERROR_SUCCESS != hres)
+ goto lend;
+
+ hres = RegDeleteKeyW(hrkey, szguid);
+ if (ERROR_SUCCESS != hres)
+ goto lend;
+
+ hres = RegOpenKeyExW(hrkey, szDMOCategories, 0, KEY_WRITE, &hckey);
+ if (ERROR_SUCCESS != hres)
+ goto lend;
+
+ hres = RegDeleteKeyW(hckey, szguid);
+ if (ERROR_SUCCESS != hres)
+ goto lend;
+
+lend:
+ if (hckey)
+ RegCloseKey(hckey);
+ if (hrkey)
+ RegCloseKey(hrkey);
+
+ return hres;
+}
+
+
+/***************************************************************
+ * DMOGetName (MSDMO.@)
+ *
+ * Get DMP Name from the registry
+ */
+HRESULT WINAPI DMOGetName(REFCLSID clsidDMO, WCHAR szName[])
+{
+ WCHAR szguid[64];
+ HRESULT hres;
+ HKEY hrkey = 0;
+ HKEY hkey = 0;
+ static const INT max_name_len = 80;
+ DWORD count;
+
+ TRACE("%s\n", debugstr_guid(clsidDMO));
+
+ hres = RegOpenKeyExW(HKEY_CLASSES_ROOT, szDMORootKey,
+ 0, KEY_READ, &hrkey);
+ if (ERROR_SUCCESS != hres)
+ goto lend;
+
+ hres = RegOpenKeyExW(hrkey, GUIDToString(szguid, clsidDMO),
+ 0, KEY_READ, &hkey);
+ if (ERROR_SUCCESS != hres)
+ goto lend;
+
+ count = max_name_len * sizeof(WCHAR);
+ hres = RegQueryValueExW(hkey, NULL, NULL, NULL,
+ (LPBYTE) szName, &count);
+
+ TRACE(" szName=%s\n", debugstr_w(szName));
+lend:
+ if (hkey)
+ RegCloseKey(hrkey);
+ if (hkey)
+ RegCloseKey(hkey);
+
+ return hres;
+}
+
+
+/**************************************************************************
+* IEnumDMOImpl_Destructor
+*/
+static BOOL IEnumDMOImpl_Destructor(IEnumDMOImpl* This)
+{
+ TRACE("%p\n", This);
+
+ if (This->hkey)
+ RegCloseKey(This->hkey);
+
+ HeapFree(GetProcessHeap(), 0, This->pInTypes);
+ HeapFree(GetProcessHeap(), 0, This->pOutTypes);
+
+ return TRUE;
+}
+
+
+/**************************************************************************
+ * IEnumDMO_Constructor
+ */
+static IEnumDMO * IEnumDMO_Constructor(
+ REFGUID guidCategory,
+ DWORD dwFlags,
+ DWORD cInTypes,
+ const DMO_PARTIAL_MEDIATYPE *pInTypes,
+ DWORD cOutTypes,
+ const DMO_PARTIAL_MEDIATYPE *pOutTypes)
+{
+ UINT size;
+ IEnumDMOImpl* lpedmo;
+ BOOL ret = FALSE;
+
+ lpedmo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumDMOImpl));
+
+ if (lpedmo)
+ {
+ lpedmo->ref = 1;
+ lpedmo->IEnumDMO_iface.lpVtbl = &edmovt;
+ lpedmo->index = -1;
+ lpedmo->guidCategory = guidCategory;
+ lpedmo->dwFlags = dwFlags;
+
+ if (cInTypes > 0)
+ {
+ size = cInTypes * sizeof(DMO_PARTIAL_MEDIATYPE);
+ lpedmo->pInTypes = HeapAlloc(GetProcessHeap(), 0, size);
+ if (!lpedmo->pInTypes)
+ goto lerr;
+ memcpy(lpedmo->pInTypes, pInTypes, size);
+ lpedmo->cInTypes = cInTypes;
+ }
+
+ if (cOutTypes > 0)
+ {
+ size = cOutTypes * sizeof(DMO_PARTIAL_MEDIATYPE);
+ lpedmo->pOutTypes = HeapAlloc(GetProcessHeap(), 0, size);
+ if (!lpedmo->pOutTypes)
+ goto lerr;
+ memcpy(lpedmo->pOutTypes, pOutTypes, size);
+ lpedmo->cOutTypes = cOutTypes;
+ }
+
+ /* If not filtering by category enum from media objects root */
+ if (IsEqualGUID(guidCategory, &GUID_NULL))
+ {
+ if (ERROR_SUCCESS == RegOpenKeyExW(HKEY_CLASSES_ROOT, szDMORootKey,
+ 0, KEY_READ, &lpedmo->hkey))
+ ret = TRUE;
+ }
+ else
+ {
+ WCHAR szguid[64];
+ WCHAR szKey[MAX_PATH];
+
+ wsprintfW(szKey, szCat3Fmt, szDMORootKey, szDMOCategories,
+ GUIDToString(szguid, guidCategory));
+ if (ERROR_SUCCESS == RegOpenKeyExW(HKEY_CLASSES_ROOT, szKey,
+ 0, KEY_READ, &lpedmo->hkey))
+ ret = TRUE;
+ }
+
+lerr:
+ if(!ret)
+ {
+ IEnumDMOImpl_Destructor(lpedmo);
+ HeapFree(GetProcessHeap(),0,lpedmo);
+ lpedmo = NULL;
+ }
+ }
+
+ TRACE("returning %p\n", lpedmo);
+
+ return (IEnumDMO*)lpedmo;
+}
+
+
+/******************************************************************************
+ * IEnumDMO_fnAddRef
+ */
+static ULONG WINAPI IEnumDMO_fnAddRef(IEnumDMO * iface)
+{
+ IEnumDMOImpl *This = impl_from_IEnumDMO(iface);
+ return InterlockedIncrement(&This->ref);
+}
+
+
+/**************************************************************************
+ * EnumDMO_QueryInterface
+ */
+static HRESULT WINAPI IEnumDMO_fnQueryInterface(
+ IEnumDMO* iface,
+ REFIID riid,
+ LPVOID *ppvObj)
+{
+ IEnumDMOImpl *This = impl_from_IEnumDMO(iface);
+
+ *ppvObj = NULL;
+
+ if(IsEqualIID(riid, &IID_IUnknown))
+ *ppvObj = This;
+ else if(IsEqualIID(riid, &IID_IEnumDMO))
+ *ppvObj = This;
+
+ if(*ppvObj)
+ {
+ IEnumDMO_fnAddRef(*ppvObj);
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+
+/******************************************************************************
+ * IEnumDMO_fnRelease
+ */
+static ULONG WINAPI IEnumDMO_fnRelease(IEnumDMO * iface)
+{
+ IEnumDMOImpl *This = impl_from_IEnumDMO(iface);
+ ULONG refCount = InterlockedDecrement(&This->ref);
+
+ if (!refCount)
+ {
+ IEnumDMOImpl_Destructor(This);
+ HeapFree(GetProcessHeap(),0,This);
+ }
+ return refCount;
+}
+
+
+/******************************************************************************
+ * IEnumDMO_fnNext
+ */
+static HRESULT WINAPI IEnumDMO_fnNext(
+ IEnumDMO * iface,
+ DWORD cItemsToFetch,
+ CLSID * pCLSID,
+ WCHAR ** Names,
+ DWORD * pcItemsFetched)
+{
+ FILETIME ft;
+ HKEY hkey;
+ WCHAR szNextKey[MAX_PATH];
+ WCHAR szGuidKey[64];
+ WCHAR szKey[MAX_PATH];
+ WCHAR szValue[MAX_PATH];
+ DWORD len;
+ UINT count = 0;
+ HRESULT hres = S_OK;
+
+ IEnumDMOImpl *This = impl_from_IEnumDMO(iface);
+
+ TRACE("--> (%p) %d %p %p %p\n", iface, cItemsToFetch, pCLSID, Names, pcItemsFetched);
+
+ if (!pCLSID || !Names || !pcItemsFetched)
+ return E_POINTER;
+
+ while (count < cItemsToFetch)
+ {
+ This->index++;
+
+ len = MAX_PATH;
+ hres = RegEnumKeyExW(This->hkey, This->index, szNextKey, &len, NULL, NULL, NULL, &ft);
+ if (hres != ERROR_SUCCESS)
+ break;
+
+ TRACE("found %s\n", debugstr_w(szNextKey));
+
+ if (!(This->dwFlags & DMO_ENUMF_INCLUDE_KEYED))
+ {
+ wsprintfW(szKey, szCat3Fmt, szDMORootKey, szNextKey, szDMOKeyed);
+ hres = RegOpenKeyExW(HKEY_CLASSES_ROOT, szKey, 0, KEY_READ, &hkey);
+ if (ERROR_SUCCESS == hres)
+ {
+ RegCloseKey(hkey);
+ /* Skip Keyed entries */
+ continue;
+ }
+ }
+
+ wsprintfW(szKey, szCat2Fmt, szDMORootKey, szNextKey);
+ hres = RegOpenKeyExW(HKEY_CLASSES_ROOT, szKey, 0, KEY_READ, &hkey);
+
+ if (This->pInTypes)
+ {
+ UINT i, j;
+ DWORD cInTypes;
+ DMO_PARTIAL_MEDIATYPE* pInTypes;
+
+ hres = read_types(hkey, szDMOInputType, &cInTypes,
+ sizeof(szValue)/sizeof(DMO_PARTIAL_MEDIATYPE),
+ (DMO_PARTIAL_MEDIATYPE*)szValue);
+
+ if (ERROR_SUCCESS != hres)
+ {
+ RegCloseKey(hkey);
+ continue;
+ }
+
+ pInTypes = (DMO_PARTIAL_MEDIATYPE*) szValue;
+
+ for (i = 0; i < This->cInTypes; i++)
+ {
+ for (j = 0; j < cInTypes; j++)
+ {
+ if (IsMediaTypeEqual(&pInTypes[j], &This->pInTypes[i]))
+ break;
+ }
+
+ if (j >= cInTypes)
+ break;
+ }
+
+ if (i < This->cInTypes)
+ {
+ RegCloseKey(hkey);
+ continue;
+ }
+ }
+
+ if (This->pOutTypes)
+ {
+ UINT i, j;
+ DWORD cOutTypes;
+ DMO_PARTIAL_MEDIATYPE* pOutTypes;
+
+ hres = read_types(hkey, szDMOOutputType, &cOutTypes,
+ sizeof(szValue)/sizeof(DMO_PARTIAL_MEDIATYPE),
+ (DMO_PARTIAL_MEDIATYPE*)szValue);
+
+ if (ERROR_SUCCESS != hres)
+ {
+ RegCloseKey(hkey);
+ continue;
+ }
+
+ pOutTypes = (DMO_PARTIAL_MEDIATYPE*) szValue;
+
+ for (i = 0; i < This->cOutTypes; i++)
+ {
+ for (j = 0; j < cOutTypes; j++)
+ {
+ if (IsMediaTypeEqual(&pOutTypes[j], &This->pOutTypes[i]))
+ break;
+ }
+
+ if (j >= cOutTypes)
+ break;
+ }
+
+ if (i < This->cOutTypes)
+ {
+ RegCloseKey(hkey);
+ continue;
+ }
+ }
+
+ /* Media object wasn't filtered so add it to return list */
+ Names[count] = NULL;
+ len = MAX_PATH * sizeof(WCHAR);
+ hres = RegQueryValueExW(hkey, NULL, NULL, NULL, (LPBYTE) szValue, &len);
+ if (ERROR_SUCCESS == hres)
+ {
- strcmpW(Names[count], szValue);
++ Names[count] = HeapAlloc(GetProcessHeap(), 0, (strlenW(szValue) + 1) * sizeof(WCHAR));
+ if (Names[count])
++ strcpyW(Names[count], szValue);
+ }
+ wsprintfW(szGuidKey,szToGuidFmt,szNextKey);
+ CLSIDFromString(szGuidKey, &pCLSID[count]);
+
+ TRACE("found match %s %s\n", debugstr_w(szValue), debugstr_w(szNextKey));
+ RegCloseKey(hkey);
+ count++;
+ }
+
+ *pcItemsFetched = count;
+ if (*pcItemsFetched < cItemsToFetch)
+ hres = S_FALSE;
+
+ TRACE("<-- %i found\n",count);
+ return hres;
+}
+
+
+/******************************************************************************
+ * IEnumDMO_fnSkip
+ */
+static HRESULT WINAPI IEnumDMO_fnSkip(IEnumDMO * iface, DWORD cItemsToSkip)
+{
+ IEnumDMOImpl *This = impl_from_IEnumDMO(iface);
+
+ This->index += cItemsToSkip;
+
+ return S_OK;
+}
+
+
+/******************************************************************************
+ * IEnumDMO_fnReset
+ */
+static HRESULT WINAPI IEnumDMO_fnReset(IEnumDMO * iface)
+{
+ IEnumDMOImpl *This = impl_from_IEnumDMO(iface);
+
+ This->index = -1;
+
+ return S_OK;
+}
+
+
+/******************************************************************************
+ * IEnumDMO_fnClone
+ */
+static HRESULT WINAPI IEnumDMO_fnClone(IEnumDMO * iface, IEnumDMO **ppEnum)
+{
+ IEnumDMOImpl *This = impl_from_IEnumDMO(iface);
+
+ FIXME("(%p)->() to (%p)->() E_NOTIMPL\n", This, ppEnum);
+
+ return E_NOTIMPL;
+}
+
+
+/***************************************************************
+ * DMOEnum (MSDMO.@)
+ *
+ * Enumerate DirectX Media Objects in the registry.
+ */
+HRESULT WINAPI DMOEnum(
+ REFGUID guidCategory,
+ DWORD dwFlags,
+ DWORD cInTypes,
+ const DMO_PARTIAL_MEDIATYPE *pInTypes,
+ DWORD cOutTypes,
+ const DMO_PARTIAL_MEDIATYPE *pOutTypes,
+ IEnumDMO **ppEnum)
+{
+ HRESULT hres = E_FAIL;
+
+ TRACE("guidCategory=%p dwFlags=0x%08x cInTypes=%d cOutTypes=%d\n",
+ guidCategory, dwFlags, cInTypes, cOutTypes);
+
+ *ppEnum = IEnumDMO_Constructor(guidCategory, dwFlags, cInTypes,
+ pInTypes, cOutTypes, pOutTypes);
+ if (*ppEnum)
+ hres = S_OK;
+
+ return hres;
+}
+
+
+static const IEnumDMOVtbl edmovt =
+{
+ IEnumDMO_fnQueryInterface,
+ IEnumDMO_fnAddRef,
+ IEnumDMO_fnRelease,
+ IEnumDMO_fnNext,
+ IEnumDMO_fnSkip,
+ IEnumDMO_fnReset,
+ IEnumDMO_fnClone,
+};
+
+
+HRESULT read_types(HKEY root, LPCWSTR key, ULONG *supplied, ULONG requested, DMO_PARTIAL_MEDIATYPE* types )
+{
+ HRESULT ret = S_OK;
+ if (MSDMO_MAJOR_VERSION > 5)
+ {
+ DWORD len;
+ len = requested * sizeof(DMO_PARTIAL_MEDIATYPE);
+ ret = RegQueryValueExW(root, key, NULL, NULL, (LPBYTE) types, &len);
+ *supplied = len / sizeof(DMO_PARTIAL_MEDIATYPE);
+ }
+ else
+ {
+ HKEY hkey;
+ WCHAR szGuidKey[64];
+
+ *supplied = 0;
+ if (ERROR_SUCCESS == RegOpenKeyExW(root, key, 0, KEY_READ, &hkey))
+ {
+ int index = 0;
+ WCHAR szNextKey[MAX_PATH];
+ DWORD len;
+ LONG rc = ERROR_SUCCESS;
+
+ while (rc == ERROR_SUCCESS)
+ {
+ len = MAX_PATH;
+ rc = RegEnumKeyExW(hkey, index, szNextKey, &len, NULL, NULL, NULL, NULL);
+ if (rc == ERROR_SUCCESS)
+ {
+ HKEY subk;
+ int sub_index = 0;
+ LONG rcs = ERROR_SUCCESS;
+ WCHAR szSubKey[MAX_PATH];
+
+ RegOpenKeyExW(hkey, szNextKey, 0, KEY_READ, &subk);
+ while (rcs == ERROR_SUCCESS)
+ {
+ len = MAX_PATH;
+ rcs = RegEnumKeyExW(subk, sub_index, szSubKey, &len, NULL, NULL, NULL, NULL);
+ if (rcs == ERROR_SUCCESS)
+ {
+ if (*supplied >= requested)
+ {
+ /* Bailing */
+ ret = S_FALSE;
+ rc = ERROR_MORE_DATA;
+ rcs = ERROR_MORE_DATA;
+ break;
+ }
+
+ wsprintfW(szGuidKey,szToGuidFmt,szNextKey);
+ CLSIDFromString(szGuidKey, &types[*supplied].type);
+ wsprintfW(szGuidKey,szToGuidFmt,szSubKey);
+ CLSIDFromString(szGuidKey, &types[*supplied].subtype);
+ TRACE("Adding type %s subtype %s at index %i\n",
+ debugstr_guid(&types[*supplied].type),
+ debugstr_guid(&types[*supplied].subtype),
+ *supplied);
+ (*supplied)++;
+ }
+ sub_index++;
+ }
+ index++;
+ }
+ }
+ RegCloseKey(hkey);
+ }
+ }
+ return ret;
+}
+
+/***************************************************************
+ * DMOGetTypes (MSDMO.@)
+ */
+HRESULT WINAPI DMOGetTypes(REFCLSID clsidDMO,
+ ULONG ulInputTypesRequested,
+ ULONG* pulInputTypesSupplied,
+ DMO_PARTIAL_MEDIATYPE* pInputTypes,
+ ULONG ulOutputTypesRequested,
+ ULONG* pulOutputTypesSupplied,
+ DMO_PARTIAL_MEDIATYPE* pOutputTypes)
+{
+ HKEY root,hkey;
+ HRESULT ret = S_OK;
+ WCHAR szguid[64];
+
+ TRACE ("(%s,%u,%p,%p,%u,%p,%p)\n", debugstr_guid(clsidDMO), ulInputTypesRequested,
+ pulInputTypesSupplied, pInputTypes, ulOutputTypesRequested, pulOutputTypesSupplied,
+ pOutputTypes);
+
+ if (ERROR_SUCCESS != RegOpenKeyExW(HKEY_CLASSES_ROOT, szDMORootKey, 0,
+ KEY_READ, &root))
+ return E_FAIL;
+
+ if (ERROR_SUCCESS != RegOpenKeyExW(root,GUIDToString(szguid,clsidDMO) , 0,
+ KEY_READ, &hkey))
+ {
+ RegCloseKey(root);
+ return E_FAIL;
+ }
+
+ if (ulInputTypesRequested > 0)
+ {
+ ret = read_types(hkey, szDMOInputType, pulInputTypesSupplied, ulInputTypesRequested, pInputTypes );
+ }
+ else
+ *pulInputTypesSupplied = 0;
+
+ if (ulOutputTypesRequested > 0)
+ {
+ HRESULT ret2;
+ ret2 = read_types(hkey, szDMOOutputType, pulOutputTypesSupplied, ulOutputTypesRequested, pOutputTypes );
+
+ if (ret == S_OK)
+ ret = ret2;
+ }
+ else
+ *pulOutputTypesSupplied = 0;
+
+ return ret;
+}
--- /dev/null
+
+spec2def(ntdll.dll def/ntdll.spec ADD_IMPORTLIB)
+
+add_definitions(
+ -D__NTDLL__
+ -D_NTOSKRNL_
+ -DCRTDLL)
+
+include_directories(
+ BEFORE include
+ ${REACTOS_SOURCE_DIR}/include/reactos/subsys
+ ${REACTOS_SOURCE_DIR}/win32ss/include)
+
+list(APPEND SOURCE
+ csr/api.c
+ csr/capture.c
+ csr/connect.c
+ dbg/dbgui.c
+ ldr/ldrapi.c
+ ldr/ldrinit.c
+ ldr/ldrpe.c
+ ldr/ldrutils.c
+ rtl/libsupp.c
+ rtl/version.c
+ include/ntdll.h)
+
+if(ARCH STREQUAL "i386")
+ list(APPEND ASM_SOURCE dispatch/i386/dispatch.S)
+elseif(ARCH STREQUAL "amd64")
+ list(APPEND ASM_SOURCE dispatch/amd64/dispatch.S)
+elseif(ARCH STREQUAL "arm")
+ list(APPEND ASM_SOURCE dispatch/arm/stubs_asm.s)
+else()
+ list(APPEND SOURCE dispatch/dispatch.c)
+endif()
+
+add_asm_files(ntdll_asm ${ASM_SOURCE})
+
+add_library(ntdll SHARED
+ ${SOURCE}
+ ${ntdll_asm}
+ def/ntdll.rc
++ ${CMAKE_CURRENT_BINARY_DIR}/ntdll_stubs.c
+ ${CMAKE_CURRENT_BINARY_DIR}/ntdll.def)
+
+set_module_type(ntdll win32dll HOTPATCHABLE ENTRYPOINT 0)
+#############################################
+## HACK FOR MSVC COMPILATION WITH win32dll ##
+set_subsystem(ntdll console)
+################# END HACK #################
+
+if(MSVC)
+ add_target_link_flags(ntdll "/RELEASE")
+endif()
+
+target_link_libraries(ntdll
+ rtl
+ ntdllsys
+ libcntpr
+ uuid
+ ${PSEH_LIB})
+
+add_pch(ntdll include/ntdll.h SOURCE)
+add_dependencies(ntdll ntstatus asm)
+
+add_cd_file(TARGET ntdll DESTINATION reactos/system32 NO_CAB FOR all)
+
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * FILE: dll/ntdll/csr/capture.c
+ * PURPOSE: Routines for probing and capturing CSR API Messages
+ * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <ntdll.h>
+
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS ********************************************************************/
+
+extern HANDLE CsrPortHeap;
+
+/* FUNCTIONS ******************************************************************/
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+CsrProbeForRead(IN PVOID Address,
+ IN ULONG Length,
+ IN ULONG Alignment)
+{
+ volatile UCHAR *Pointer;
+ UCHAR Data;
+
+ /* Validate length */
+ if (Length == 0) return;
+
+ /* Validate alignment */
+ if ((ULONG_PTR)Address & (Alignment - 1))
+ {
+ /* Raise exception if it doesn't match */
+ RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
+ }
+
+ /* Probe first byte */
+ Pointer = Address;
+ Data = *Pointer;
+
+ /* Probe last byte */
+ Pointer = (PUCHAR)Address + Length - 1;
+ Data = *Pointer;
+ (void)Data;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+CsrProbeForWrite(IN PVOID Address,
+ IN ULONG Length,
+ IN ULONG Alignment)
+{
+ volatile UCHAR *Pointer;
+
+ /* Validate length */
+ if (Length == 0) return;
+
+ /* Validate alignment */
+ if ((ULONG_PTR)Address & (Alignment - 1))
+ {
+ /* Raise exception if it doesn't match */
+ RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
+ }
+
+ /* Probe first byte */
+ Pointer = Address;
+ *Pointer = *Pointer;
+
+ /* Probe last byte */
+ Pointer = (PUCHAR)Address + Length - 1;
+ *Pointer = *Pointer;
+}
+
+/*
+ * @implemented
+ */
+PCSR_CAPTURE_BUFFER
+NTAPI
+CsrAllocateCaptureBuffer(IN ULONG ArgumentCount,
+ IN ULONG BufferSize)
+{
+ PCSR_CAPTURE_BUFFER CaptureBuffer;
+
+ /* Validate size */
+ if (BufferSize >= MAXLONG) return NULL;
+
+ /* Add the size of the header and for each offset to the pointers */
+ BufferSize += FIELD_OFFSET(CSR_CAPTURE_BUFFER, PointerOffsetsArray) +
+ (ArgumentCount * sizeof(ULONG_PTR));
+
+ /* Align it to a 4-byte boundary */
+ BufferSize = (BufferSize + 3) & ~3;
+
++ /* Add the size of the alignment padding for each argument */
++ BufferSize += ArgumentCount * 3;
++
+ /* Allocate memory from the port heap */
+ CaptureBuffer = RtlAllocateHeap(CsrPortHeap, HEAP_ZERO_MEMORY, BufferSize);
+ if (CaptureBuffer == NULL) return NULL;
+
+ /* Initialize the header */
+ CaptureBuffer->Size = BufferSize;
+ CaptureBuffer->PointerCount = 0;
+
+ /* Initialize all the offsets */
+ RtlZeroMemory(CaptureBuffer->PointerOffsetsArray,
+ ArgumentCount * sizeof(ULONG_PTR));
+
+ /* Point to the start of the free buffer */
+ CaptureBuffer->BufferEnd = (PVOID)((ULONG_PTR)CaptureBuffer->PointerOffsetsArray +
+ ArgumentCount * sizeof(ULONG_PTR));
+
+ /* Return the address of the buffer */
+ return CaptureBuffer;
+}
+
+/*
+ * @implemented
+ */
+ULONG
+NTAPI
+CsrAllocateMessagePointer(IN OUT PCSR_CAPTURE_BUFFER CaptureBuffer,
+ IN ULONG MessageLength,
+ OUT PVOID* CapturedData)
+{
+ if (MessageLength == 0)
+ {
+ *CapturedData = NULL;
+ CapturedData = NULL;
+ }
+ else
+ {
+ /* Set the capture data at our current available buffer */
+ *CapturedData = CaptureBuffer->BufferEnd;
+
+ /* Validate the size */
+ if (MessageLength >= MAXLONG) return 0;
+
+ /* Align it to a 4-byte boundary */
+ MessageLength = (MessageLength + 3) & ~3;
+
+ /* Move our available buffer beyond this space */
+ CaptureBuffer->BufferEnd = (PVOID)((ULONG_PTR)CaptureBuffer->BufferEnd + MessageLength);
+ }
+
+ /* Write down this pointer in the array and increase the count */
+ CaptureBuffer->PointerOffsetsArray[CaptureBuffer->PointerCount++] = (ULONG_PTR)CapturedData;
+
+ /* Return the aligned length */
+ return MessageLength;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+CsrCaptureMessageBuffer(IN OUT PCSR_CAPTURE_BUFFER CaptureBuffer,
+ IN PVOID MessageBuffer OPTIONAL,
+ IN ULONG MessageLength,
+ OUT PVOID* CapturedData)
+{
+ /* Simply allocate a message pointer in the buffer */
+ CsrAllocateMessagePointer(CaptureBuffer, MessageLength, CapturedData);
+
+ /* Check if there was any data */
+ if (!MessageBuffer || !MessageLength) return;
+
+ /* Copy the data into the buffer */
+ RtlMoveMemory(*CapturedData, MessageBuffer, MessageLength);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+CsrFreeCaptureBuffer(IN PCSR_CAPTURE_BUFFER CaptureBuffer)
+{
+ /* Free it from the heap */
+ RtlFreeHeap(CsrPortHeap, 0, CaptureBuffer);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+CsrCaptureMessageString(IN OUT PCSR_CAPTURE_BUFFER CaptureBuffer,
+ IN PCSTR String OPTIONAL,
+ IN ULONG StringLength,
+ IN ULONG MaximumLength,
+ OUT PSTRING CapturedString)
+{
+ ASSERT(CapturedString != NULL);
+
+ /*
+ * If we don't have a string, initialize an empty one,
+ * otherwise capture the given string.
+ */
+ if (!String)
+ {
+ CapturedString->Length = 0;
+ CapturedString->MaximumLength = (USHORT)MaximumLength;
+
+ /* Allocate a pointer for it */
+ CsrAllocateMessagePointer(CaptureBuffer,
+ MaximumLength,
+ (PVOID*)&CapturedString->Buffer);
+ }
+ else
+ {
+ /* Cut-off the string length if needed */
+ if (StringLength > MaximumLength)
+ StringLength = MaximumLength;
+
+ CapturedString->Length = (USHORT)StringLength;
+
+ /* Allocate a buffer and get its size */
+ CapturedString->MaximumLength =
+ (USHORT)CsrAllocateMessagePointer(CaptureBuffer,
+ MaximumLength,
+ (PVOID*)&CapturedString->Buffer);
+
+ /* If the string has data, copy it into the buffer */
+ if (StringLength)
+ RtlMoveMemory(CapturedString->Buffer, String, StringLength);
+ }
+
+ /* Null-terminate the string if we don't take up the whole space */
+ if (CapturedString->Length < CapturedString->MaximumLength)
+ CapturedString->Buffer[CapturedString->Length] = '\0';
+}
+
+static VOID
+CsrCaptureMessageUnicodeStringInPlace(IN OUT PCSR_CAPTURE_BUFFER CaptureBuffer,
+ IN PUNICODE_STRING String)
+{
+ ASSERT(String != NULL);
+
+ /* This is a way to capture the UNICODE string, since (Maximum)Length are also in bytes */
+ CsrCaptureMessageString(CaptureBuffer,
+ (PCSTR)String->Buffer,
+ String->Length,
+ String->MaximumLength,
+ (PSTRING)String);
+
+ /* Null-terminate the string */
+ if (String->MaximumLength >= String->Length + sizeof(WCHAR))
+ {
+ String->Buffer[String->Length / sizeof(WCHAR)] = L'\0';
+ }
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+CsrCaptureMessageMultiUnicodeStringsInPlace(OUT PCSR_CAPTURE_BUFFER* CaptureBuffer,
+ IN ULONG StringsCount,
+ IN PUNICODE_STRING* MessageStrings)
+{
+ ULONG Count;
+
+ if (!CaptureBuffer) return STATUS_INVALID_PARAMETER;
+
+ /* Allocate a new capture buffer if we don't have one already */
+ if (!*CaptureBuffer)
+ {
+ /* Compute the required size for the capture buffer */
+ ULONG Size = 0;
+
+ Count = 0;
+ while (Count < StringsCount)
+ {
+ if (MessageStrings[Count])
+ Size += MessageStrings[Count]->MaximumLength;
+
+ ++Count;
+ }
+
+ /* Allocate the capture buffer */
+ *CaptureBuffer = CsrAllocateCaptureBuffer(StringsCount, Size);
+ if (!*CaptureBuffer) return STATUS_NO_MEMORY;
+ }
+
+ /* Now capture each UNICODE string */
+ Count = 0;
+ while (Count < StringsCount)
+ {
+ if (MessageStrings[Count])
+ CsrCaptureMessageUnicodeStringInPlace(*CaptureBuffer, MessageStrings[Count]);
+
+ ++Count;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+PLARGE_INTEGER
+NTAPI
+CsrCaptureTimeout(IN ULONG Milliseconds,
+ OUT PLARGE_INTEGER Timeout)
+{
+ /* Validate the time */
+ if (Milliseconds == -1) return NULL;
+
+ /* Convert to relative ticks */
+ Timeout->QuadPart = Int32x32To64(Milliseconds, -10000);
+ return Timeout;
+}
+
+/* EOF */
--- /dev/null
- ;@ stdcall NtGetTickCount()
+
+@ stdcall CsrAllocateCaptureBuffer(long long)
+@ stdcall CsrAllocateMessagePointer(ptr long ptr)
+@ stdcall CsrCaptureMessageBuffer(ptr ptr long ptr)
+@ stdcall CsrCaptureMessageMultiUnicodeStringsInPlace(ptr long ptr)
+@ stdcall CsrCaptureMessageString(ptr str long long ptr)
+@ stdcall CsrCaptureTimeout(long ptr)
+@ stdcall CsrClientCallServer(ptr ptr long long)
+@ stdcall CsrClientConnectToServer(str long ptr ptr ptr)
+@ stdcall CsrFreeCaptureBuffer(ptr)
+@ stdcall CsrGetProcessId()
+@ stdcall CsrIdentifyAlertableThread()
+@ stdcall CsrNewThread()
+@ stdcall CsrProbeForRead(ptr long long)
+@ stdcall CsrProbeForWrite(ptr long long)
+@ stdcall CsrSetPriorityClass(ptr ptr)
+@ stdcall DbgBreakPoint()
+@ varargs DbgPrint(str)
+@ varargs DbgPrintEx(long long str)
+@ varargs DbgPrintReturnControlC(str)
+@ stdcall DbgPrompt(ptr ptr long)
+@ stdcall DbgQueryDebugFilterState(long long)
+@ stdcall DbgSetDebugFilterState(long long long)
+@ stdcall DbgUiConnectToDbg()
+@ stdcall DbgUiContinue(ptr long)
+@ stdcall DbgUiConvertStateChangeStructure(ptr ptr)
+@ stdcall DbgUiDebugActiveProcess(ptr)
+@ stdcall DbgUiGetThreadDebugObject()
+@ stdcall DbgUiIssueRemoteBreakin(ptr)
+@ stdcall DbgUiRemoteBreakin()
+@ stdcall DbgUiSetThreadDebugObject(ptr)
+@ stdcall DbgUiStopDebugging(ptr)
+@ stdcall DbgUiWaitStateChange(ptr ptr)
+@ stdcall DbgUserBreakPoint()
+@ stdcall -arch=i386 KiFastSystemCall()
+@ stdcall -arch=i386 KiFastSystemCallRet()
+@ stdcall -arch=i386 KiIntSystemCall()
+@ stdcall -arch=i386,x86_64 ExpInterlockedPopEntrySListEnd()
+@ stdcall -arch=i386,x86_64 ExpInterlockedPopEntrySListFault()
+@ stdcall -arch=i386,x86_64 ExpInterlockedPopEntrySListResume()
+@ stdcall KiRaiseUserExceptionDispatcher()
+@ stdcall KiUserApcDispatcher(ptr ptr ptr ptr)
+@ stdcall KiUserCallbackDispatcher(ptr ptr long) ; CHECKME
+@ stdcall KiUserExceptionDispatcher(ptr ptr)
+@ stdcall LdrAccessOutOfProcessResource(ptr ptr ptr ptr ptr)
+@ stdcall LdrAccessResource(long ptr ptr ptr)
+@ stdcall LdrAddRefDll(long ptr)
+;@ stdcall LdrAlternateResourcesEnabled
+@ stdcall LdrCreateOutOfProcessImage(long ptr ptr ptr)
+@ stdcall LdrDestroyOutOfProcessImage(ptr)
+@ stdcall LdrDisableThreadCalloutsForDll(long)
+@ stdcall LdrEnumResources(ptr ptr long ptr ptr)
+@ stdcall LdrEnumerateLoadedModules(long ptr long)
+@ stdcall LdrFindCreateProcessManifest(long ptr ptr long ptr) ; 5.1 and 5.2 only
+@ stdcall LdrFindEntryForAddress(ptr ptr)
+@ stdcall LdrFindResourceDirectory_U(long ptr long ptr)
+;@ stdcall LdrFindResourceEx_U ; 5.1 and higher
+@ stdcall LdrFindResource_U(long ptr long ptr)
+@ stdcall LdrFlushAlternateResourceModules()
+@ stdcall LdrGetDllHandle(wstr long ptr ptr)
+@ stdcall LdrGetDllHandleEx(long wstr long ptr ptr)
+@ stdcall LdrGetProcedureAddress(ptr ptr long ptr)
+;@ stdcall LdrHotPatchRoutine
+;@ stdcall LdrInitShimEngineDynamic
+@ stdcall LdrInitializeThunk(long long long long)
+@ stdcall LdrLoadAlternateResourceModule(ptr ptr)
+@ stdcall LdrLoadDll(wstr long ptr ptr)
+@ stdcall LdrLockLoaderLock(long ptr ptr)
+@ stdcall LdrOpenImageFileOptionsKey(ptr long ptr) ; 5.2 SP1 and higher
+@ stdcall LdrProcessRelocationBlock(ptr long ptr long)
+@ stdcall LdrQueryImageFileExecutionOptions(ptr str long ptr long ptr)
+@ stdcall LdrQueryImageFileKeyOption(ptr ptr long ptr long ptr)
+@ stdcall LdrQueryProcessModuleInformation(ptr long ptr)
+;@ stdcall LdrSetAppCompatDllRedirectionCallback
+@ stdcall LdrSetDllManifestProber(ptr)
+@ stdcall LdrShutdownProcess()
+@ stdcall LdrShutdownThread()
+@ stdcall LdrUnloadAlternateResourceModule(ptr)
+@ stdcall LdrUnloadDll(ptr)
+@ stdcall LdrUnlockLoaderLock(long long)
+@ stdcall LdrVerifyImageMatchesChecksum(ptr long long long)
+@ extern NlsAnsiCodePage
+@ extern NlsMbCodePageTag
+@ extern NlsMbOemCodePageTag
+@ stdcall NtAcceptConnectPort(ptr long ptr long long ptr)
+@ stdcall NtAccessCheck(ptr long long ptr ptr ptr ptr ptr)
+@ stdcall NtAccessCheckAndAuditAlarm(ptr long ptr ptr ptr long ptr long ptr ptr ptr)
+@ stdcall NtAccessCheckByType(ptr ptr ptr long ptr long ptr ptr long ptr ptr)
+@ stdcall NtAccessCheckByTypeAndAuditAlarm(ptr ptr ptr ptr ptr ptr long long long ptr long ptr long ptr ptr ptr)
+@ stdcall NtAccessCheckByTypeResultList(ptr ptr ptr long ptr long ptr ptr long ptr ptr)
+@ stdcall NtAccessCheckByTypeResultListAndAuditAlarm(ptr ptr ptr ptr ptr ptr long long long ptr long ptr long ptr ptr ptr)
+@ stdcall NtAccessCheckByTypeResultListAndAuditAlarmByHandle(ptr ptr ptr ptr ptr ptr ptr long long long ptr long ptr long ptr ptr ptr)
+@ stdcall NtAddAtom(ptr long ptr)
+@ stdcall NtAddBootEntry(ptr long)
+@ stdcall NtAddDriverEntry(ptr long) ; 5.2 and higher
+@ stdcall NtAdjustGroupsToken(long long ptr long ptr ptr)
+@ stdcall NtAdjustPrivilegesToken(long long long long long long)
+@ stdcall NtAlertResumeThread(long ptr)
+@ stdcall NtAlertThread(long)
+@ stdcall NtAllocateLocallyUniqueId(ptr)
+@ stdcall NtAllocateUserPhysicalPages(ptr ptr ptr)
+@ stdcall NtAllocateUuids(ptr ptr ptr ptr)
+@ stdcall NtAllocateVirtualMemory(long ptr ptr ptr long long)
+@ stdcall NtApphelpCacheControl(long ptr)
+@ stdcall NtAreMappedFilesTheSame(ptr ptr)
+@ stdcall NtAssignProcessToJobObject(long long)
+@ stdcall NtCallbackReturn(ptr long long)
+@ stdcall NtCancelDeviceWakeupRequest(ptr)
+@ stdcall NtCancelIoFile(long ptr)
+@ stdcall NtCancelTimer(long ptr)
+@ stdcall NtClearEvent(long)
+@ stdcall NtClose(long)
+@ stdcall NtCloseObjectAuditAlarm(ptr ptr long)
+@ stdcall NtCompactKeys(long ptr)
+@ stdcall NtCompareTokens(ptr ptr ptr)
+@ stdcall NtCompleteConnectPort(ptr)
+@ stdcall NtCompressKey(ptr)
+@ stdcall NtConnectPort(ptr ptr ptr ptr ptr ptr ptr ptr)
+@ stdcall NtContinue(ptr long)
+@ stdcall NtCreateDebugObject(ptr long ptr long)
+@ stdcall NtCreateDirectoryObject(long long long)
+@ stdcall NtCreateEvent(long long long long long)
+@ stdcall NtCreateEventPair(ptr long ptr)
+@ stdcall NtCreateFile(ptr long ptr ptr long long long ptr long long ptr)
+@ stdcall NtCreateIoCompletion(ptr long ptr long)
+@ stdcall NtCreateJobObject(ptr long ptr)
+@ stdcall NtCreateJobSet(long ptr long)
+@ stdcall NtCreateKey(ptr long ptr long ptr long long)
+@ stdcall NtCreateKeyedEvent(ptr long ptr long)
+@ stdcall NtCreateMailslotFile(long long long long long long long long)
+@ stdcall NtCreateMutant(ptr long ptr long)
+@ stdcall NtCreateNamedPipeFile(ptr long ptr ptr long long long long long long long long long ptr)
+@ stdcall NtCreatePagingFile(long long long long)
+@ stdcall NtCreatePort(ptr ptr long long ptr)
+@ stdcall NtCreateProcess(ptr long ptr ptr long ptr ptr ptr)
+@ stdcall NtCreateProcessEx(ptr long ptr ptr long ptr ptr ptr long)
+@ stdcall NtCreateProfile(ptr ptr ptr long long ptr long long long) ; CHECKME
+@ stdcall NtCreateSection(ptr long ptr ptr long long long)
+@ stdcall NtCreateSemaphore(ptr long ptr long long)
+@ stdcall NtCreateSymbolicLinkObject(ptr long ptr ptr)
+@ stdcall NtCreateThread(ptr long ptr ptr ptr ptr ptr long)
+@ stdcall NtCreateTimer(ptr long ptr long)
+@ stdcall NtCreateToken(ptr long ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr)
+@ stdcall NtCreateWaitablePort(ptr ptr long long long)
+@ stdcall -arch=win32 NtCurrentTeb() _NtCurrentTeb
+@ stdcall NtDebugActiveProcess(ptr ptr)
+@ stdcall NtDebugContinue(ptr ptr long)
+@ stdcall NtDelayExecution(long ptr)
+@ stdcall NtDeleteAtom(long)
+@ stdcall NtDeleteBootEntry(long)
+@ stdcall NtDeleteFile(ptr)
+@ stdcall NtDeleteKey(long)
+@ stdcall NtDeleteObjectAuditAlarm(ptr ptr long)
+@ stdcall NtDeleteValueKey(long ptr)
+@ stdcall NtDeviceIoControlFile(long long long long long long long long long long)
+@ stdcall NtDisplayString(ptr)
+@ stdcall NtDuplicateObject(long long long ptr long long long)
+@ stdcall NtDuplicateToken(long long long long long long)
+@ stdcall NtEnumerateBootEntries(ptr ptr)
+@ stdcall NtEnumerateKey (long long long long long long)
+@ stdcall NtEnumerateSystemEnvironmentValuesEx(long ptr long)
+@ stdcall NtEnumerateValueKey(long long long long long long)
+@ stdcall NtExtendSection(ptr ptr)
+@ stdcall NtFilterToken(ptr long ptr ptr ptr ptr)
+@ stdcall NtFindAtom(ptr long ptr)
+@ stdcall NtFlushBuffersFile(long ptr)
+@ stdcall NtFlushInstructionCache(long ptr long)
+@ stdcall NtFlushKey(long)
+@ stdcall NtFlushVirtualMemory(long ptr ptr long)
+@ stdcall NtFlushWriteBuffer()
+@ stdcall NtFreeUserPhysicalPages(ptr ptr ptr)
+@ stdcall NtFreeVirtualMemory(long ptr ptr long)
+@ stdcall NtFsControlFile(long long long long long long long long long long)
+@ stdcall NtGetContextThread(long ptr)
+@ stdcall NtGetCurrentProcessorNumber() ; 5.2 and higher
+@ stdcall NtGetDevicePowerState(ptr ptr)
+@ stdcall NtGetPlugPlayEvent(long long ptr long)
++@ stdcall -stub NtGetTickCount()
+@ stdcall NtGetWriteWatch(long long ptr long ptr ptr ptr)
+@ stdcall NtImpersonateAnonymousToken(ptr)
+@ stdcall NtImpersonateClientOfPort(ptr ptr)
+@ stdcall NtImpersonateThread(ptr ptr ptr)
+@ stdcall NtInitializeRegistry(long)
+@ stdcall NtInitiatePowerAction (long long long long)
+@ stdcall NtIsProcessInJob(long long)
+@ stdcall NtIsSystemResumeAutomatic()
+@ stdcall NtListenPort(ptr ptr)
+@ stdcall NtLoadDriver(ptr)
+@ stdcall NtLoadKey2(ptr ptr long)
+@ stdcall NtLoadKey(ptr ptr)
+@ stdcall NtLockFile(long long ptr ptr ptr ptr ptr ptr long long)
+@ stdcall NtLockProductActivationKeys(ptr ptr)
+@ stdcall NtLockRegistryKey(ptr)
+@ stdcall NtLockVirtualMemory(long ptr ptr long)
+@ stdcall NtMakePermanentObject(ptr)
+@ stdcall NtMakeTemporaryObject(long)
+@ stdcall NtMapUserPhysicalPages(ptr ptr ptr)
+@ stdcall NtMapUserPhysicalPagesScatter(ptr ptr ptr)
+@ stdcall NtMapViewOfSection(long long ptr long long ptr ptr long long long)
+@ stdcall NtModifyBootEntry(ptr)
+@ stdcall NtNotifyChangeDirectoryFile(long long ptr ptr ptr ptr long long long)
+@ stdcall NtNotifyChangeKey(long long ptr ptr ptr long long ptr long long)
+@ stdcall NtNotifyChangeMultipleKeys(ptr long ptr ptr ptr ptr ptr long long ptr long long)
+@ stdcall NtOpenDirectoryObject(long long long)
+@ stdcall NtOpenEvent(long long long)
+@ stdcall NtOpenEventPair(ptr long ptr)
+@ stdcall NtOpenFile(ptr long ptr ptr long long)
+@ stdcall NtOpenIoCompletion(ptr long ptr)
+@ stdcall NtOpenJobObject(ptr long ptr)
+@ stdcall NtOpenKey(ptr long ptr)
+@ stdcall NtOpenKeyedEvent(ptr long ptr)
+@ stdcall NtOpenMutant(ptr long ptr)
+@ stdcall NtOpenObjectAuditAlarm(ptr ptr ptr ptr ptr ptr long long ptr long long ptr)
+@ stdcall NtOpenProcess(ptr long ptr ptr)
+@ stdcall NtOpenProcessToken(long long ptr)
+@ stdcall NtOpenProcessTokenEx(long long long ptr)
+@ stdcall NtOpenSection(ptr long ptr)
+@ stdcall NtOpenSemaphore(long long ptr)
+@ stdcall NtOpenSymbolicLinkObject (ptr long ptr)
+@ stdcall NtOpenThread(ptr long ptr ptr)
+@ stdcall NtOpenThreadToken(long long long ptr)
+@ stdcall NtOpenThreadTokenEx(long long long long ptr)
+@ stdcall NtOpenTimer(ptr long ptr)
+@ stdcall NtPlugPlayControl(ptr ptr long)
+@ stdcall NtPowerInformation(long ptr long ptr long)
+@ stdcall NtPrivilegeCheck(ptr ptr ptr)
+@ stdcall NtPrivilegeObjectAuditAlarm(ptr ptr ptr long ptr long)
+@ stdcall NtPrivilegedServiceAuditAlarm(ptr ptr ptr ptr long)
+@ stdcall NtProtectVirtualMemory(long ptr ptr long ptr)
+@ stdcall NtPulseEvent(long ptr)
+@ stdcall NtQueryAttributesFile(ptr ptr)
+@ stdcall NtQueryBootEntryOrder(ptr ptr)
+@ stdcall NtQueryBootOptions(ptr ptr)
+@ stdcall NtQueryDebugFilterState(long long)
+@ stdcall NtQueryDefaultLocale(long ptr)
+@ stdcall NtQueryDefaultUILanguage(ptr)
+@ stdcall NtQueryDirectoryFile(long long ptr ptr ptr ptr long long long ptr long)
+@ stdcall NtQueryDirectoryObject(long ptr long long long ptr ptr)
+@ stdcall NtQueryEaFile(long ptr ptr long long ptr long ptr long)
+@ stdcall NtQueryEvent(long long ptr long ptr)
+@ stdcall NtQueryFullAttributesFile(ptr ptr)
+@ stdcall NtQueryInformationAtom(long long ptr long ptr)
+@ stdcall NtQueryInformationFile(long ptr ptr long long)
+@ stdcall NtQueryInformationJobObject(long long ptr long ptr)
+@ stdcall NtQueryInformationPort(ptr long ptr long ptr)
+@ stdcall NtQueryInformationProcess(long long ptr long ptr)
+@ stdcall NtQueryInformationThread(long long ptr long ptr)
+@ stdcall NtQueryInformationToken(long long ptr long ptr)
+@ stdcall NtQueryInstallUILanguage(ptr)
+@ stdcall NtQueryIntervalProfile(long ptr)
+@ stdcall NtQueryIoCompletion(long long ptr long ptr)
+@ stdcall NtQueryKey (long long ptr long ptr)
+@ stdcall NtQueryMultipleValueKey(long ptr long ptr long ptr)
+@ stdcall NtQueryMutant(long long ptr long ptr)
+@ stdcall NtQueryObject(long long long long long)
+@ stdcall NtQueryOpenSubKeys(ptr ptr)
+@ stdcall NtQueryPerformanceCounter(ptr ptr)
+@ stdcall NtQueryPortInformationProcess()
+@ stdcall NtQueryQuotaInformationFile(ptr ptr ptr long long ptr long ptr long)
+@ stdcall NtQuerySection (long long long long long)
+@ stdcall NtQuerySecurityObject (long long long long long)
+@ stdcall NtQuerySemaphore (long long ptr long ptr)
+@ stdcall NtQuerySymbolicLinkObject(long ptr ptr)
+@ stdcall NtQuerySystemEnvironmentValue(ptr ptr long ptr)
+@ stdcall NtQuerySystemEnvironmentValueEx(ptr ptr ptr ptr ptr)
+@ stdcall NtQuerySystemInformation(long long long long)
+@ stdcall NtQuerySystemTime(ptr)
+@ stdcall NtQueryTimer(ptr long ptr long ptr)
+@ stdcall NtQueryTimerResolution(long long long)
+@ stdcall NtQueryValueKey(long long long long long long)
+@ stdcall NtQueryVirtualMemory(long ptr long ptr long ptr)
+@ stdcall NtQueryVolumeInformationFile(long ptr ptr long long)
+@ stdcall NtQueueApcThread(long ptr long long long)
+@ stdcall NtRaiseException(ptr ptr long)
+@ stdcall NtRaiseHardError(long long long ptr long ptr)
+@ stdcall NtReadFile(long long ptr ptr ptr ptr long ptr ptr)
+@ stdcall NtReadFileScatter(long long ptr ptr ptr ptr long ptr ptr)
+@ stdcall NtReadRequestData(ptr ptr long ptr long ptr)
+@ stdcall NtReadVirtualMemory(long ptr ptr long ptr)
+@ stdcall NtRegisterThreadTerminatePort(ptr)
+@ stdcall NtReleaseKeyedEvent(ptr ptr long ptr)
+@ stdcall NtReleaseMutant(long ptr)
+@ stdcall NtReleaseSemaphore(long long ptr)
+@ stdcall NtRemoveIoCompletion(ptr ptr ptr ptr ptr)
+@ stdcall NtRemoveProcessDebug(ptr ptr)
+@ stdcall NtRenameKey(ptr ptr)
+@ stdcall NtReplaceKey(ptr long ptr)
+@ stdcall NtReplyPort(ptr ptr)
+@ stdcall NtReplyWaitReceivePort(ptr ptr ptr ptr)
+@ stdcall NtReplyWaitReceivePortEx(ptr ptr ptr ptr ptr)
+@ stdcall NtReplyWaitReplyPort(ptr ptr)
+@ stdcall NtRequestDeviceWakeup(ptr)
+@ stdcall NtRequestPort(ptr ptr)
+@ stdcall NtRequestWaitReplyPort(ptr ptr ptr)
+@ stdcall NtRequestWakeupLatency(long)
+@ stdcall NtResetEvent(long ptr)
+@ stdcall NtResetWriteWatch(long ptr long)
+@ stdcall NtRestoreKey(long long long)
+@ stdcall NtResumeProcess(ptr)
+@ stdcall NtResumeThread(long long)
+@ stdcall NtSaveKey(long long)
+@ stdcall NtSaveKeyEx(ptr ptr long)
+@ stdcall NtSaveMergedKeys(ptr ptr ptr)
+@ stdcall NtSecureConnectPort(ptr ptr ptr ptr ptr ptr ptr ptr ptr)
+@ stdcall NtSetBootEntryOrder(ptr ptr)
+@ stdcall NtSetBootOptions(ptr long)
+@ stdcall NtSetContextThread(long ptr)
+@ stdcall NtSetDebugFilterState(long long long)
+@ stdcall NtSetDefaultHardErrorPort(ptr)
+@ stdcall NtSetDefaultLocale(long long)
+@ stdcall NtSetDefaultUILanguage(long)
+@ stdcall NtSetEaFile(long ptr ptr long)
+@ stdcall NtSetEvent(long long)
+@ stdcall NtSetEventBoostPriority(ptr)
+@ stdcall NtSetHighEventPair(ptr)
+@ stdcall NtSetHighWaitLowEventPair(ptr)
+@ stdcall NtSetInformationDebugObject(ptr long ptr long ptr)
+@ stdcall NtSetInformationFile(long long long long long)
+@ stdcall NtSetInformationJobObject(long long ptr long)
+@ stdcall NtSetInformationKey(long long ptr long)
+@ stdcall NtSetInformationObject(long long ptr long)
+@ stdcall NtSetInformationProcess(long long long long)
+@ stdcall NtSetInformationThread(long long ptr long)
+@ stdcall NtSetInformationToken(long long ptr long)
+@ stdcall NtSetIntervalProfile(long long)
+@ stdcall NtSetIoCompletion(ptr long ptr long long)
+@ stdcall NtSetLdtEntries(long double long double) ; CHECKME
+@ stdcall NtSetLowEventPair(ptr)
+@ stdcall NtSetLowWaitHighEventPair(ptr)
+@ stdcall NtSetQuotaInformationFile(ptr ptr ptr long)
+@ stdcall NtSetSecurityObject(long long ptr)
+@ stdcall NtSetSystemEnvironmentValue(ptr ptr)
+@ stdcall NtSetSystemEnvironmentValueEx(ptr ptr)
+@ stdcall NtSetSystemInformation(long ptr long)
+@ stdcall NtSetSystemPowerState(long long long)
+@ stdcall NtSetSystemTime(ptr ptr)
+@ stdcall NtSetThreadExecutionState(long ptr)
+@ stdcall NtSetTimer(long ptr ptr ptr long long ptr)
+@ stdcall NtSetTimerResolution(long long ptr)
+@ stdcall NtSetUuidSeed(ptr)
+@ stdcall NtSetValueKey(long long long long long long)
+@ stdcall NtSetVolumeInformationFile(long ptr ptr long long)
+@ stdcall NtShutdownSystem(long)
+@ stdcall NtSignalAndWaitForSingleObject(long long long ptr)
+@ stdcall NtStartProfile(ptr)
+@ stdcall NtStopProfile(ptr)
+@ stdcall NtSuspendProcess(ptr)
+@ stdcall NtSuspendThread(long ptr)
+@ stdcall NtSystemDebugControl(long ptr long ptr long ptr)
+@ stdcall NtTerminateJobObject(long long)
+@ stdcall NtTerminateProcess(long long)
+@ stdcall NtTerminateThread(long long)
+@ stdcall NtTestAlert()
+@ stdcall NtTraceEvent(long long long ptr)
+@ stdcall NtTranslateFilePath(ptr long ptr long)
+@ stdcall NtUnloadDriver(ptr)
+@ stdcall NtUnloadKey(long)
+@ stdcall NtUnloadKeyEx(ptr ptr)
+@ stdcall NtUnlockFile(long ptr ptr ptr ptr)
+@ stdcall NtUnlockVirtualMemory(long ptr ptr long)
+@ stdcall NtUnmapViewOfSection(long ptr)
+@ stdcall NtVdmControl(long ptr)
+@ stdcall NtWaitForDebugEvent(ptr long ptr ptr)
+@ stdcall NtWaitForKeyedEvent(ptr ptr long ptr)
+@ stdcall NtWaitForMultipleObjects(long ptr long long ptr)
+@ stdcall NtWaitForSingleObject(long long long)
+@ stdcall NtWaitHighEventPair(ptr)
+@ stdcall NtWaitLowEventPair(ptr)
+@ stdcall NtWriteFile(long long ptr ptr ptr ptr long ptr ptr)
+@ stdcall NtWriteFileGather(long long ptr ptr ptr ptr long ptr ptr)
+@ stdcall NtWriteRequestData(ptr ptr long ptr long ptr)
+@ stdcall NtWriteVirtualMemory(long ptr ptr long ptr)
+@ stdcall NtYieldExecution()
+;@ stdcall PfxFindPrefix
+;@ stdcall PfxInitialize
+;@ stdcall PfxInsertPrefix
+;@ stdcall PfxRemovePrefix
+;@ stdcall PropertyLengthAsVariant
+@ stdcall RtlAbortRXact(ptr)
+@ stdcall RtlAbsoluteToSelfRelativeSD(ptr ptr ptr)
+@ stdcall RtlAcquirePebLock()
+@ stdcall RtlAcquirePrivilege(ptr long long ptr)
+@ stdcall RtlAcquireResourceExclusive(ptr long)
+@ stdcall RtlAcquireResourceShared(ptr long)
+@ stdcall RtlAcquireSRWLockExclusive(ptr)
+@ stdcall RtlAcquireSRWLockShared(ptr)
+@ stdcall RtlActivateActivationContext(long ptr ptr)
+@ stdcall RtlActivateActivationContextEx(long ptr ptr ptr)
+@ fastcall RtlActivateActivationContextUnsafeFast(ptr ptr)
+@ stdcall RtlAddAccessAllowedAce(ptr long long ptr)
+@ stdcall RtlAddAccessAllowedAceEx(ptr long long long ptr)
+@ stdcall RtlAddAccessAllowedObjectAce(ptr long long long ptr ptr ptr)
+@ stdcall RtlAddAccessDeniedAce(ptr long long ptr)
+@ stdcall RtlAddAccessDeniedAceEx(ptr long long long ptr)
+@ stdcall RtlAddAccessDeniedObjectAce(ptr long long long ptr ptr ptr)
+@ stdcall RtlAddAce(ptr long long ptr long)
+@ stdcall RtlAddActionToRXact(ptr long ptr long ptr long)
+@ stdcall RtlAddAtomToAtomTable(ptr wstr ptr)
+@ stdcall RtlAddAttributeActionToRXact(ptr long ptr ptr ptr long ptr long)
+@ stdcall RtlAddAuditAccessAce(ptr long long ptr long long)
+@ stdcall RtlAddAuditAccessAceEx(ptr long long long ptr long long)
+@ stdcall RtlAddAuditAccessObjectAce(ptr long long long ptr ptr ptr long long)
+;@ stdcall RtlAddCompoundAce
+;@ stdcall RtlAddRange ; 5.0 and 5.1 only
+@ stdcall -arch=x86_64 RtlAddFunctionTable(ptr long long)
+;@ stdcall RtlAddMandatoryAce(ptr long long long long ptr)
+@ stdcall RtlAddRefActivationContext(ptr)
+@ stdcall RtlAddRefMemoryStream(ptr)
+@ stdcall RtlAddVectoredContinueHandler(long ptr)
+@ stdcall RtlAddVectoredExceptionHandler(long ptr)
+;@ stdcall RtlAddressInSectionTable
+@ stdcall RtlAdjustPrivilege(long long long ptr)
+@ stdcall RtlAllocateActivationContextStack(ptr) ; CHECKME
+@ stdcall RtlAllocateAndInitializeSid(ptr long long long long long long long long long ptr)
+@ stdcall RtlAllocateHandle(ptr ptr)
+@ stdcall RtlAllocateHeap(ptr long ptr)
+@ stdcall RtlAnsiCharToUnicodeChar(ptr)
+@ stdcall RtlAnsiStringToUnicodeSize(ptr) RtlxAnsiStringToUnicodeSize
+@ stdcall RtlAnsiStringToUnicodeString(ptr ptr long)
+@ stdcall RtlAppendAsciizToString(ptr str)
+;@ stdcall RtlAppendPathElement
+@ stdcall RtlAppendStringToString(ptr ptr)
+@ stdcall RtlAppendUnicodeStringToString(ptr ptr)
+@ stdcall RtlAppendUnicodeToString(ptr wstr)
+;@ stdcall RtlApplicationVerifierStop
+@ stdcall RtlApplyRXact(ptr)
+@ stdcall RtlApplyRXactNoFlush(ptr)
+@ stdcall RtlAreAllAccessesGranted(long long)
+@ stdcall RtlAreAnyAccessesGranted(long long)
+@ stdcall RtlAreBitsClear(ptr long long)
+@ stdcall RtlAreBitsSet(ptr long long)
+@ stdcall RtlAssert(ptr ptr long ptr)
+;@ stdcall RtlCancelTimer
+@ stdcall -register RtlCaptureContext(ptr)
+@ stdcall RtlCaptureStackBackTrace(long long ptr ptr)
+;@ stdcall RtlCaptureStackContext
+@ stdcall RtlCharToInteger(ptr long ptr)
+@ stdcall RtlCheckForOrphanedCriticalSections(ptr)
+;@ stdcall RtlCheckProcessParameters
+@ stdcall RtlCheckRegistryKey(long ptr)
+@ stdcall RtlClearAllBits(ptr)
+@ stdcall RtlClearBits(ptr long long)
+@ stdcall RtlCloneMemoryStream(ptr ptr)
+@ stdcall RtlCommitMemoryStream(ptr long)
+@ stdcall RtlCompactHeap(long long)
+@ stdcall RtlCompareMemory(ptr ptr long)
+@ stdcall RtlCompareMemoryUlong(ptr long long)
+@ stdcall RtlCompareString(ptr ptr long)
+@ stdcall RtlCompareUnicodeString (ptr ptr long)
+@ stdcall RtlCompressBuffer(long ptr long ptr long long ptr ptr)
+@ stdcall RtlComputeCrc32(long ptr long)
+@ stdcall RtlComputeImportTableHash(ptr ptr long)
+@ stdcall RtlComputePrivatizedDllName_U(ptr ptr ptr)
+@ stdcall RtlConsoleMultiByteToUnicodeN(ptr long ptr ptr long ptr)
+@ stdcall RtlConvertExclusiveToShared(ptr)
+@ stdcall -arch=win32 -ret64 RtlConvertLongToLargeInteger(long)
+;@ stdcall RtlConvertPropertyToVariant
+@ stdcall RtlConvertSharedToExclusive(ptr)
+@ stdcall RtlConvertSidToUnicodeString(ptr ptr long)
+@ stdcall RtlConvertToAutoInheritSecurityObject(ptr ptr ptr ptr long ptr)
+;@ stdcall RtlConvertUiListToApiList
+@ stdcall -arch=win32 -ret64 RtlConvertUlongToLargeInteger(long)
+;@ stdcall RtlConvertVariantToProperty
+@ stdcall RtlCopyLuid(ptr ptr)
+@ stdcall RtlCopyLuidAndAttributesArray(long ptr ptr)
+;@ stdcall RtlCopyMappedMemory
+@ stdcall RtlCopyMemoryStreamTo(ptr ptr int64 ptr ptr)
+@ stdcall RtlCopyOutOfProcessMemoryStreamTo(ptr ptr int64 ptr ptr) RtlCopyMemoryStreamTo
+;@ stdcall RtlCopyRangeList ; 5.0 and 5.1 only
+@ stdcall RtlCopySecurityDescriptor(ptr ptr)
+@ stdcall RtlCopySid(long ptr ptr)
+@ stdcall RtlCopySidAndAttributesArray(long ptr long ptr ptr ptr ptr)
+@ stdcall RtlCopyString(ptr ptr)
+@ stdcall RtlCopyUnicodeString(ptr ptr)
+@ stdcall RtlCreateAcl(ptr long long)
+@ stdcall RtlCreateActivationContext(long ptr long ptr ptr ptr)
+@ stdcall RtlCreateAndSetSD(ptr long ptr ptr ptr)
+@ stdcall RtlCreateAtomTable(long ptr)
+@ stdcall RtlCreateBootStatusDataFile()
+@ stdcall RtlCreateEnvironment(long ptr)
+@ stdcall RtlCreateHeap(long ptr long long ptr ptr)
+@ stdcall RtlCreateProcessParameters(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr)
+@ stdcall RtlCreateQueryDebugBuffer(long long)
+@ stdcall RtlCreateRegistryKey(long wstr)
+@ stdcall RtlCreateSecurityDescriptor(ptr long)
+@ stdcall RtlCreateSystemVolumeInformationFolder(ptr)
+@ stdcall RtlCreateTagHeap(ptr long str str)
+@ stdcall RtlCreateTimer(ptr ptr ptr ptr long long long)
+@ stdcall RtlCreateTimerQueue(ptr)
+@ stdcall RtlCreateUnicodeString(ptr wstr)
+@ stdcall RtlCreateUnicodeStringFromAsciiz(ptr str)
+@ stdcall RtlCreateUserProcess(ptr long ptr ptr ptr ptr long ptr ptr ptr)
+@ stdcall RtlCreateUserSecurityObject(ptr long ptr ptr long ptr ptr)
+@ stdcall RtlCreateUserThread(long ptr long ptr long long ptr ptr ptr ptr)
+@ stdcall RtlCustomCPToUnicodeN(ptr wstr long ptr str long)
+@ stdcall RtlCutoverTimeToSystemTime(ptr ptr ptr long)
+@ stdcall RtlDeNormalizeProcessParams(ptr)
+@ stdcall RtlDeactivateActivationContext(long long)
+@ fastcall RtlDeactivateActivationContextUnsafeFast(ptr)
+@ stdcall RtlDecodePointer(ptr)
+@ stdcall RtlDecodeSystemPointer(ptr) RtlEncodeSystemPointer
+@ stdcall RtlDecompressBuffer(long ptr long ptr long ptr)
+@ stdcall RtlDecompressFragment(long ptr long ptr long long ptr ptr)
+@ stdcall RtlDefaultNpAcl(ptr)
+@ stdcall RtlDelete(ptr)
+@ stdcall RtlDeleteAce(ptr long)
+@ stdcall RtlDeleteAtomFromAtomTable(ptr long)
+@ stdcall RtlDeleteCriticalSection(ptr)
+@ stdcall RtlDeleteElementGenericTable(ptr ptr)
+@ stdcall RtlDeleteElementGenericTableAvl(ptr ptr)
+@ cdecl -arch=x86_64 RtlDeleteFunctionTable(ptr)
+@ stdcall RtlDeleteNoSplay(ptr ptr)
+@ stdcall RtlDeleteOwnersRanges(ptr ptr)
+@ stdcall RtlDeleteRange(ptr long long long long ptr)
+@ stdcall RtlDeleteRegistryValue(long ptr ptr)
+@ stdcall RtlDeleteResource(ptr)
+@ stdcall RtlDeleteSecurityObject(ptr)
+@ stdcall RtlDeleteTimer(ptr ptr ptr)
+@ stdcall RtlDeleteTimerQueue(ptr)
+@ stdcall RtlDeleteTimerQueueEx(ptr ptr)
+@ stdcall RtlDeregisterWait(ptr)
+@ stdcall RtlDeregisterWaitEx(ptr ptr)
+@ stdcall RtlDestroyAtomTable(ptr)
+@ stdcall RtlDestroyEnvironment(ptr)
+@ stdcall RtlDestroyHandleTable(ptr)
+@ stdcall RtlDestroyHeap(long)
+@ stdcall RtlDestroyProcessParameters(ptr)
+@ stdcall RtlDestroyQueryDebugBuffer(ptr)
+@ stdcall RtlDetermineDosPathNameType_U(wstr)
+@ stdcall RtlDllShutdownInProgress()
+@ stdcall RtlDnsHostNameToComputerName(ptr ptr long)
+@ stdcall RtlDoesFileExists_U(wstr)
+@ stdcall RtlDosApplyFileIsolationRedirection_Ustr(long ptr ptr ptr ptr ptr ptr ptr ptr)
+@ stdcall RtlDosPathNameToNtPathName_U(wstr ptr ptr ptr)
+@ stdcall RtlDosPathNameToNtPathName_U_WithStatus(wstr ptr ptr ptr) ; 5.2 SP1, and higher
+@ stdcall RtlDosPathNameToRelativeNtPathName_U(ptr ptr ptr ptr)
+@ stdcall RtlDosPathNameToRelativeNtPathName_U_WithStatus(wstr ptr ptr ptr)
+@ stdcall RtlDosSearchPath_U(wstr wstr wstr long ptr ptr)
+@ stdcall RtlDosSearchPath_Ustr(long ptr ptr ptr ptr ptr ptr ptr ptr)
+@ stdcall RtlDowncaseUnicodeChar(long)
+@ stdcall RtlDowncaseUnicodeString(ptr ptr long)
+@ stdcall RtlDumpResource(ptr)
+@ stdcall RtlDuplicateUnicodeString(long ptr ptr)
+@ stdcall RtlEmptyAtomTable(ptr long)
+;@ stdcall RtlEnableEarlyCriticalSectionEventCreation
+@ stdcall RtlEncodePointer(ptr)
+@ stdcall RtlEncodeSystemPointer(ptr)
+@ stdcall -arch=win32 -ret64 RtlEnlargedIntegerMultiply(long long)
+@ stdcall -arch=win32 RtlEnlargedUnsignedDivide(double long ptr)
+@ stdcall -arch=win32 -ret64 RtlEnlargedUnsignedMultiply(long long)
+@ stdcall RtlEnterCriticalSection(ptr)
+@ stdcall RtlEnumProcessHeaps(ptr ptr)
+@ stdcall RtlEnumerateGenericTable(ptr long)
+@ stdcall RtlEnumerateGenericTableAvl(ptr long)
+@ stdcall RtlEnumerateGenericTableLikeADirectory(ptr ptr ptr long ptr ptr ptr)
+@ stdcall RtlEnumerateGenericTableWithoutSplaying(ptr ptr)
+@ stdcall RtlEnumerateGenericTableWithoutSplayingAvl(ptr ptr)
+@ stdcall RtlEqualComputerName(ptr ptr)
+@ stdcall RtlEqualDomainName(ptr ptr)
+@ stdcall RtlEqualLuid(ptr ptr)
+@ stdcall RtlEqualPrefixSid(ptr ptr)
+@ stdcall RtlEqualSid(long long)
+@ stdcall RtlEqualString(ptr ptr long)
+@ stdcall RtlEqualUnicodeString(ptr ptr long)
+@ stdcall RtlEraseUnicodeString(ptr)
+@ stdcall RtlExitUserThread(long)
+@ stdcall RtlExpandEnvironmentStrings_U(ptr ptr ptr ptr)
+@ stdcall RtlExtendHeap(ptr long ptr ptr)
+@ stdcall -arch=win32 -ret64 RtlExtendedIntegerMultiply(double long)
+@ stdcall -arch=win32 -ret64 RtlExtendedLargeIntegerDivide(double long ptr)
+@ stdcall -arch=win32 -ret64 RtlExtendedMagicDivide(double double long)
+@ stdcall RtlFillMemory(ptr long long)
+@ stdcall RtlFillMemoryUlong(ptr long long)
+@ stdcall RtlFinalReleaseOutOfProcessMemoryStream(ptr)
+@ stdcall RtlFindActivationContextSectionGuid(long ptr long ptr ptr)
+@ stdcall RtlFindActivationContextSectionString(long ptr long ptr ptr)
+@ stdcall RtlFindCharInUnicodeString(long ptr ptr ptr)
+@ stdcall RtlFindClearBits(ptr long long)
+@ stdcall RtlFindClearBitsAndSet(ptr long long)
+@ stdcall RtlFindClearRuns(ptr ptr long long)
+@ stdcall RtlFindLastBackwardRunClear(ptr long ptr)
+;@ stdcall RtlFindLastBackwardRunSet(ptr long ptr)
+@ stdcall RtlFindLeastSignificantBit(double)
+@ stdcall RtlFindLongestRunClear(ptr long)
+@ stdcall RtlFindLongestRunSet(ptr long)
+@ stdcall RtlFindMessage(long long long long ptr)
+@ stdcall RtlFindMostSignificantBit(double)
+@ stdcall RtlFindNextForwardRunClear(ptr long ptr)
+;@ stdcall RtlFindNextForwardRunSet(ptr long ptr)
+@ stdcall RtlFindRange(ptr long long long long long long long long ptr ptr ptr)
+@ stdcall RtlFindSetBits(ptr long long)
+@ stdcall RtlFindSetBitsAndClear(ptr long long)
+;@ stdcall RtlFindSetRuns(ptr ptr long long)
+@ stdcall RtlFirstEntrySList(ptr)
+@ stdcall RtlFirstFreeAce(ptr ptr)
+@ stdcall RtlFlushSecureMemoryCache(ptr ptr)
+@ stdcall RtlFormatCurrentUserKeyPath(ptr)
+@ stdcall RtlFormatMessage(ptr long long long long ptr ptr long)
+@ stdcall RtlFormatMessageEx(ptr long long long long ptr ptr long long)
+@ stdcall RtlFreeActivationContextStack(ptr)
+@ stdcall RtlFreeAnsiString(long)
+@ stdcall RtlFreeHandle(ptr ptr)
+@ stdcall RtlFreeHeap(long long long)
+@ stdcall RtlFreeOemString(ptr)
+@ stdcall RtlFreeRangeList(ptr)
+@ stdcall RtlFreeSid(long)
+@ stdcall RtlFreeThreadActivationContextStack()
+@ stdcall RtlFreeUnicodeString(ptr)
+@ stdcall RtlFreeUserThreadStack(ptr ptr) ; 4.0 to 5.2 only
+@ stdcall RtlGUIDFromString(ptr ptr)
+@ stdcall RtlGenerate8dot3Name(ptr ptr long ptr)
+@ stdcall RtlGetAce(ptr long ptr)
+@ stdcall RtlGetActiveActivationContext(ptr)
+@ stdcall RtlGetCallersAddress(ptr ptr)
+@ stdcall RtlGetCompressionWorkSpaceSize(long ptr ptr)
+@ stdcall RtlGetControlSecurityDescriptor(ptr ptr ptr)
+@ stdcall RtlGetCriticalSectionRecursionCount(ptr)
+@ stdcall RtlGetCurrentDirectory_U(long ptr)
+@ stdcall RtlGetCurrentPeb()
+@ stdcall RtlGetCurrentProcessorNumber() ; 5.2 SP1 and higher
+@ stdcall RtlGetDaclSecurityDescriptor(ptr ptr ptr ptr)
+@ stdcall RtlGetElementGenericTable(ptr long)
+@ stdcall RtlGetElementGenericTableAvl(ptr long)
+@ stdcall RtlGetFirstRange(ptr ptr ptr)
+;@ stdcall RtlGetFrame
+@ stdcall RtlGetFullPathName_U(wstr long ptr ptr)
+@ stdcall RtlGetFullPathName_UstrEx(ptr ptr ptr ptr ptr ptr ptr ptr)
+@ stdcall RtlGetGroupSecurityDescriptor(ptr ptr ptr)
+@ stdcall RtlGetLastNtStatus()
+@ stdcall RtlGetLastWin32Error()
+@ stdcall RtlGetLengthWithoutLastFullDosOrNtPathElement(long ptr ptr)
+; Yes, Microsoft really misspelled this one!
+@ stdcall RtlGetLengthWithoutTrailingPathSeperators(long ptr ptr) RtlGetLengthWithoutTrailingPathSeparators
+@ stdcall RtlGetLongestNtPathLength()
+@ stdcall RtlGetNativeSystemInformation(long long long long) NtQuerySystemInformation
+@ stdcall RtlGetNextRange(ptr ptr long)
+@ stdcall RtlGetNtGlobalFlags()
+@ stdcall RtlGetNtProductType(ptr)
+@ stdcall RtlGetNtVersionNumbers(ptr ptr ptr)
+@ stdcall RtlGetOwnerSecurityDescriptor(ptr ptr ptr)
+;@ stdcall RtlGetProductInfo(long long long long ptr)
+@ stdcall RtlGetProcessHeaps(long ptr)
+@ stdcall RtlGetSaclSecurityDescriptor(ptr ptr ptr ptr)
+@ stdcall RtlGetSecurityDescriptorRMControl(ptr ptr)
+@ stdcall RtlGetSetBootStatusData(ptr long long ptr long long)
+@ stdcall RtlGetThreadErrorMode()
+;@ stdcall RtlGetUnloadEventTrace
+@ stdcall RtlGetUserInfoHeap(ptr long ptr ptr ptr)
+@ stdcall RtlGetVersion(ptr)
+@ stdcall RtlHashUnicodeString(ptr long long ptr)
+@ stdcall RtlIdentifierAuthoritySid(ptr)
+@ stdcall RtlImageDirectoryEntryToData(long long long ptr)
+@ stdcall RtlImageNtHeader(long)
+@ stdcall RtlImageNtHeaderEx(long ptr double ptr)
+@ stdcall RtlImageRvaToSection(ptr long long)
+@ stdcall RtlImageRvaToVa(ptr long long ptr)
+@ stdcall RtlImpersonateSelf(long)
+@ stdcall RtlInitAnsiString(ptr str)
+@ stdcall RtlInitAnsiStringEx(ptr str)
+@ stdcall RtlInitCodePageTable(ptr ptr)
+@ stdcall RtlInitMemoryStream(ptr)
+@ stdcall RtlInitNlsTables(ptr ptr ptr ptr)
+@ stdcall RtlInitOutOfProcessMemoryStream(ptr)
+@ stdcall RtlInitString(ptr str)
+@ stdcall RtlInitUnicodeString(ptr wstr)
+@ stdcall RtlInitUnicodeStringEx(ptr wstr)
+;@ stdcall RtlInitializeAtomPackage
+@ stdcall RtlInitializeBitMap(ptr long long)
+@ stdcall RtlInitializeContext(ptr ptr ptr ptr ptr)
+@ stdcall RtlInitializeCriticalSection(ptr)
+@ stdcall RtlInitializeCriticalSectionAndSpinCount(ptr long)
+;@ stdcall RtlInitializeCriticalSectionEx(ptr long long)
+@ stdcall RtlInitializeGenericTable(ptr ptr ptr ptr ptr)
+@ stdcall RtlInitializeGenericTableAvl(ptr ptr ptr ptr ptr)
+@ stdcall RtlInitializeHandleTable(long long ptr)
+@ stdcall RtlInitializeRXact(ptr long ptr)
+@ stdcall RtlInitializeRangeList(ptr)
+@ stdcall RtlInitializeResource(ptr)
+@ stdcall RtlInitializeSListHead(ptr)
+@ stdcall RtlInitializeSid(ptr ptr long)
+@ stdcall RtlInitializeSRWLock(ptr)
+;@ stdcall RtlInitializeStackTraceDataBase ; 5.1 SP2 and SP3, and 5.2 only
+@ stdcall RtlInsertElementGenericTable(ptr ptr long ptr)
+@ stdcall RtlInsertElementGenericTableAvl(ptr ptr long ptr)
+@ stdcall -arch=x86_64 RtlInstallFunctionTableCallback(double double long ptr ptr ptr)
+@ stdcall RtlInt64ToUnicodeString(double long ptr)
+@ stdcall RtlIntegerToChar(long long long ptr)
+@ stdcall RtlIntegerToUnicodeString(long long ptr)
+@ stdcall -arch=win32 -ret64 RtlInterlockedCompareExchange64(ptr double double)
+@ stdcall -arch=i386,x86_64 RtlInterlockedFlushSList(ptr)
+@ stdcall -arch=i386,x86_64 RtlInterlockedPopEntrySList(ptr)
+@ stdcall -arch=i386,x86_64 RtlInterlockedPushEntrySList(ptr ptr)
+@ stdcall RtlInterlockedPushListSList(ptr ptr ptr long)
+@ stdcall RtlInvertRangeList(ptr ptr)
+@ stdcall RtlIpv4AddressToStringA(ptr ptr)
+@ stdcall RtlIpv4AddressToStringExA(ptr long ptr ptr)
+@ stdcall RtlIpv4AddressToStringExW(ptr long ptr ptr)
+@ stdcall RtlIpv4AddressToStringW(ptr ptr)
+@ stdcall RtlIpv4StringToAddressA(str long ptr ptr)
+@ stdcall RtlIpv4StringToAddressExA(str long ptr ptr)
+@ stdcall RtlIpv4StringToAddressExW(wstr long ptr ptr)
+@ stdcall RtlIpv4StringToAddressW(wstr long ptr ptr)
+@ stdcall RtlIpv6AddressToStringA(ptr ptr)
+@ stdcall RtlIpv6AddressToStringExA(ptr long long ptr ptr)
+@ stdcall RtlIpv6AddressToStringExW(ptr long long ptr ptr)
+@ stdcall RtlIpv6AddressToStringW(ptr ptr)
+@ stdcall RtlIpv6StringToAddressA(str ptr ptr)
+@ stdcall RtlIpv6StringToAddressExA(str ptr ptr ptr)
+@ stdcall RtlIpv6StringToAddressExW(wstr ptr ptr ptr)
+@ stdcall RtlIpv6StringToAddressW(wstr ptr ptr)
+@ stdcall RtlIsActivationContextActive(ptr)
+;@ stdcall RtlIsCriticalSectionLocked
+;@ stdcall RtlIsCriticalSectionLockedByThread
+@ stdcall RtlIsDosDeviceName_U(wstr)
+@ stdcall RtlIsGenericTableEmpty(ptr)
+@ stdcall RtlIsGenericTableEmptyAvl(ptr)
+@ stdcall RtlIsNameLegalDOS8Dot3(ptr ptr ptr)
+@ stdcall RtlIsRangeAvailable(ptr long long long long long long ptr ptr ptr)
+@ stdcall RtlIsTextUnicode(ptr long ptr)
+@ stdcall RtlIsThreadWithinLoaderCallout()
+@ stdcall RtlIsValidHandle(ptr ptr)
+@ stdcall RtlIsValidIndexHandle(ptr long ptr)
+@ stdcall -arch=win32 -ret64 RtlLargeIntegerAdd(double double)
+@ stdcall -arch=win32 -ret64 RtlLargeIntegerArithmeticShift(double long)
+@ stdcall -arch=win32 -ret64 RtlLargeIntegerDivide(double double ptr)
+@ stdcall -arch=win32 -ret64 RtlLargeIntegerNegate(double)
+@ stdcall -arch=win32 -ret64 RtlLargeIntegerShiftLeft(double long)
+@ stdcall -arch=win32 -ret64 RtlLargeIntegerShiftRight(double long)
+@ stdcall -arch=win32 -ret64 RtlLargeIntegerSubtract(double double)
+@ stdcall RtlLargeIntegerToChar(ptr long long ptr)
+@ stdcall RtlLeaveCriticalSection(ptr)
+@ stdcall RtlLengthRequiredSid(long)
+@ stdcall RtlLengthSecurityDescriptor(ptr)
+@ stdcall RtlLengthSid(ptr)
+@ stdcall RtlLocalTimeToSystemTime(ptr ptr)
+@ stdcall RtlLockBootStatusData(ptr)
+@ stdcall RtlLockHeap(long)
+@ stdcall RtlLockMemoryStreamRegion(ptr int64 int64 long)
+;@ stdcall RtlLogStackBackTrace
+@ stdcall RtlLookupAtomInAtomTable(ptr wstr ptr)
+@ stdcall RtlLookupElementGenericTable(ptr ptr)
+@ stdcall RtlLookupElementGenericTableAvl(ptr ptr)
+@ stdcall -arch=x86_64 RtlLookupFunctionEntry(long ptr ptr)
+@ stdcall RtlMakeSelfRelativeSD(ptr ptr ptr)
+@ stdcall RtlMapGenericMask(long ptr)
+;@ stdcall RtlMapSecurityErrorToNtStatus
+@ stdcall RtlMergeRangeLists(ptr ptr ptr long)
+@ stdcall RtlMoveMemory(ptr ptr long)
+@ stdcall RtlMultiAppendUnicodeStringBuffer(ptr long ptr)
+@ stdcall RtlMultiByteToUnicodeN(ptr long ptr ptr long)
+@ stdcall RtlMultiByteToUnicodeSize(ptr str long)
+@ stdcall RtlNewInstanceSecurityObject(long long ptr ptr ptr ptr ptr long ptr ptr)
+@ stdcall RtlNewSecurityGrantedAccess(long ptr ptr ptr ptr ptr)
+@ stdcall RtlNewSecurityObject(ptr ptr ptr long ptr ptr)
+@ stdcall RtlNewSecurityObjectEx(ptr ptr ptr ptr long long ptr ptr)
+@ stdcall RtlNewSecurityObjectWithMultipleInheritance(ptr ptr ptr ptr long long long ptr ptr)
+@ stdcall RtlNormalizeProcessParams(ptr)
+@ stdcall RtlNtPathNameToDosPathName(ptr ptr ptr ptr) ; CHECKME
+@ stdcall RtlNtStatusToDosError(long)
+@ stdcall RtlNtStatusToDosErrorNoTeb(long)
+@ stdcall RtlNumberGenericTableElements(ptr)
+@ stdcall RtlNumberGenericTableElementsAvl(ptr)
+@ stdcall RtlNumberOfClearBits(ptr)
+@ stdcall RtlNumberOfSetBits(ptr)
+;@ stdcall RtlOemStringToUnicodeSize(ptr)
+@ stdcall RtlOemStringToUnicodeString(ptr ptr long)
+@ stdcall RtlOemToUnicodeN(ptr long ptr ptr long)
+@ stdcall RtlOpenCurrentUser(long ptr)
+@ stdcall RtlPcToFileHeader(ptr ptr)
+@ stdcall RtlPinAtomInAtomTable(ptr long)
+;@ stdcall RtlPopFrame
+@ stdcall RtlPrefixString(ptr ptr long)
+@ stdcall RtlPrefixUnicodeString(ptr ptr long)
+;@ stdcall RtlPropertySetNameToGuid ; 4.0 only
+@ stdcall RtlProtectHeap(ptr long)
+;@ stdcall RtlPushFrame
+@ stdcall RtlQueryAtomInAtomTable(ptr long ptr ptr ptr ptr)
+@ stdcall RtlQueryDepthSList(ptr)
+@ stdcall RtlQueryEnvironmentVariable_U(ptr ptr ptr)
+@ stdcall RtlQueryHeapInformation(long long ptr long ptr)
+@ stdcall RtlQueryInformationAcl(ptr ptr long long)
+@ stdcall RtlQueryInformationActivationContext(long long ptr long ptr long ptr)
+@ stdcall RtlQueryInformationActiveActivationContext(long ptr long ptr)
+@ stdcall RtlQueryInterfaceMemoryStream(ptr ptr ptr)
+;@ stdcall RtlQueryProcessBackTraceInformation
+@ stdcall RtlQueryProcessDebugInformation(long long ptr)
+;@ stdcall RtlQueryProcessHeapInformation
+;@ stdcall RtlQueryProcessLockInformation
+;@ stdcall RtlQueryProperties ; 4.0 only
+;@ stdcall RtlQueryPropertyNames ; 4.0 only
+;@ stdcall RtlQueryPropertySet ; 4.0 only
+@ stdcall RtlQueryRegistryValues(long ptr ptr ptr ptr)
+@ stdcall RtlQuerySecurityObject(ptr long ptr long ptr)
+@ stdcall RtlQueryTagHeap(ptr long long long ptr)
+@ stdcall RtlQueryTimeZoneInformation(ptr)
+;@ stdcall RtlQueueApcWow64Thread
+@ stdcall RtlQueueWorkItem(ptr ptr long)
+@ stdcall -register RtlRaiseException(ptr)
+@ stdcall RtlRaiseStatus(long)
+@ stdcall RtlRandom(ptr)
+@ stdcall RtlRandomEx(ptr)
+@ stdcall RtlReAllocateHeap(long long ptr long)
+@ stdcall RtlReadMemoryStream(ptr ptr long ptr)
+@ stdcall RtlReadOutOfProcessMemoryStream(ptr ptr long ptr)
+@ stdcall RtlRealPredecessor(ptr)
+@ stdcall RtlRealSuccessor(ptr)
+@ stdcall RtlRegisterSecureMemoryCacheCallback(ptr)
+@ stdcall RtlRegisterWait(ptr ptr ptr ptr long long)
+@ stdcall RtlReleaseActivationContext(ptr)
+@ stdcall RtlReleaseMemoryStream(ptr)
+@ stdcall RtlReleasePebLock()
+@ stdcall RtlReleasePrivilege(ptr)
+@ stdcall RtlReleaseRelativeName(ptr)
+@ stdcall RtlReleaseResource(ptr)
+@ stdcall RtlReleaseSRWLockExclusive(ptr)
+@ stdcall RtlReleaseSRWLockShared(ptr)
+@ stdcall RtlRemoteCall(ptr ptr ptr long ptr long long)
+@ stdcall RtlRemoveVectoredContinueHandler(ptr)
+@ stdcall RtlRemoveVectoredExceptionHandler(ptr)
+@ stdcall RtlResetRtlTranslations(ptr)
+@ stdcall -arch=x86_64 RtlRestoreContext(ptr ptr)
+@ stdcall RtlRestoreLastWin32Error(long) RtlSetLastWin32Error
+@ stdcall RtlRevertMemoryStream(ptr)
+@ stdcall RtlRunDecodeUnicodeString(long ptr)
+@ stdcall RtlRunEncodeUnicodeString(long ptr)
+@ stdcall RtlSecondsSince1970ToTime(long ptr)
+@ stdcall RtlSecondsSince1980ToTime(long ptr)
+@ stdcall RtlSeekMemoryStream(ptr int64 long ptr)
+@ stdcall RtlSelfRelativeToAbsoluteSD2(ptr ptr)
+@ stdcall RtlSelfRelativeToAbsoluteSD(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr)
+@ stdcall RtlSetAllBits(ptr)
+@ stdcall RtlSetAttributesSecurityDescriptor(ptr long ptr)
+@ stdcall RtlSetBits(ptr long long)
+@ stdcall RtlSetControlSecurityDescriptor(ptr long long)
+@ stdcall RtlSetCriticalSectionSpinCount(ptr long)
+@ stdcall RtlSetCurrentDirectory_U(ptr)
+@ stdcall RtlSetCurrentEnvironment(wstr ptr)
+@ stdcall RtlSetDaclSecurityDescriptor(ptr long ptr long)
+@ stdcall RtlSetEnvironmentStrings(wstr long)
+@ stdcall RtlSetEnvironmentVariable(ptr ptr ptr)
+@ stdcall RtlSetGroupSecurityDescriptor(ptr ptr long)
+@ stdcall RtlSetHeapInformation(ptr long ptr ptr)
+@ stdcall RtlSetInformationAcl(ptr ptr long long)
+@ stdcall RtlSetIoCompletionCallback(long ptr long)
+@ stdcall RtlSetLastWin32Error(long)
+@ stdcall RtlSetLastWin32ErrorAndNtStatusFromNtStatus(long)
+@ stdcall RtlSetMemoryStreamSize(ptr int64)
+@ stdcall RtlSetOwnerSecurityDescriptor(ptr ptr long)
+@ cdecl RtlSetProcessIsCritical(long ptr long)
+;@ stdcall RtlSetProperties ; RtlSetProperties
+;@ stdcall RtlSetPropertyClassId ; 4.0 only
+;@ stdcall RtlSetPropertyNames ; 4.0 only
+;@ stdcall RtlSetPropertySetClassId ; 4.0 only
+@ stdcall RtlSetSaclSecurityDescriptor(ptr long ptr long)
+@ stdcall RtlSetSecurityDescriptorRMControl(ptr ptr)
+@ stdcall RtlSetSecurityObject(long ptr ptr ptr ptr)
+@ stdcall RtlSetSecurityObjectEx(long ptr ptr long ptr ptr)
+@ stdcall RtlSetThreadErrorMode(long ptr)
+@ cdecl RtlSetThreadIsCritical(long ptr long)
+@ stdcall RtlSetThreadPoolStartFunc(ptr ptr)
+@ stdcall RtlSetTimeZoneInformation(ptr)
+;@ stdcall RtlSetTimer
+@ stdcall RtlSetUnhandledExceptionFilter(ptr)
+;@ stdcall RtlSetUnicodeCallouts
+@ stdcall RtlSetUserFlagsHeap(ptr long ptr long long)
+@ stdcall RtlSetUserValueHeap(ptr long ptr ptr)
+@ stdcall RtlSizeHeap(long long ptr)
+@ stdcall RtlSleepConditionVariableCS(ptr ptr ptr)
+@ stdcall RtlSleepConditionVariableSRW(ptr ptr ptr long)
+@ stdcall RtlSplay(ptr)
+@ stdcall RtlStartRXact(ptr)
+@ stdcall RtlStatMemoryStream(ptr ptr long)
+@ stdcall RtlStringFromGUID(ptr ptr)
+@ stdcall RtlSubAuthorityCountSid(ptr)
+@ stdcall RtlSubAuthoritySid(ptr long)
+@ stdcall RtlSubtreePredecessor(ptr)
+@ stdcall RtlSubtreeSuccessor(ptr)
+@ stdcall RtlSystemTimeToLocalTime(ptr ptr)
+@ stdcall RtlTimeFieldsToTime(ptr ptr)
+@ stdcall RtlTimeToElapsedTimeFields(long long)
+@ stdcall RtlTimeToSecondsSince1970(ptr ptr)
+@ stdcall RtlTimeToSecondsSince1980(ptr ptr)
+@ stdcall RtlTimeToTimeFields (long long)
+;@ stdcall RtlTraceDatabaseAdd
+;@ stdcall RtlTraceDatabaseCreate
+;@ stdcall RtlTraceDatabaseDestroy
+;@ stdcall RtlTraceDatabaseEnumerate
+;@ stdcall RtlTraceDatabaseFind
+;@ stdcall RtlTraceDatabaseLock
+;@ stdcall RtlTraceDatabaseUnlock
+;@ stdcall RtlTraceDatabaseValidate
+@ stdcall RtlTryEnterCriticalSection(ptr)
+@ fastcall -arch=i386 RtlUlongByteSwap(long)
+@ fastcall -ret64 RtlUlonglongByteSwap(double)
+;@ stdcall RtlUnhandledExceptionFilter2
+@ stdcall RtlUnhandledExceptionFilter(ptr)
+;@ stdcall RtlUnicodeStringToAnsiSize(ptr)
+@ stdcall RtlUnicodeStringToAnsiString(ptr ptr long)
+@ stdcall RtlUnicodeStringToCountedOemString(ptr ptr long)
+@ stdcall RtlUnicodeStringToInteger(ptr long ptr)
+;@ stdcall RtlUnicodeStringToOemSize(ptr)
+@ stdcall RtlUnicodeStringToOemString(ptr ptr long)
+@ stdcall RtlUnicodeToCustomCPN(ptr ptr long ptr wstr long)
+@ stdcall RtlUnicodeToMultiByteN(ptr long ptr ptr long)
+@ stdcall RtlUnicodeToMultiByteSize(ptr ptr long)
+@ stdcall RtlUnicodeToOemN(ptr long ptr ptr long)
+@ stdcall RtlUniform(ptr)
+@ stdcall RtlUnlockBootStatusData(ptr)
+@ stdcall RtlUnlockHeap(long)
+@ stdcall RtlUnlockMemoryStreamRegion(ptr int64 int64 long)
+@ stdcall -register RtlUnwind(ptr ptr ptr ptr)
+@ stdcall -arch=x86_64 RtlUnwindEx(long long ptr long ptr)
+@ stdcall RtlUpcaseUnicodeChar(long)
+@ stdcall RtlUpcaseUnicodeString(ptr ptr long)
+@ stdcall RtlUpcaseUnicodeStringToAnsiString(ptr ptr long)
+@ stdcall RtlUpcaseUnicodeStringToCountedOemString(ptr ptr long)
+@ stdcall RtlUpcaseUnicodeStringToOemString(ptr ptr long)
+@ stdcall RtlUpcaseUnicodeToCustomCPN(ptr ptr long ptr wstr long)
+@ stdcall RtlUpcaseUnicodeToMultiByteN(ptr long ptr ptr long)
+@ stdcall RtlUpcaseUnicodeToOemN(ptr long ptr ptr long)
+@ stdcall RtlUpdateTimer(ptr ptr long long)
+@ stdcall RtlUpperChar(long)
+@ stdcall RtlUpperString(ptr ptr)
+@ stdcall RtlUsageHeap(ptr long ptr)
+@ fastcall -arch=i386 RtlUshortByteSwap(long)
+@ stdcall RtlValidAcl(ptr)
+@ stdcall RtlValidRelativeSecurityDescriptor(ptr long long)
+@ stdcall RtlValidSecurityDescriptor(ptr)
+@ stdcall RtlValidSid(ptr)
+@ stdcall RtlValidateHeap(long long ptr)
+@ stdcall RtlValidateProcessHeaps()
+@ stdcall RtlValidateUnicodeString(long ptr)
+@ stdcall RtlVerifyVersionInfo(ptr long double)
+@ stdcall -arch=x86_64 RtlVirtualUnwind(long long long ptr ptr ptr ptr ptr)
+@ stdcall RtlWalkFrameChain(ptr long long)
+@ stdcall RtlWalkHeap(long ptr)
+@ stdcall RtlWow64EnableFsRedirection(long)
+@ stdcall RtlWow64EnableFsRedirectionEx(long ptr)
+@ stdcall RtlWakeAllConditionVariable(ptr)
+@ stdcall RtlWakeConditionVariable(ptr)
+@ stdcall RtlWriteMemoryStream(ptr ptr long ptr)
+@ stdcall RtlWriteRegistryValue(long ptr ptr long ptr long)
+@ stdcall RtlZeroHeap(ptr long)
+@ stdcall RtlZeroMemory(ptr long)
+@ stdcall RtlZombifyActivationContext(ptr)
+@ stdcall RtlpApplyLengthFunction(long long ptr ptr)
+@ stdcall RtlpEnsureBufferSize(ptr ptr ptr) ; CHECKME
+;@ stdcall RtlpNotOwnerCriticalSection
+@ stdcall RtlpNtCreateKey(ptr long ptr long ptr ptr)
+@ stdcall RtlpNtEnumerateSubKey(ptr ptr long long)
+@ stdcall RtlpNtMakeTemporaryKey(ptr)
+@ stdcall RtlpNtOpenKey(ptr long ptr long)
+@ stdcall RtlpNtQueryValueKey(ptr ptr ptr ptr long)
+@ stdcall RtlpNtSetValueKey(ptr long ptr long)
+@ stdcall RtlpUnWaitCriticalSection(ptr)
+@ stdcall RtlpWaitForCriticalSection(ptr)
+@ stdcall RtlxAnsiStringToUnicodeSize(ptr)
+@ stdcall RtlxOemStringToUnicodeSize(ptr)
+@ stdcall RtlxUnicodeStringToAnsiSize(ptr)
+@ stdcall RtlxUnicodeStringToOemSize(ptr) ; RtlUnicodeStringToOemSize
+@ stdcall -ret64 VerSetConditionMask(double long long)
+@ stdcall ZwAcceptConnectPort(ptr long ptr long long ptr) NtAcceptConnectPort
+@ stdcall ZwAccessCheck(ptr long long ptr ptr ptr ptr ptr) NtAccessCheck
+@ stdcall ZwAccessCheckAndAuditAlarm(ptr long ptr ptr ptr long ptr long ptr ptr ptr) NtAccessCheckAndAuditAlarm
+@ stdcall ZwAccessCheckByType(ptr ptr ptr long ptr long ptr ptr long ptr ptr) NtAccessCheckByType
+@ stdcall ZwAccessCheckByTypeAndAuditAlarm(ptr ptr ptr ptr ptr ptr long long long ptr long ptr long ptr ptr ptr) NtAccessCheckByTypeAndAuditAlarm
+@ stdcall ZwAccessCheckByTypeResultList(ptr ptr ptr long ptr long ptr ptr long ptr ptr) NtAccessCheckByTypeResultList
+@ stdcall ZwAccessCheckByTypeResultListAndAuditAlarm(ptr ptr ptr ptr ptr ptr long long long ptr long ptr long ptr ptr ptr) NtAccessCheckByTypeResultListAndAuditAlarm
+@ stdcall ZwAccessCheckByTypeResultListAndAuditAlarmByHandle(ptr ptr ptr ptr ptr ptr ptr long long long ptr long ptr long ptr ptr ptr) NtAccessCheckByTypeResultListAndAuditAlarmByHandle
+@ stdcall ZwAddAtom(ptr long ptr) NtAddAtom
+@ stdcall ZwAddBootEntry(ptr long)
+@ stdcall ZwAdjustGroupsToken(long long long long long long) NtAdjustGroupsToken
+@ stdcall ZwAdjustPrivilegesToken(long long long long long long) NtAdjustPrivilegesToken
+@ stdcall ZwAlertResumeThread(long ptr) NtAlertResumeThread
+@ stdcall ZwAlertThread(long) NtAlertThread
+@ stdcall ZwAllocateLocallyUniqueId(ptr) NtAllocateLocallyUniqueId
+@ stdcall ZwAllocateUserPhysicalPages(ptr ptr ptr)
+@ stdcall ZwAllocateUuids(ptr ptr ptr ptr) NtAllocateUuids
+@ stdcall ZwAllocateVirtualMemory(long ptr ptr ptr long long) NtAllocateVirtualMemory
+@ stdcall ZwAreMappedFilesTheSame(ptr ptr) NtAreMappedFilesTheSame
+@ stdcall ZwAssignProcessToJobObject(long long) NtAssignProcessToJobObject
+@ stdcall ZwCallbackReturn(ptr long long)
+@ stdcall ZwCancelDeviceWakeupRequest(ptr)
+@ stdcall ZwCancelIoFile(long ptr) NtCancelIoFile
+;@ stdcall ZwCancelIoFileEx(long ptr ptr) NtCancelIoFileEx
+@ stdcall ZwCancelTimer(long ptr) NtCancelTimer
+@ stdcall ZwClearEvent(long) NtClearEvent
+@ stdcall ZwClose(long) NtClose
+@ stdcall ZwCloseObjectAuditAlarm(ptr ptr long)
+@ stdcall ZwCompactKeys(long ptr) NtCompactKeys
+@ stdcall ZwCompareTokens(ptr ptr ptr) NtCompareTokens
+@ stdcall ZwCompleteConnectPort(ptr) NtCompleteConnectPort
+@ stdcall ZwCompressKey(ptr) NtCompressKey
+@ stdcall ZwConnectPort(ptr ptr ptr ptr ptr ptr ptr ptr) NtConnectPort
+@ stdcall ZwContinue(ptr long) NtContinue
+@ stdcall ZwCreateDebugObject(ptr long ptr long) NtCreateDebugObject
+@ stdcall ZwCreateDirectoryObject(long long long) NtCreateDirectoryObject
+@ stdcall ZwCreateEvent(long long long long long) NtCreateEvent
+@ stdcall ZwCreateEventPair(ptr long ptr) NtCreateEventPair
+@ stdcall ZwCreateFile(ptr long ptr ptr long long long ptr long long ptr) NtCreateFile
+@ stdcall ZwCreateIoCompletion(ptr long ptr long) NtCreateIoCompletion
+@ stdcall ZwCreateJobObject(ptr long ptr) NtCreateJobObject
+@ stdcall ZwCreateJobSet(long ptr long) NtCreateJobSet
+@ stdcall ZwCreateKey(ptr long ptr long ptr long long) NtCreateKey
+@ stdcall ZwCreateKeyedEvent(ptr long ptr long) NtCreateKeyedEvent
+@ stdcall ZwCreateMailslotFile(long long long long long long long long) NtCreateMailslotFile
+@ stdcall ZwCreateMutant(ptr long ptr long) NtCreateMutant
+@ stdcall ZwCreateNamedPipeFile(ptr long ptr ptr long long long long long long long long long ptr) NtCreateNamedPipeFile
+@ stdcall ZwCreatePagingFile(long long long long) NtCreatePagingFile
+@ stdcall ZwCreatePort(ptr ptr long long long) NtCreatePort
+@ stdcall ZwCreateProcess(ptr long ptr ptr long ptr ptr ptr)
+@ stdcall ZwCreateProcessEx(ptr long ptr ptr long ptr ptr ptr long) NtCreateProcessEx
+@ stdcall ZwCreateProfile(ptr ptr ptr long long ptr long long long) NtCreateProfile ; CHECKME
+@ stdcall ZwCreateSection(ptr long ptr ptr long long long) NtCreateSection
+@ stdcall ZwCreateSemaphore(ptr long ptr long long) NtCreateSemaphore
+@ stdcall ZwCreateSymbolicLinkObject(ptr long ptr ptr) NtCreateSymbolicLinkObject
+@ stdcall ZwCreateThread(ptr long ptr ptr ptr ptr ptr long)
+@ stdcall ZwCreateTimer(ptr long ptr long) NtCreateTimer
+@ stdcall ZwCreateToken(ptr long ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr)
+@ stdcall ZwCreateWaitablePort(ptr ptr long long long) NtCreateWaitablePort
+@ stdcall ZwDebugActiveProcess(ptr ptr) NtDebugActiveProcess
+@ stdcall ZwDebugContinue(ptr ptr long) NtDebugContinue
+@ stdcall ZwDelayExecution(long ptr) NtDelayExecution
+@ stdcall ZwDeleteAtom(long) NtDeleteAtom
+@ stdcall ZwDeleteBootEntry(long) NtDeleteBootEntry
+@ stdcall ZwDeleteFile(ptr) NtDeleteFile
+@ stdcall ZwDeleteKey(long) NtDeleteKey
+@ stdcall ZwDeleteObjectAuditAlarm(ptr ptr long)
+@ stdcall ZwDeleteValueKey(long ptr) NtDeleteValueKey
+@ stdcall ZwDeviceIoControlFile(long long long long long long long long long long) NtDeviceIoControlFile
+@ stdcall ZwDisplayString(ptr) NtDisplayString
+@ stdcall ZwDuplicateObject(long long long ptr long long long) NtDuplicateObject
+@ stdcall ZwDuplicateToken(long long long long long long) NtDuplicateToken
+@ stdcall ZwEnumerateBootEntries(ptr ptr)
+;@ stdcall ZwEnumerateBus ; 3.51 only
+@ stdcall ZwEnumerateKey(long long long ptr long ptr) NtEnumerateKey
+@ stdcall ZwEnumerateSystemEnvironmentValuesEx(long ptr long) NtEnumerateSystemEnvironmentValuesEx
+@ stdcall ZwEnumerateValueKey(long long long ptr long ptr) NtEnumerateValueKey
+@ stdcall ZwExtendSection(ptr ptr) NtExtendSection
+@ stdcall ZwFilterToken(ptr long ptr ptr ptr ptr) NtFilterToken
+@ stdcall ZwFindAtom(ptr long ptr) NtFindAtom
+@ stdcall ZwFlushBuffersFile(long ptr) NtFlushBuffersFile
+@ stdcall ZwFlushInstructionCache(long ptr long) NtFlushInstructionCache
+@ stdcall ZwFlushKey(long) NtFlushKey
+@ stdcall ZwFlushVirtualMemory(long ptr ptr long) NtFlushVirtualMemory
+@ stdcall ZwFlushWriteBuffer()
+@ stdcall ZwFreeUserPhysicalPages(ptr ptr ptr)
+@ stdcall ZwFreeVirtualMemory(long ptr ptr long) NtFreeVirtualMemory
+@ stdcall ZwFsControlFile(long long long long long long long long long long) NtFsControlFile
+@ stdcall ZwGetContextThread(long ptr) NtGetContextThread
+@ stdcall ZwGetCurrentProcessorNumber()
+@ stdcall ZwGetDevicePowerState(ptr ptr)
+@ stdcall ZwGetPlugPlayEvent(long long ptr long)
+;@ stdcall ZwGetTickCount() NtGetTickCount
+@ stdcall ZwGetWriteWatch(long long ptr long ptr ptr ptr) NtGetWriteWatch
+@ stdcall ZwImpersonateAnonymousToken(ptr)
+@ stdcall ZwImpersonateClientOfPort(ptr ptr) NtImpersonateClientOfPort
+@ stdcall ZwImpersonateThread(ptr ptr ptr) NtImpersonateThread
+@ stdcall ZwInitializeRegistry(long)
+@ stdcall ZwInitiatePowerAction(long long long long) NtInitiatePowerAction
+@ stdcall ZwIsProcessInJob(long long) NtIsProcessInJob
+@ stdcall ZwIsSystemResumeAutomatic()
+@ stdcall ZwListenPort(ptr ptr) NtListenPort
+@ stdcall ZwLoadDriver(ptr) NtLoadDriver
+@ stdcall ZwLoadKey2(ptr ptr long) NtLoadKey2
+@ stdcall ZwLoadKey(ptr ptr) NtLoadKey
+@ stdcall ZwLockFile(long long ptr ptr ptr ptr ptr ptr long long) NtLockFile
+@ stdcall ZwLockProductActivationKeys(ptr ptr) NtLockProductActivationKeys
+@ stdcall ZwLockRegistryKey(ptr) NtLockRegistryKey
+@ stdcall ZwLockVirtualMemory(long ptr ptr long) NtLockVirtualMemory
+@ stdcall ZwMakePermanentObject(ptr) NtMakePermanentObject
+@ stdcall ZwMakeTemporaryObject(long) NtMakeTemporaryObject
+@ stdcall ZwMapUserPhysicalPages(ptr ptr ptr)
+@ stdcall ZwMapUserPhysicalPagesScatter(ptr ptr ptr)
+@ stdcall ZwMapViewOfSection(long long ptr long long ptr ptr long long long) NtMapViewOfSection
+@ stdcall ZwModifyBootEntry(ptr) NtModifyBootEntry
+@ stdcall ZwNotifyChangeDirectoryFile(long long ptr ptr ptr ptr long long long) NtNotifyChangeDirectoryFile
+@ stdcall ZwNotifyChangeKey(long long ptr ptr ptr long long ptr long long) NtNotifyChangeKey
+@ stdcall ZwNotifyChangeMultipleKeys(ptr long ptr ptr ptr ptr ptr long long ptr long long) NtNotifyChangeMultipleKeys
+@ stdcall ZwOpenDirectoryObject(long long long) NtOpenDirectoryObject
+@ stdcall ZwOpenEvent(long long long) NtOpenEvent
+@ stdcall ZwOpenEventPair(ptr long ptr) NtOpenEventPair
+@ stdcall ZwOpenFile(ptr long ptr ptr long long) NtOpenFile
+@ stdcall ZwOpenIoCompletion(ptr long ptr) NtOpenIoCompletion
+@ stdcall ZwOpenJobObject(ptr long ptr) NtOpenJobObject
+@ stdcall ZwOpenKey(ptr long ptr) NtOpenKey
+@ stdcall ZwOpenKeyedEvent(ptr long ptr) NtOpenKeyedEvent
+@ stdcall ZwOpenMutant(ptr long ptr) NtOpenMutant
+@ stdcall ZwOpenObjectAuditAlarm(ptr ptr ptr ptr ptr ptr long long ptr long long ptr)
+@ stdcall ZwOpenProcess(ptr long ptr ptr) NtOpenProcess
+@ stdcall ZwOpenProcessToken(long long ptr) NtOpenProcessToken
+@ stdcall ZwOpenProcessTokenEx(long long long ptr) NtOpenProcessTokenEx
+@ stdcall ZwOpenSection(ptr long ptr) NtOpenSection
+@ stdcall ZwOpenSemaphore(long long ptr) NtOpenSemaphore
+@ stdcall ZwOpenSymbolicLinkObject (ptr long ptr) NtOpenSymbolicLinkObject
+@ stdcall ZwOpenThread(ptr long ptr ptr) NtOpenThread
+@ stdcall ZwOpenThreadToken(long long long ptr) NtOpenThreadToken
+@ stdcall ZwOpenThreadTokenEx(long long long long ptr) NtOpenThreadTokenEx
+@ stdcall ZwOpenTimer(ptr long ptr) NtOpenTimer
+@ stdcall ZwPlugPlayControl(ptr ptr long)
+@ stdcall ZwPowerInformation(long ptr long ptr long) NtPowerInformation
+@ stdcall ZwPrivilegeCheck(ptr ptr ptr) NtPrivilegeCheck
+@ stdcall ZwPrivilegeObjectAuditAlarm(ptr ptr ptr long ptr long)
+@ stdcall ZwPrivilegedServiceAuditAlarm(ptr ptr ptr ptr long)
+@ stdcall ZwProtectVirtualMemory(long ptr ptr long ptr) NtProtectVirtualMemory
+@ stdcall ZwPulseEvent(long ptr) NtPulseEvent
+@ stdcall ZwQueryAttributesFile(ptr ptr) NtQueryAttributesFile
+@ stdcall ZwQueryBootEntryOrder(ptr ptr) NtQueryBootEntryOrder
+@ stdcall ZwQueryBootOptions(ptr ptr) NtQueryBootOptions
+@ stdcall ZwQueryDebugFilterState(long long) NtQueryDebugFilterState
+@ stdcall ZwQueryDefaultLocale(long ptr) NtQueryDefaultLocale
+@ stdcall ZwQueryDefaultUILanguage(ptr) NtQueryDefaultUILanguage
+@ stdcall ZwQueryDirectoryFile(long long ptr ptr ptr ptr long long long ptr long) NtQueryDirectoryFile
+@ stdcall ZwQueryDirectoryObject(long ptr long long long ptr ptr) NtQueryDirectoryObject
+@ stdcall ZwQueryEaFile(long ptr ptr long long ptr long ptr long) NtQueryEaFile
+@ stdcall ZwQueryEvent(long long ptr long ptr) NtQueryEvent
+@ stdcall ZwQueryFullAttributesFile(ptr ptr) NtQueryFullAttributesFile
+@ stdcall ZwQueryInformationAtom(long long ptr long ptr) NtQueryInformationAtom
+@ stdcall ZwQueryInformationFile(long ptr ptr long long) NtQueryInformationFile
+@ stdcall ZwQueryInformationJobObject(long long ptr long ptr) NtQueryInformationJobObject
+@ stdcall ZwQueryInformationPort(ptr long ptr long ptr) NtQueryInformationPort
+@ stdcall ZwQueryInformationProcess(long long ptr long ptr) NtQueryInformationProcess
+@ stdcall ZwQueryInformationThread(long long ptr long ptr) NtQueryInformationThread
+@ stdcall ZwQueryInformationToken(long long ptr long ptr) NtQueryInformationToken
+@ stdcall ZwQueryInstallUILanguage(ptr) NtQueryInstallUILanguage
+@ stdcall ZwQueryIntervalProfile(long ptr) NtQueryIntervalProfile
+@ stdcall ZwQueryIoCompletion(long long ptr long ptr) NtQueryIoCompletion
+@ stdcall ZwQueryKey(long long ptr long ptr) NtQueryKey
+@ stdcall ZwQueryMultipleValueKey(long ptr long ptr long ptr) NtQueryMultipleValueKey
+@ stdcall ZwQueryMutant(long long ptr long ptr) NtQueryMutant
+@ stdcall ZwQueryObject(long long long long long) NtQueryObject
+@ stdcall ZwQueryOpenSubKeys(ptr ptr) NtQueryOpenSubKeys
+@ stdcall ZwQueryPerformanceCounter (long long) NtQueryPerformanceCounter
+@ stdcall ZwQueryPortInformationProcess() NtQueryPortInformationProcess
+@ stdcall ZwQueryQuotaInformationFile(ptr ptr ptr long long ptr long ptr long) NtQueryQuotaInformationFile
+@ stdcall ZwQuerySection (long long long long long) NtQuerySection
+@ stdcall ZwQuerySecurityObject (long long long long long) NtQuerySecurityObject
+@ stdcall ZwQuerySemaphore (long long long long long) NtQuerySemaphore
+@ stdcall ZwQuerySymbolicLinkObject(long ptr ptr) NtQuerySymbolicLinkObject
+@ stdcall ZwQuerySystemEnvironmentValue(ptr ptr long ptr) NtQuerySystemEnvironmentValue
+@ stdcall ZwQuerySystemEnvironmentValueEx(ptr ptr ptr ptr ptr) NtQuerySystemEnvironmentValueEx
+@ stdcall ZwQuerySystemInformation(long long long long) NtQuerySystemInformation
+@ stdcall ZwQuerySystemTime(ptr) NtQuerySystemTime
+@ stdcall ZwQueryTimer(ptr long ptr long ptr) NtQueryTimer
+@ stdcall ZwQueryTimerResolution(long long long) NtQueryTimerResolution
+@ stdcall ZwQueryValueKey(long ptr long ptr long ptr) NtQueryValueKey
+@ stdcall ZwQueryVirtualMemory(long ptr long ptr long ptr) NtQueryVirtualMemory
+@ stdcall ZwQueryVolumeInformationFile(long ptr ptr long long) NtQueryVolumeInformationFile
+@ stdcall ZwQueueApcThread(long ptr long long long) NtQueueApcThread
+@ stdcall ZwRaiseException(ptr ptr long) NtRaiseException
+@ stdcall ZwRaiseHardError(long long long ptr long ptr) NtRaiseHardError
+@ stdcall ZwReadFile(long long ptr ptr ptr ptr long ptr ptr) NtReadFile
+@ stdcall ZwReadFileScatter(long long ptr ptr ptr ptr long ptr ptr) NtReadFileScatter
+@ stdcall ZwReadRequestData(ptr ptr long ptr long ptr) NtReadRequestData
+@ stdcall ZwReadVirtualMemory(long ptr ptr long ptr) NtReadVirtualMemory
+;@ stdcall ZwRegisterNewDevice ; 3.51 only
+@ stdcall ZwRegisterThreadTerminatePort(ptr) NtRegisterThreadTerminatePort
+@ stdcall ZwReleaseKeyedEvent(ptr ptr long ptr) NtReleaseKeyedEvent
+@ stdcall ZwReleaseMutant(long ptr) NtReleaseMutant
+;@ stdcall ZwReleaseProcessMutant ; 3.51 only
+@ stdcall ZwReleaseSemaphore(long long ptr) NtReleaseSemaphore
+@ stdcall ZwRemoveIoCompletion(ptr ptr ptr ptr ptr) NtRemoveIoCompletion
+@ stdcall ZwRemoveProcessDebug(ptr ptr) NtRemoveProcessDebug
+@ stdcall ZwRenameKey(ptr ptr) NtRenameKey
+@ stdcall ZwReplaceKey(ptr long ptr) NtReplaceKey
+@ stdcall ZwReplyPort(ptr ptr) NtReplyPort
+@ stdcall ZwReplyWaitReceivePort(ptr ptr ptr ptr) NtReplyWaitReceivePort
+@ stdcall ZwReplyWaitReceivePortEx(ptr ptr ptr ptr ptr)
+@ stdcall ZwReplyWaitReplyPort(ptr ptr)
+@ stdcall ZwRequestDeviceWakeup(ptr)
+@ stdcall ZwRequestPort(ptr ptr)
+@ stdcall ZwRequestWaitReplyPort(ptr ptr ptr)
+@ stdcall ZwRequestWakeupLatency(long)
+@ stdcall ZwResetEvent(long ptr)
+@ stdcall ZwResetWriteWatch(long ptr long)
+@ stdcall ZwRestoreKey(long long long)
+@ stdcall ZwResumeProcess(ptr)
+@ stdcall ZwResumeThread(long long)
+@ stdcall ZwSaveKey(long long)
+@ stdcall ZwSaveKeyEx(ptr ptr long)
+@ stdcall ZwSaveMergedKeys(ptr ptr ptr)
+@ stdcall ZwSecureConnectPort(ptr ptr ptr ptr ptr ptr ptr ptr ptr)
+@ stdcall ZwSetBootEntryOrder(ptr ptr)
+@ stdcall ZwSetBootOptions(ptr long)
+@ stdcall ZwSetContextThread(long ptr)
+@ stdcall ZwSetDebugFilterState(long long long)
+@ stdcall ZwSetDefaultHardErrorPort(ptr)
+@ stdcall ZwSetDefaultLocale(long long)
+@ stdcall ZwSetDefaultUILanguage(long)
+@ stdcall ZwSetEaFile(long ptr ptr long)
+@ stdcall ZwSetEvent(long long)
+@ stdcall ZwSetEventBoostPriority(ptr)
+@ stdcall ZwSetHighEventPair(ptr)
+@ stdcall ZwSetHighWaitLowEventPair(ptr)
+;@ stdcall ZwSetHighWaitLowThread ; 3.51 and 4.0 only
+@ stdcall ZwSetInformationDebugObject(ptr long ptr long ptr)
+@ stdcall ZwSetInformationFile(long long long long long)
+@ stdcall ZwSetInformationJobObject(long long ptr long)
+@ stdcall ZwSetInformationKey(long long ptr long)
+@ stdcall ZwSetInformationObject(long long ptr long)
+@ stdcall ZwSetInformationProcess(long long long long)
+@ stdcall ZwSetInformationThread(long long ptr long)
+@ stdcall ZwSetInformationToken(long long ptr long)
+@ stdcall ZwSetIntervalProfile(long long)
+@ stdcall ZwSetIoCompletion(ptr long ptr long long)
+@ stdcall ZwSetLdtEntries(long double long double) ; CHECKME
+@ stdcall ZwSetLowEventPair(ptr)
+@ stdcall ZwSetLowWaitHighEventPair(ptr)
+;@ stdcall ZwSetLowWaitHighThread ; 3.51 and 4.0 only
+@ stdcall ZwSetQuotaInformationFile(ptr ptr ptr long)
+@ stdcall ZwSetSecurityObject(long long ptr)
+@ stdcall ZwSetSystemEnvironmentValue(ptr ptr)
+@ stdcall ZwSetSystemEnvironmentValueEx(ptr ptr)
+@ stdcall ZwSetSystemInformation(long ptr long)
+@ stdcall ZwSetSystemPowerState(long long long)
+@ stdcall ZwSetSystemTime(ptr ptr)
+@ stdcall ZwSetThreadExecutionState(long ptr)
+@ stdcall ZwSetTimer(long ptr ptr ptr long long ptr)
+@ stdcall ZwSetTimerResolution(long long ptr)
+@ stdcall ZwSetUuidSeed(ptr)
+@ stdcall ZwSetValueKey(long long long long long long)
+@ stdcall ZwSetVolumeInformationFile(long ptr ptr long long)
+@ stdcall ZwShutdownSystem(long)
+@ stdcall ZwSignalAndWaitForSingleObject(long long long ptr)
+@ stdcall ZwStartProfile(ptr)
+@ stdcall ZwStopProfile(ptr)
+@ stdcall ZwSuspendProcess(ptr)
+@ stdcall ZwSuspendThread(long ptr)
+@ stdcall ZwSystemDebugControl(long ptr long ptr long ptr)
+@ stdcall ZwTerminateJobObject(long long)
+@ stdcall ZwTerminateProcess(long long)
+@ stdcall ZwTerminateThread(long long)
+@ stdcall ZwTestAlert()
+@ stdcall ZwTraceEvent(long long long ptr)
+@ stdcall ZwTranslateFilePath(ptr long ptr long)
+@ stdcall ZwUnloadDriver(ptr)
+@ stdcall ZwUnloadKey(long)
+@ stdcall ZwUnloadKeyEx(ptr ptr)
+@ stdcall ZwUnlockFile(long ptr ptr ptr ptr)
+@ stdcall ZwUnlockVirtualMemory(long ptr ptr long)
+@ stdcall ZwUnmapViewOfSection(long ptr)
+@ stdcall ZwVdmControl(long ptr)
+;@ stdcall ZwW32Call(long ptr long ptr ptr)
+@ stdcall ZwWaitForDebugEvent(ptr long ptr ptr)
+@ stdcall ZwWaitForKeyedEvent(ptr ptr long ptr)
+@ stdcall ZwWaitForMultipleObjects(long ptr long long ptr)
+;@ stdcall ZwWaitForProcessMutant ; 3.51 only
+@ stdcall ZwWaitForSingleObject(long long long)
+@ stdcall ZwWaitHighEventPair(ptr)
+@ stdcall ZwWaitLowEventPair(ptr)
+@ stdcall ZwWriteFile(long long ptr ptr ptr ptr long ptr ptr)
+@ stdcall ZwWriteFileGather(long long ptr ptr ptr ptr long ptr ptr)
+@ stdcall ZwWriteRequestData(ptr ptr long ptr long ptr)
+@ stdcall ZwWriteVirtualMemory(long ptr ptr long ptr)
+@ stdcall ZwYieldExecution()
+@ cdecl -arch=i386 _CIcos()
+@ cdecl -arch=i386 _CIlog()
+@ cdecl -arch=i386 _CIpow()
+@ cdecl -arch=i386 _CIsin()
+@ cdecl -arch=i386 _CIsqrt()
+@ cdecl -arch=x86_64 __C_specific_handler(ptr long ptr ptr)
+@ cdecl __isascii(long)
+@ cdecl __iscsym(long)
+@ cdecl __iscsymf(long)
+@ cdecl __toascii(long)
+@ cdecl -arch=i386 -ret64 _alldiv(double double)
+@ cdecl -arch=i386 _alldvrm()
+@ cdecl -arch=i386 -ret64 _allmul(double double)
+@ cdecl -arch=i386 -norelay _alloca_probe()
+@ cdecl -arch=i386 -ret64 _allrem(double double)
+@ cdecl -arch=i386 _allshl()
+@ cdecl -arch=i386 _allshr()
+@ cdecl -ret64 _atoi64(str)
+@ cdecl -arch=i386 -ret64 _aulldiv(double double)
+@ cdecl -arch=i386 _aulldvrm()
+@ cdecl -arch=i386 -ret64 _aullrem(double double)
+@ cdecl -arch=i386 _aullshr()
+@ extern -arch=i386 _chkstk
+@ cdecl -arch=i386,x86_64 _fltused()
+@ cdecl -arch=i386 -ret64 _ftol()
+@ cdecl _i64toa(double ptr long)
+@ cdecl _i64tow(double ptr long)
+@ cdecl _itoa(long ptr long)
+@ cdecl _itow(long ptr long)
+@ cdecl _lfind(ptr ptr ptr long ptr)
+@ cdecl -arch=x86_64 _local_unwind()
+@ cdecl _ltoa(long ptr long)
+@ cdecl _ltow(long ptr long)
+@ cdecl _memccpy(ptr ptr long long)
+@ cdecl _memicmp(str str long)
+@ cdecl -arch=x86_64 _setjmp(ptr ptr)
+@ cdecl -arch=x86_64 _setjmpex(ptr ptr)
+@ varargs _snprintf(ptr long str)
+@ varargs _snwprintf(ptr long wstr)
+@ cdecl _splitpath(str ptr ptr ptr ptr)
+@ cdecl _strcmpi(str str) _stricmp
+@ cdecl _stricmp(str str)
+@ cdecl _strlwr(str)
+@ cdecl _strnicmp(str str long)
+@ cdecl _strupr(str)
+@ cdecl _tolower(long)
+@ cdecl _toupper(long)
+@ cdecl _ui64toa(double ptr long)
+@ cdecl _ui64tow(double ptr long)
+@ cdecl _ultoa(long ptr long)
+@ cdecl _ultow(long ptr long)
+@ cdecl _vscwprintf(wstr ptr)
+@ cdecl _vsnprintf(ptr long str ptr)
+@ cdecl _vsnwprintf(ptr long wstr ptr)
+@ cdecl _wcsicmp(wstr wstr)
+@ cdecl _wcslwr(wstr)
+@ cdecl _wcsnicmp(wstr wstr long)
+@ cdecl _wcsupr(wstr)
+@ cdecl _wtoi(wstr)
+@ cdecl _wtoi64(wstr)
+@ cdecl _wtol(wstr)
+@ cdecl abs(long)
+@ cdecl -arch=i386,x86_64 atan(double)
+@ cdecl atoi(str)
+@ cdecl atol(str)
+@ cdecl bsearch(ptr ptr long long ptr)
+@ cdecl -arch=i386,x86_64 ceil(double)
+@ cdecl -arch=i386,x86_64 cos(double)
+@ cdecl -arch=i386,x86_64 fabs(double)
+@ cdecl -arch=i386,x86_64 floor(double)
+@ cdecl isalnum(long)
+@ cdecl isalpha(long)
+@ cdecl iscntrl(long)
+@ cdecl isdigit(long)
+@ cdecl isgraph(long)
+@ cdecl islower(long)
+@ cdecl isprint(long)
+@ cdecl ispunct(long)
+@ cdecl isspace(long)
+@ cdecl isupper(long)
+@ cdecl iswalpha(long)
+@ cdecl iswctype(long long)
+@ cdecl iswdigit(long)
+@ cdecl iswlower(long)
+@ cdecl iswspace(long)
+@ cdecl iswxdigit(long)
+@ cdecl isxdigit(long)
+@ cdecl labs(long)
+@ cdecl -arch=i386,x86_64 log(double)
+@ cdecl -arch=x86_64 longjmp(ptr)
+@ cdecl mbstowcs(ptr str long)
+@ cdecl memchr(ptr long long)
+@ cdecl memcmp(ptr ptr long)
+@ cdecl memcpy(ptr ptr long) memmove
+@ cdecl memmove(ptr ptr long)
+@ cdecl memset(ptr long long)
+@ cdecl -arch=i386,x86_64 pow(double double)
+@ cdecl qsort(ptr long long ptr)
+@ cdecl -arch=i386,x86_64 sin(double)
+@ varargs sprintf(ptr str)
+@ cdecl -arch=i386,x86_64 sqrt(double)
+@ varargs sscanf(str str)
+@ cdecl strcat(str str)
+@ cdecl strchr(str long)
+@ cdecl strcmp(str str)
+@ cdecl strcpy(ptr str)
+@ cdecl strcspn(str str)
+@ cdecl strlen(str)
+@ cdecl strncat(str str long)
+@ cdecl strncmp(str str long)
+@ cdecl strncpy(ptr str long)
+@ cdecl strpbrk(str str)
+@ cdecl strrchr(str long)
+@ cdecl strspn(str str)
+@ cdecl strstr(str str)
+@ cdecl strtol(str ptr long)
+@ cdecl strtoul(str ptr long)
+@ varargs swprintf(ptr wstr)
+@ cdecl -arch=i386,x86_64 tan(double)
+@ cdecl tolower(long)
+@ cdecl toupper(long)
+@ cdecl towlower(long)
+@ cdecl towupper(long)
+@ stdcall vDbgPrintEx(long long str ptr)
+@ stdcall vDbgPrintExWithPrefix(str long long str ptr)
+@ cdecl vsprintf(ptr str ptr)
+@ cdecl wcscat(wstr wstr)
+@ cdecl wcschr(wstr long)
+@ cdecl wcscmp(wstr wstr)
+@ cdecl wcscpy(ptr wstr)
+@ cdecl wcscspn(wstr wstr)
+@ cdecl wcslen(wstr)
+@ cdecl wcsncat(wstr wstr long)
+@ cdecl wcsncmp(wstr wstr long)
+@ cdecl wcsncpy(ptr wstr long)
+@ cdecl wcspbrk(wstr wstr)
+@ cdecl wcsrchr(wstr long)
+@ cdecl wcsspn(wstr wstr)
+@ cdecl wcsstr(wstr wstr)
+;@ cdecl wcstok(wstr wstr)
+@ cdecl wcstol(wstr ptr long)
+@ cdecl wcstombs(ptr ptr long)
+@ cdecl wcstoul(wstr ptr long)
--- /dev/null
- /* synched with wine 1.1.26 */
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * FILE: dll/win32/kernel32/wine/actctx.c
+ * PURPOSE: Activation contexts
+ * PROGRAMMERS: Jacek Caban for CodeWeavers
+ * Eric Pouech
+ * Jon Griffiths
+ * Dmitry Chapyshev (dmitry@reactos.org)
+ * Samuel Serapión
+ */
+
- FIXME("%08x %s %u %s %p\n", dwFlags, debugstr_guid(lpExtGuid),
- ulId, debugstr_guid(lpSearchGuid), pInfo);
- SetLastError( ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
- }
++/* Partly synched with Wine 1.7.17 */
+
+#include <k32.h>
+
+#define NDEBUG
+#include <debug.h>
+DEBUG_CHANNEL(actctx);
+
+#define ACTCTX_FAKE_HANDLE ((HANDLE) 0xf00baa)
+
+/***********************************************************************
+ * CreateActCtxA (KERNEL32.@)
+ *
+ * Create an activation context.
+ */
+HANDLE WINAPI CreateActCtxA(PCACTCTXA pActCtx)
+{
+ ACTCTXW actw;
+ SIZE_T len;
+ HANDLE ret = INVALID_HANDLE_VALUE;
+ LPWSTR src = NULL, assdir = NULL, resname = NULL, appname = NULL;
+
+ TRACE("%p %08x\n", pActCtx, pActCtx ? pActCtx->dwFlags : 0);
+
+ if (!pActCtx || pActCtx->cbSize != sizeof(*pActCtx))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ actw.cbSize = sizeof(actw);
+ actw.dwFlags = pActCtx->dwFlags;
+ if (pActCtx->lpSource)
+ {
+ len = MultiByteToWideChar(CP_ACP, 0, pActCtx->lpSource, -1, NULL, 0);
+ src = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (!src) return INVALID_HANDLE_VALUE;
+ MultiByteToWideChar(CP_ACP, 0, pActCtx->lpSource, -1, src, len);
+ }
+ actw.lpSource = src;
+
+ if (actw.dwFlags & ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID)
+ actw.wProcessorArchitecture = pActCtx->wProcessorArchitecture;
+ if (actw.dwFlags & ACTCTX_FLAG_LANGID_VALID)
+ actw.wLangId = pActCtx->wLangId;
+ if (actw.dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID)
+ {
+ len = MultiByteToWideChar(CP_ACP, 0, pActCtx->lpAssemblyDirectory, -1, NULL, 0);
+ assdir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (!assdir) goto done;
+ MultiByteToWideChar(CP_ACP, 0, pActCtx->lpAssemblyDirectory, -1, assdir, len);
+ actw.lpAssemblyDirectory = assdir;
+ }
+ if (actw.dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID)
+ {
+ if ((ULONG_PTR)pActCtx->lpResourceName >> 16)
+ {
+ len = MultiByteToWideChar(CP_ACP, 0, pActCtx->lpResourceName, -1, NULL, 0);
+ resname = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (!resname) goto done;
+ MultiByteToWideChar(CP_ACP, 0, pActCtx->lpResourceName, -1, resname, len);
+ actw.lpResourceName = resname;
+ }
+ else actw.lpResourceName = (LPCWSTR)pActCtx->lpResourceName;
+ }
+ if (actw.dwFlags & ACTCTX_FLAG_APPLICATION_NAME_VALID)
+ {
+ len = MultiByteToWideChar(CP_ACP, 0, pActCtx->lpApplicationName, -1, NULL, 0);
+ appname = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (!appname) goto done;
+ MultiByteToWideChar(CP_ACP, 0, pActCtx->lpApplicationName, -1, appname, len);
+ actw.lpApplicationName = appname;
+ }
+ if (actw.dwFlags & ACTCTX_FLAG_HMODULE_VALID)
+ actw.hModule = pActCtx->hModule;
+
+ ret = CreateActCtxW(&actw);
+
+done:
+ HeapFree(GetProcessHeap(), 0, src);
+ HeapFree(GetProcessHeap(), 0, assdir);
+ HeapFree(GetProcessHeap(), 0, resname);
+ HeapFree(GetProcessHeap(), 0, appname);
+ return ret;
+}
+
+/***********************************************************************
+ * CreateActCtxW (KERNEL32.@)
+ *
+ * Create an activation context.
+ */
+HANDLE WINAPI CreateActCtxW(PCACTCTXW pActCtx)
+{
+ NTSTATUS status;
+ HANDLE hActCtx;
+
+ TRACE("%p %08x\n", pActCtx, pActCtx ? pActCtx->dwFlags : 0);
+
+ if ((status = RtlCreateActivationContext(0, (PVOID)pActCtx, 0, NULL, NULL, &hActCtx)))
+ {
+ SetLastError(RtlNtStatusToDosError(status));
+ return INVALID_HANDLE_VALUE;
+ }
+ return hActCtx;
+}
+
+/***********************************************************************
+ * FindActCtxSectionStringA (KERNEL32.@)
+ *
+ * Find information about a string in an activation context.
+ */
+BOOL WINAPI FindActCtxSectionStringA(DWORD dwFlags, const GUID* lpExtGuid,
+ ULONG ulId, LPCSTR lpSearchStr,
+ PACTCTX_SECTION_KEYED_DATA pInfo)
+{
+ LPWSTR search_str;
+ DWORD len;
+ BOOL ret;
+
+ TRACE("%08x %s %u %s %p\n", dwFlags, debugstr_guid(lpExtGuid),
+ ulId, debugstr_a(lpSearchStr), pInfo);
+
+ if (!lpSearchStr)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ len = MultiByteToWideChar(CP_ACP, 0, lpSearchStr, -1, NULL, 0);
+ search_str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, lpSearchStr, -1, search_str, len);
+
+ ret = FindActCtxSectionStringW(dwFlags, lpExtGuid, ulId, search_str, pInfo);
+
+ HeapFree(GetProcessHeap(), 0, search_str);
+ return ret;
+}
+
+/***********************************************************************
+ * FindActCtxSectionStringW (KERNEL32.@)
+ *
+ * Find information about a string in an activation context.
+ */
+BOOL WINAPI FindActCtxSectionStringW(DWORD dwFlags, const GUID* lpExtGuid,
+ ULONG ulId, LPCWSTR lpSearchStr,
+ PACTCTX_SECTION_KEYED_DATA pInfo)
+{
+ UNICODE_STRING us;
+ NTSTATUS status;
+
+ RtlInitUnicodeString(&us, lpSearchStr);
+ if ((status = RtlFindActivationContextSectionString(dwFlags, lpExtGuid, ulId, &us, pInfo)))
+ {
+ SetLastError(RtlNtStatusToDosError(status));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/***********************************************************************
+ * FindActCtxSectionGuid (KERNEL32.@)
+ *
+ * Find information about a GUID in an activation context.
+ */
+BOOL WINAPI FindActCtxSectionGuid(DWORD dwFlags, const GUID* lpExtGuid,
+ ULONG ulId, const GUID* lpSearchGuid,
+ PACTCTX_SECTION_KEYED_DATA pInfo)
+{
++ NTSTATUS status;
+
++ if ((status = RtlFindActivationContextSectionGuid(dwFlags, lpExtGuid, ulId, lpSearchGuid, pInfo)))
++ {
++ SetLastError(RtlNtStatusToDosError(status));
++ return FALSE;
++ }
++
++ return TRUE;
++}
+
+/* EOF */
--- /dev/null
- if(!(dwAttrFrom & FILE_ATTRIBUTE_DIRECTORY))
+/*
+ * Path Functions
+ *
+ * Copyright 1999, 2000 Juergen Schmied
+ * Copyright 2001, 2002 Jon Griffiths
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "precomp.h"
+
+/* Get a function pointer from a DLL handle */
+#define GET_FUNC(func, module, name, fail) \
+ do { \
+ if (!func) { \
+ if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \
+ func = (fn##func)GetProcAddress(SHLWAPI_h##module, name); \
+ if (!func) return fail; \
+ } \
+ } while (0)
+
+/* DLL handles for late bound calls */
+static HMODULE SHLWAPI_hshell32;
+
+/* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */
+typedef BOOL (WINAPI *fnpIsNetDrive)(int);
+static fnpIsNetDrive pIsNetDrive;
+
+HRESULT WINAPI SHGetWebFolderFilePathW(LPCWSTR,LPWSTR,DWORD);
+
+static inline WCHAR* heap_strdupAtoW(LPCSTR str)
+{
+ WCHAR *ret = NULL;
+
+ if (str)
+ {
+ DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
+ ret = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
+ if (ret)
+ MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
+ }
+
+ return ret;
+}
+
+/*************************************************************************
+ * PathAppendA [SHLWAPI.@]
+ *
+ * Append one path to another.
+ *
+ * PARAMS
+ * lpszPath [I/O] Initial part of path, and destination for output
+ * lpszAppend [I] Path to append
+ *
+ * RETURNS
+ * Success: TRUE. lpszPath contains the newly created path.
+ * Failure: FALSE, if either path is NULL, or PathCombineA() fails.
+ *
+ * NOTES
+ * lpszAppend must contain at least one backslash ('\') if not NULL.
+ * Because PathCombineA() is used to join the paths, the resulting
+ * path is also canonicalized.
+ */
+BOOL WINAPI PathAppendA (LPSTR lpszPath, LPCSTR lpszAppend)
+{
+ TRACE("(%s,%s)\n",debugstr_a(lpszPath), debugstr_a(lpszAppend));
+
+ if (lpszPath && lpszAppend)
+ {
+ if (!PathIsUNCA(lpszAppend))
+ while (*lpszAppend == '\\')
+ lpszAppend++;
+ if (PathCombineA(lpszPath, lpszPath, lpszAppend))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathAppendW [SHLWAPI.@]
+ *
+ * See PathAppendA.
+ */
+BOOL WINAPI PathAppendW(LPWSTR lpszPath, LPCWSTR lpszAppend)
+{
+ TRACE("(%s,%s)\n",debugstr_w(lpszPath), debugstr_w(lpszAppend));
+
+ if (lpszPath && lpszAppend)
+ {
+ if (!PathIsUNCW(lpszAppend))
+ while (*lpszAppend == '\\')
+ lpszAppend++;
+ if (PathCombineW(lpszPath, lpszPath, lpszAppend))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathCombineA [SHLWAPI.@]
+ *
+ * Combine two paths together.
+ *
+ * PARAMS
+ * lpszDest [O] Destination for combined path
+ * lpszDir [I] Directory path
+ * lpszFile [I] File path
+ *
+ * RETURNS
+ * Success: The output path
+ * Failure: NULL, if inputs are invalid.
+ *
+ * NOTES
+ * lpszDest should be at least MAX_PATH in size, and may point to the same
+ * memory location as lpszDir. The combined path is canonicalised.
+ */
+LPSTR WINAPI PathCombineA(LPSTR lpszDest, LPCSTR lpszDir, LPCSTR lpszFile)
+{
+ WCHAR szDest[MAX_PATH];
+ WCHAR szDir[MAX_PATH];
+ WCHAR szFile[MAX_PATH];
+ TRACE("(%p,%s,%s)\n", lpszDest, debugstr_a(lpszDir), debugstr_a(lpszFile));
+
+ /* Invalid parameters */
+ if (!lpszDest)
+ return NULL;
+ if (!lpszDir && !lpszFile)
+ {
+ lpszDest[0] = 0;
+ return NULL;
+ }
+
+ if (lpszDir)
+ MultiByteToWideChar(CP_ACP,0,lpszDir,-1,szDir,MAX_PATH);
+ if (lpszFile)
+ MultiByteToWideChar(CP_ACP,0,lpszFile,-1,szFile,MAX_PATH);
+
+ if (PathCombineW(szDest, lpszDir ? szDir : NULL, lpszFile ? szFile : NULL))
+ if (WideCharToMultiByte(CP_ACP,0,szDest,-1,lpszDest,MAX_PATH,0,0))
+ return lpszDest;
+
+ lpszDest[0] = 0;
+ return NULL;
+}
+
+/*************************************************************************
+ * PathCombineW [SHLWAPI.@]
+ *
+ * See PathCombineA.
+ */
+LPWSTR WINAPI PathCombineW(LPWSTR lpszDest, LPCWSTR lpszDir, LPCWSTR lpszFile)
+{
+ WCHAR szTemp[MAX_PATH];
+ BOOL bUseBoth = FALSE, bStrip = FALSE;
+
+ TRACE("(%p,%s,%s)\n", lpszDest, debugstr_w(lpszDir), debugstr_w(lpszFile));
+
+ /* Invalid parameters */
+ if (!lpszDest)
+ return NULL;
+ if (!lpszDir && !lpszFile)
+ {
+ lpszDest[0] = 0;
+ return NULL;
+ }
+
+ if ((!lpszFile || !*lpszFile) && lpszDir)
+ {
+ /* Use dir only */
+ lstrcpynW(szTemp, lpszDir, MAX_PATH);
+ }
+ else if (!lpszDir || !*lpszDir || !PathIsRelativeW(lpszFile))
+ {
+ if (!lpszDir || !*lpszDir || *lpszFile != '\\' || PathIsUNCW(lpszFile))
+ {
+ /* Use file only */
+ lstrcpynW(szTemp, lpszFile, MAX_PATH);
+ }
+ else
+ {
+ bUseBoth = TRUE;
+ bStrip = TRUE;
+ }
+ }
+ else
+ bUseBoth = TRUE;
+
+ if (bUseBoth)
+ {
+ lstrcpynW(szTemp, lpszDir, MAX_PATH);
+ if (bStrip)
+ {
+ PathStripToRootW(szTemp);
+ lpszFile++; /* Skip '\' */
+ }
+ if (!PathAddBackslashW(szTemp) || strlenW(szTemp) + strlenW(lpszFile) >= MAX_PATH)
+ {
+ lpszDest[0] = 0;
+ return NULL;
+ }
+ strcatW(szTemp, lpszFile);
+ }
+
+ PathCanonicalizeW(lpszDest, szTemp);
+ return lpszDest;
+}
+
+/*************************************************************************
+ * PathAddBackslashA [SHLWAPI.@]
+ *
+ * Append a backslash ('\') to a path if one doesn't exist.
+ *
+ * PARAMS
+ * lpszPath [I/O] The path to append a backslash to.
+ *
+ * RETURNS
+ * Success: The position of the last backslash in the path.
+ * Failure: NULL, if lpszPath is NULL or the path is too large.
+ */
+LPSTR WINAPI PathAddBackslashA(LPSTR lpszPath)
+{
+ size_t iLen;
+ LPSTR prev = lpszPath;
+
+ TRACE("(%s)\n",debugstr_a(lpszPath));
+
+ if (!lpszPath || (iLen = strlen(lpszPath)) >= MAX_PATH)
+ return NULL;
+
+ if (iLen)
+ {
+ do {
+ lpszPath = CharNextA(prev);
+ if (*lpszPath)
+ prev = lpszPath;
+ } while (*lpszPath);
+ if (*prev != '\\')
+ {
+ *lpszPath++ = '\\';
+ *lpszPath = '\0';
+ }
+ }
+ return lpszPath;
+}
+
+/*************************************************************************
+ * PathAddBackslashW [SHLWAPI.@]
+ *
+ * See PathAddBackslashA.
+ */
+LPWSTR WINAPI PathAddBackslashW( LPWSTR lpszPath )
+{
+ size_t iLen;
+
+ TRACE("(%s)\n",debugstr_w(lpszPath));
+
+ if (!lpszPath || (iLen = strlenW(lpszPath)) >= MAX_PATH)
+ return NULL;
+
+ if (iLen)
+ {
+ lpszPath += iLen;
+ if (lpszPath[-1] != '\\')
+ {
+ *lpszPath++ = '\\';
+ *lpszPath = '\0';
+ }
+ }
+ return lpszPath;
+}
+
+/*************************************************************************
+ * PathBuildRootA [SHLWAPI.@]
+ *
+ * Create a root drive string (e.g. "A:\") from a drive number.
+ *
+ * PARAMS
+ * lpszPath [O] Destination for the drive string
+ *
+ * RETURNS
+ * lpszPath
+ *
+ * NOTES
+ * If lpszPath is NULL or drive is invalid, nothing is written to lpszPath.
+ */
+LPSTR WINAPI PathBuildRootA(LPSTR lpszPath, int drive)
+{
+ TRACE("(%p,%d)\n", lpszPath, drive);
+
+ if (lpszPath && drive >= 0 && drive < 26)
+ {
+ lpszPath[0] = 'A' + drive;
+ lpszPath[1] = ':';
+ lpszPath[2] = '\\';
+ lpszPath[3] = '\0';
+ }
+ return lpszPath;
+}
+
+/*************************************************************************
+ * PathBuildRootW [SHLWAPI.@]
+ *
+ * See PathBuildRootA.
+ */
+LPWSTR WINAPI PathBuildRootW(LPWSTR lpszPath, int drive)
+{
+ TRACE("(%p,%d)\n", lpszPath, drive);
+
+ if (lpszPath && drive >= 0 && drive < 26)
+ {
+ lpszPath[0] = 'A' + drive;
+ lpszPath[1] = ':';
+ lpszPath[2] = '\\';
+ lpszPath[3] = '\0';
+ }
+ return lpszPath;
+}
+
+/*************************************************************************
+ * PathFindFileNameA [SHLWAPI.@]
+ *
+ * Locate the start of the file name in a path
+ *
+ * PARAMS
+ * lpszPath [I] Path to search
+ *
+ * RETURNS
+ * A pointer to the first character of the file name
+ */
+LPSTR WINAPI PathFindFileNameA(LPCSTR lpszPath)
+{
+ LPCSTR lastSlash = lpszPath;
+
+ TRACE("(%s)\n",debugstr_a(lpszPath));
+
+ while (lpszPath && *lpszPath)
+ {
+ if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') &&
+ lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/')
+ lastSlash = lpszPath + 1;
+ lpszPath = CharNextA(lpszPath);
+ }
+ return (LPSTR)lastSlash;
+}
+
+/*************************************************************************
+ * PathFindFileNameW [SHLWAPI.@]
+ *
+ * See PathFindFileNameA.
+ */
+LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
+{
+ LPCWSTR lastSlash = lpszPath;
+
+ TRACE("(%s)\n",debugstr_w(lpszPath));
+
+ while (lpszPath && *lpszPath)
+ {
+ if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') &&
+ lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/')
+ lastSlash = lpszPath + 1;
+ lpszPath++;
+ }
+ return (LPWSTR)lastSlash;
+}
+
+/*************************************************************************
+ * PathFindExtensionA [SHLWAPI.@]
+ *
+ * Locate the start of the file extension in a path
+ *
+ * PARAMS
+ * lpszPath [I] The path to search
+ *
+ * RETURNS
+ * A pointer to the first character of the extension, the end of
+ * the string if the path has no extension, or NULL If lpszPath is NULL
+ */
+LPSTR WINAPI PathFindExtensionA( LPCSTR lpszPath )
+{
+ LPCSTR lastpoint = NULL;
+
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if (lpszPath)
+ {
+ while (*lpszPath)
+ {
+ if (*lpszPath == '\\' || *lpszPath==' ')
+ lastpoint = NULL;
+ else if (*lpszPath == '.')
+ lastpoint = lpszPath;
+ lpszPath = CharNextA(lpszPath);
+ }
+ }
+ return (LPSTR)(lastpoint ? lastpoint : lpszPath);
+}
+
+/*************************************************************************
+ * PathFindExtensionW [SHLWAPI.@]
+ *
+ * See PathFindExtensionA.
+ */
+LPWSTR WINAPI PathFindExtensionW( LPCWSTR lpszPath )
+{
+ LPCWSTR lastpoint = NULL;
+
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if (lpszPath)
+ {
+ while (*lpszPath)
+ {
+ if (*lpszPath == '\\' || *lpszPath==' ')
+ lastpoint = NULL;
+ else if (*lpszPath == '.')
+ lastpoint = lpszPath;
+ lpszPath++;
+ }
+ }
+ return (LPWSTR)(lastpoint ? lastpoint : lpszPath);
+}
+
+/*************************************************************************
+ * PathGetArgsA [SHLWAPI.@]
+ *
+ * Find the next argument in a string delimited by spaces.
+ *
+ * PARAMS
+ * lpszPath [I] The string to search for arguments in
+ *
+ * RETURNS
+ * The start of the next argument in lpszPath, or NULL if lpszPath is NULL
+ *
+ * NOTES
+ * Spaces in quoted strings are ignored as delimiters.
+ */
+LPSTR WINAPI PathGetArgsA(LPCSTR lpszPath)
+{
+ BOOL bSeenQuote = FALSE;
+
+ TRACE("(%s)\n",debugstr_a(lpszPath));
+
+ if (lpszPath)
+ {
+ while (*lpszPath)
+ {
+ if ((*lpszPath==' ') && !bSeenQuote)
+ return (LPSTR)lpszPath + 1;
+ if (*lpszPath == '"')
+ bSeenQuote = !bSeenQuote;
+ lpszPath = CharNextA(lpszPath);
+ }
+ }
+ return (LPSTR)lpszPath;
+}
+
+/*************************************************************************
+ * PathGetArgsW [SHLWAPI.@]
+ *
+ * See PathGetArgsA.
+ */
+LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath)
+{
+ BOOL bSeenQuote = FALSE;
+
+ TRACE("(%s)\n",debugstr_w(lpszPath));
+
+ if (lpszPath)
+ {
+ while (*lpszPath)
+ {
+ if ((*lpszPath==' ') && !bSeenQuote)
+ return (LPWSTR)lpszPath + 1;
+ if (*lpszPath == '"')
+ bSeenQuote = !bSeenQuote;
+ lpszPath++;
+ }
+ }
+ return (LPWSTR)lpszPath;
+}
+
+/*************************************************************************
+ * PathGetDriveNumberA [SHLWAPI.@]
+ *
+ * Return the drive number from a path
+ *
+ * PARAMS
+ * lpszPath [I] Path to get the drive number from
+ *
+ * RETURNS
+ * Success: The drive number corresponding to the drive in the path
+ * Failure: -1, if lpszPath contains no valid drive
+ */
+int WINAPI PathGetDriveNumberA(LPCSTR lpszPath)
+{
+ TRACE ("(%s)\n",debugstr_a(lpszPath));
+
+ if (lpszPath && !IsDBCSLeadByte(*lpszPath) && lpszPath[1] == ':' &&
+ tolower(*lpszPath) >= 'a' && tolower(*lpszPath) <= 'z')
+ return tolower(*lpszPath) - 'a';
+ return -1;
+}
+
+/*************************************************************************
+ * PathGetDriveNumberW [SHLWAPI.@]
+ *
+ * See PathGetDriveNumberA.
+ */
+int WINAPI PathGetDriveNumberW(LPCWSTR lpszPath)
+{
+ TRACE ("(%s)\n",debugstr_w(lpszPath));
+
+ if (lpszPath)
+ {
+ WCHAR tl = tolowerW(lpszPath[0]);
+ if (tl >= 'a' && tl <= 'z' && lpszPath[1] == ':')
+ return tl - 'a';
+ }
+ return -1;
+}
+
+/*************************************************************************
+ * PathRemoveFileSpecA [SHLWAPI.@]
+ *
+ * Remove the file specification from a path.
+ *
+ * PARAMS
+ * lpszPath [I/O] Path to remove the file spec from
+ *
+ * RETURNS
+ * TRUE If the path was valid and modified
+ * FALSE Otherwise
+ */
+BOOL WINAPI PathRemoveFileSpecA(LPSTR lpszPath)
+{
+ LPSTR lpszFileSpec = lpszPath;
+ BOOL bModified = FALSE;
+
+ TRACE("(%s)\n",debugstr_a(lpszPath));
+
+ if(lpszPath)
+ {
+ /* Skip directory or UNC path */
+ if (*lpszPath == '\\')
+ lpszFileSpec = ++lpszPath;
+ if (*lpszPath == '\\')
+ lpszFileSpec = ++lpszPath;
+
+ while (*lpszPath)
+ {
+ if(*lpszPath == '\\')
+ lpszFileSpec = lpszPath; /* Skip dir */
+ else if(*lpszPath == ':')
+ {
+ lpszFileSpec = ++lpszPath; /* Skip drive */
+ if (*lpszPath == '\\')
+ lpszFileSpec++;
+ }
+ if (!(lpszPath = CharNextA(lpszPath)))
+ break;
+ }
+
+ if (*lpszFileSpec)
+ {
+ *lpszFileSpec = '\0';
+ bModified = TRUE;
+ }
+ }
+ return bModified;
+}
+
+/*************************************************************************
+ * PathRemoveFileSpecW [SHLWAPI.@]
+ *
+ * See PathRemoveFileSpecA.
+ */
+BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath)
+{
+ LPWSTR lpszFileSpec = lpszPath;
+ BOOL bModified = FALSE;
+
+ TRACE("(%s)\n",debugstr_w(lpszPath));
+
+ if(lpszPath)
+ {
+ /* Skip directory or UNC path */
+ if (*lpszPath == '\\')
+ lpszFileSpec = ++lpszPath;
+ if (*lpszPath == '\\')
+ lpszFileSpec = ++lpszPath;
+
+ while (*lpszPath)
+ {
+ if(*lpszPath == '\\')
+ lpszFileSpec = lpszPath; /* Skip dir */
+ else if(*lpszPath == ':')
+ {
+ lpszFileSpec = ++lpszPath; /* Skip drive */
+ if (*lpszPath == '\\')
+ lpszFileSpec++;
+ }
+ lpszPath++;
+ }
+
+ if (*lpszFileSpec)
+ {
+ *lpszFileSpec = '\0';
+ bModified = TRUE;
+ }
+ }
+ return bModified;
+}
+
+/*************************************************************************
+ * PathStripPathA [SHLWAPI.@]
+ *
+ * Remove the initial path from the beginning of a filename
+ *
+ * PARAMS
+ * lpszPath [I/O] Path to remove the initial path from
+ *
+ * RETURNS
+ * Nothing.
+ */
+void WINAPI PathStripPathA(LPSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if (lpszPath)
+ {
+ LPSTR lpszFileName = PathFindFileNameA(lpszPath);
+ if(lpszFileName)
+ RtlMoveMemory(lpszPath, lpszFileName, strlen(lpszFileName)+1);
+ }
+}
+
+/*************************************************************************
+ * PathStripPathW [SHLWAPI.@]
+ *
+ * See PathStripPathA.
+ */
+void WINAPI PathStripPathW(LPWSTR lpszPath)
+{
+ LPWSTR lpszFileName;
+
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+ lpszFileName = PathFindFileNameW(lpszPath);
+ if(lpszFileName)
+ RtlMoveMemory(lpszPath, lpszFileName, (strlenW(lpszFileName)+1)*sizeof(WCHAR));
+}
+
+/*************************************************************************
+ * PathStripToRootA [SHLWAPI.@]
+ *
+ * Reduce a path to its root.
+ *
+ * PARAMS
+ * lpszPath [I/O] the path to reduce
+ *
+ * RETURNS
+ * Success: TRUE if the stripped path is a root path
+ * Failure: FALSE if the path cannot be stripped or is NULL
+ */
+BOOL WINAPI PathStripToRootA(LPSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if (!lpszPath)
+ return FALSE;
+ while(!PathIsRootA(lpszPath))
+ if (!PathRemoveFileSpecA(lpszPath))
+ return FALSE;
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathStripToRootW [SHLWAPI.@]
+ *
+ * See PathStripToRootA.
+ */
+BOOL WINAPI PathStripToRootW(LPWSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if (!lpszPath)
+ return FALSE;
+ while(!PathIsRootW(lpszPath))
+ if (!PathRemoveFileSpecW(lpszPath))
+ return FALSE;
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathRemoveArgsA [SHLWAPI.@]
+ *
+ * Strip space separated arguments from a path.
+ *
+ * PARAMS
+ * lpszPath [I/O] Path to remove arguments from
+ *
+ * RETURNS
+ * Nothing.
+ */
+void WINAPI PathRemoveArgsA(LPSTR lpszPath)
+{
+ TRACE("(%s)\n",debugstr_a(lpszPath));
+
+ if(lpszPath)
+ {
+ LPSTR lpszArgs = PathGetArgsA(lpszPath);
+ if (*lpszArgs)
+ lpszArgs[-1] = '\0';
+ else
+ {
+ LPSTR lpszLastChar = CharPrevA(lpszPath, lpszArgs);
+ if(*lpszLastChar == ' ')
+ *lpszLastChar = '\0';
+ }
+ }
+}
+
+/*************************************************************************
+ * PathRemoveArgsW [SHLWAPI.@]
+ *
+ * See PathRemoveArgsA.
+ */
+void WINAPI PathRemoveArgsW(LPWSTR lpszPath)
+{
+ TRACE("(%s)\n",debugstr_w(lpszPath));
+
+ if(lpszPath)
+ {
+ LPWSTR lpszArgs = PathGetArgsW(lpszPath);
+ if (*lpszArgs || (lpszArgs > lpszPath && lpszArgs[-1] == ' '))
+ lpszArgs[-1] = '\0';
+ }
+}
+
+/*************************************************************************
+ * PathRemoveExtensionA [SHLWAPI.@]
+ *
+ * Remove the file extension from a path
+ *
+ * PARAMS
+ * lpszPath [I/O] Path to remove the extension from
+ *
+ * NOTES
+ * The NUL terminator must be written only if extension exists
+ * and if the pointed character is not already NUL.
+ *
+ * RETURNS
+ * Nothing.
+ */
+void WINAPI PathRemoveExtensionA(LPSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if (lpszPath)
+ {
+ lpszPath = PathFindExtensionA(lpszPath);
+ if (lpszPath && *lpszPath != '\0')
+ *lpszPath = '\0';
+ }
+}
+
+/*************************************************************************
+ * PathRemoveExtensionW [SHLWAPI.@]
+ *
+ * See PathRemoveExtensionA.
+*/
+void WINAPI PathRemoveExtensionW(LPWSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if (lpszPath)
+ {
+ lpszPath = PathFindExtensionW(lpszPath);
+ if (lpszPath && *lpszPath != '\0')
+ *lpszPath = '\0';
+ }
+}
+
+/*************************************************************************
+ * PathRemoveBackslashA [SHLWAPI.@]
+ *
+ * Remove a trailing backslash from a path.
+ *
+ * PARAMS
+ * lpszPath [I/O] Path to remove backslash from
+ *
+ * RETURNS
+ * Success: A pointer to the end of the path
+ * Failure: NULL, if lpszPath is NULL
+ */
+LPSTR WINAPI PathRemoveBackslashA( LPSTR lpszPath )
+{
+ LPSTR szTemp = NULL;
+
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if(lpszPath)
+ {
+ szTemp = CharPrevA(lpszPath, lpszPath + strlen(lpszPath));
+ if (!PathIsRootA(lpszPath) && *szTemp == '\\')
+ *szTemp = '\0';
+ }
+ return szTemp;
+}
+
+/*************************************************************************
+ * PathRemoveBackslashW [SHLWAPI.@]
+ *
+ * See PathRemoveBackslashA.
+ */
+LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpszPath )
+{
+ LPWSTR szTemp = NULL;
+
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if(lpszPath)
+ {
+ szTemp = lpszPath + strlenW(lpszPath);
+ if (szTemp > lpszPath) szTemp--;
+ if (!PathIsRootW(lpszPath) && *szTemp == '\\')
+ *szTemp = '\0';
+ }
+ return szTemp;
+}
+
+/*************************************************************************
+ * PathRemoveBlanksA [SHLWAPI.@]
+ *
+ * Remove Spaces from the start and end of a path.
+ *
+ * PARAMS
+ * lpszPath [I/O] Path to strip blanks from
+ *
+ * RETURNS
+ * Nothing.
+ */
+VOID WINAPI PathRemoveBlanksA(LPSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if(lpszPath && *lpszPath)
+ {
+ LPSTR start = lpszPath;
+
+ while (*lpszPath == ' ')
+ lpszPath = CharNextA(lpszPath);
+
+ while(*lpszPath)
+ *start++ = *lpszPath++;
+
+ if (start != lpszPath)
+ while (start[-1] == ' ')
+ start--;
+ *start = '\0';
+ }
+}
+
+/*************************************************************************
+ * PathRemoveBlanksW [SHLWAPI.@]
+ *
+ * See PathRemoveBlanksA.
+ */
+VOID WINAPI PathRemoveBlanksW(LPWSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if(lpszPath && *lpszPath)
+ {
+ LPWSTR start = lpszPath;
+
+ while (*lpszPath == ' ')
+ lpszPath++;
+
+ while(*lpszPath)
+ *start++ = *lpszPath++;
+
+ if (start != lpszPath)
+ while (start[-1] == ' ')
+ start--;
+ *start = '\0';
+ }
+}
+
+/*************************************************************************
+ * PathQuoteSpacesA [SHLWAPI.@]
+ *
+ * Surround a path containing spaces in quotes.
+ *
+ * PARAMS
+ * lpszPath [I/O] Path to quote
+ *
+ * RETURNS
+ * Nothing.
+ *
+ * NOTES
+ * The path is not changed if it is invalid or has no spaces.
+ */
+VOID WINAPI PathQuoteSpacesA(LPSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if(lpszPath && StrChrA(lpszPath,' '))
+ {
+ size_t iLen = strlen(lpszPath) + 1;
+
+ if (iLen + 2 < MAX_PATH)
+ {
+ memmove(lpszPath + 1, lpszPath, iLen);
+ lpszPath[0] = '"';
+ lpszPath[iLen] = '"';
+ lpszPath[iLen + 1] = '\0';
+ }
+ }
+}
+
+/*************************************************************************
+ * PathQuoteSpacesW [SHLWAPI.@]
+ *
+ * See PathQuoteSpacesA.
+ */
+VOID WINAPI PathQuoteSpacesW(LPWSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if(lpszPath && StrChrW(lpszPath,' '))
+ {
+ int iLen = strlenW(lpszPath) + 1;
+
+ if (iLen + 2 < MAX_PATH)
+ {
+ memmove(lpszPath + 1, lpszPath, iLen * sizeof(WCHAR));
+ lpszPath[0] = '"';
+ lpszPath[iLen] = '"';
+ lpszPath[iLen + 1] = '\0';
+ }
+ }
+}
+
+/*************************************************************************
+ * PathUnquoteSpacesA [SHLWAPI.@]
+ *
+ * Remove quotes ("") from around a path, if present.
+ *
+ * PARAMS
+ * lpszPath [I/O] Path to strip quotes from
+ *
+ * RETURNS
+ * Nothing
+ *
+ * NOTES
+ * If the path contains a single quote only, an empty string will result.
+ * Otherwise quotes are only removed if they appear at the start and end
+ * of the path.
+ */
+VOID WINAPI PathUnquoteSpacesA(LPSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if (lpszPath && *lpszPath == '"')
+ {
+ DWORD dwLen = strlen(lpszPath) - 1;
+
+ if (lpszPath[dwLen] == '"')
+ {
+ lpszPath[dwLen] = '\0';
+ for (; *lpszPath; lpszPath++)
+ *lpszPath = lpszPath[1];
+ }
+ }
+}
+
+/*************************************************************************
+ * PathUnquoteSpacesW [SHLWAPI.@]
+ *
+ * See PathUnquoteSpacesA.
+ */
+VOID WINAPI PathUnquoteSpacesW(LPWSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if (lpszPath && *lpszPath == '"')
+ {
+ DWORD dwLen = strlenW(lpszPath) - 1;
+
+ if (lpszPath[dwLen] == '"')
+ {
+ lpszPath[dwLen] = '\0';
+ for (; *lpszPath; lpszPath++)
+ *lpszPath = lpszPath[1];
+ }
+ }
+}
+
+/*************************************************************************
+ * PathParseIconLocationA [SHLWAPI.@]
+ *
+ * Parse the location of an icon from a path.
+ *
+ * PARAMS
+ * lpszPath [I/O] The path to parse the icon location from.
+ *
+ * RETURNS
+ * Success: The number of the icon
+ * Failure: 0 if the path does not contain an icon location or is NULL
+ *
+ * NOTES
+ * The path has surrounding quotes and spaces removed regardless
+ * of whether the call succeeds or not.
+ */
+int WINAPI PathParseIconLocationA(LPSTR lpszPath)
+{
+ int iRet = 0;
+ LPSTR lpszComma;
+
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if (lpszPath)
+ {
+ if ((lpszComma = strchr(lpszPath, ',')))
+ {
+ *lpszComma++ = '\0';
+ iRet = StrToIntA(lpszComma);
+ }
+ PathUnquoteSpacesA(lpszPath);
+ PathRemoveBlanksA(lpszPath);
+ }
+ return iRet;
+}
+
+/*************************************************************************
+ * PathParseIconLocationW [SHLWAPI.@]
+ *
+ * See PathParseIconLocationA.
+ */
+int WINAPI PathParseIconLocationW(LPWSTR lpszPath)
+{
+ int iRet = 0;
+ LPWSTR lpszComma;
+
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if (lpszPath)
+ {
+ if ((lpszComma = StrChrW(lpszPath, ',')))
+ {
+ *lpszComma++ = '\0';
+ iRet = StrToIntW(lpszComma);
+ }
+ PathUnquoteSpacesW(lpszPath);
+ PathRemoveBlanksW(lpszPath);
+ }
+ return iRet;
+}
+
+/*************************************************************************
+ * @ [SHLWAPI.4]
+ *
+ * Unicode version of PathFileExistsDefExtA.
+ */
+BOOL WINAPI PathFileExistsDefExtW(LPWSTR lpszPath,DWORD dwWhich)
+{
+ static const WCHAR pszExts[][5] = { { '.', 'p', 'i', 'f', 0},
+ { '.', 'c', 'o', 'm', 0},
+ { '.', 'e', 'x', 'e', 0},
+ { '.', 'b', 'a', 't', 0},
+ { '.', 'l', 'n', 'k', 0},
+ { '.', 'c', 'm', 'd', 0},
+ { 0, 0, 0, 0, 0} };
+
+ TRACE("(%s,%d)\n", debugstr_w(lpszPath), dwWhich);
+
+ if (!lpszPath || PathIsUNCServerW(lpszPath) || PathIsUNCServerShareW(lpszPath))
+ return FALSE;
+
+ if (dwWhich)
+ {
+ LPCWSTR szExt = PathFindExtensionW(lpszPath);
+ if (!*szExt || dwWhich & 0x40)
+ {
+ size_t iChoose = 0;
+ int iLen = lstrlenW(lpszPath);
+ if (iLen > (MAX_PATH - 5))
+ return FALSE;
+ while ( (dwWhich & 0x1) && pszExts[iChoose][0] )
+ {
+ lstrcpyW(lpszPath + iLen, pszExts[iChoose]);
+ if (PathFileExistsW(lpszPath))
+ return TRUE;
+ iChoose++;
+ dwWhich >>= 1;
+ }
+ *(lpszPath + iLen) = (WCHAR)'\0';
+ return FALSE;
+ }
+ }
+ return PathFileExistsW(lpszPath);
+}
+
+/*************************************************************************
+ * @ [SHLWAPI.3]
+ *
+ * Determine if a file exists locally and is of an executable type.
+ *
+ * PARAMS
+ * lpszPath [I/O] File to search for
+ * dwWhich [I] Type of executable to search for
+ *
+ * RETURNS
+ * TRUE If the file was found. lpszPath contains the file name.
+ * FALSE Otherwise.
+ *
+ * NOTES
+ * lpszPath is modified in place and must be at least MAX_PATH in length.
+ * If the function returns FALSE, the path is modified to its original state.
+ * If the given path contains an extension or dwWhich is 0, executable
+ * extensions are not checked.
+ *
+ * Ordinals 3-6 are a classic case of MS exposing limited functionality to
+ * users (here through PathFindOnPathA()) and keeping advanced functionality for
+ * their own developers exclusive use. Monopoly, anyone?
+ */
+BOOL WINAPI PathFileExistsDefExtA(LPSTR lpszPath,DWORD dwWhich)
+{
+ BOOL bRet = FALSE;
+
+ TRACE("(%s,%d)\n", debugstr_a(lpszPath), dwWhich);
+
+ if (lpszPath)
+ {
+ WCHAR szPath[MAX_PATH];
+ MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
+ bRet = PathFileExistsDefExtW(szPath, dwWhich);
+ if (bRet)
+ WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0);
+ }
+ return bRet;
+}
+
+/*************************************************************************
+ * SHLWAPI_PathFindInOtherDirs
+ *
+ * Internal helper for SHLWAPI_PathFindOnPathExA/W.
+ */
+static BOOL SHLWAPI_PathFindInOtherDirs(LPWSTR lpszFile, DWORD dwWhich)
+{
+ static const WCHAR szSystem[] = { 'S','y','s','t','e','m','\0'};
+ static const WCHAR szPath[] = { 'P','A','T','H','\0'};
+ DWORD dwLenPATH;
+ LPCWSTR lpszCurr;
+ WCHAR *lpszPATH;
+ WCHAR buff[MAX_PATH];
+
+ TRACE("(%s,%08x)\n", debugstr_w(lpszFile), dwWhich);
+
+ /* Try system directories */
+ GetSystemDirectoryW(buff, MAX_PATH);
+ if (!PathAppendW(buff, lpszFile))
+ return FALSE;
+ if (PathFileExistsDefExtW(buff, dwWhich))
+ {
+ strcpyW(lpszFile, buff);
+ return TRUE;
+ }
+ GetWindowsDirectoryW(buff, MAX_PATH);
+ if (!PathAppendW(buff, szSystem ) || !PathAppendW(buff, lpszFile))
+ return FALSE;
+ if (PathFileExistsDefExtW(buff, dwWhich))
+ {
+ strcpyW(lpszFile, buff);
+ return TRUE;
+ }
+ GetWindowsDirectoryW(buff, MAX_PATH);
+ if (!PathAppendW(buff, lpszFile))
+ return FALSE;
+ if (PathFileExistsDefExtW(buff, dwWhich))
+ {
+ strcpyW(lpszFile, buff);
+ return TRUE;
+ }
+ /* Try dirs listed in %PATH% */
+ dwLenPATH = GetEnvironmentVariableW(szPath, buff, MAX_PATH);
+
+ if (!dwLenPATH || !(lpszPATH = HeapAlloc(GetProcessHeap(), 0, (dwLenPATH + 1) * sizeof (WCHAR))))
+ return FALSE;
+
+ GetEnvironmentVariableW(szPath, lpszPATH, dwLenPATH + 1);
+ lpszCurr = lpszPATH;
+ while (lpszCurr)
+ {
+ LPCWSTR lpszEnd = lpszCurr;
+ LPWSTR pBuff = buff;
+
+ while (*lpszEnd == ' ')
+ lpszEnd++;
+ while (*lpszEnd && *lpszEnd != ';')
+ *pBuff++ = *lpszEnd++;
+ *pBuff = '\0';
+
+ if (*lpszEnd)
+ lpszCurr = lpszEnd + 1;
+ else
+ lpszCurr = NULL; /* Last Path, terminate after this */
+
+ if (!PathAppendW(buff, lpszFile))
+ {
+ HeapFree(GetProcessHeap(), 0, lpszPATH);
+ return FALSE;
+ }
+ if (PathFileExistsDefExtW(buff, dwWhich))
+ {
+ strcpyW(lpszFile, buff);
+ HeapFree(GetProcessHeap(), 0, lpszPATH);
+ return TRUE;
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, lpszPATH);
+ return FALSE;
+}
+
+/*************************************************************************
+ * @ [SHLWAPI.5]
+ *
+ * Search a range of paths for a specific type of executable.
+ *
+ * PARAMS
+ * lpszFile [I/O] File to search for
+ * lppszOtherDirs [I] Other directories to look in
+ * dwWhich [I] Type of executable to search for
+ *
+ * RETURNS
+ * Success: TRUE. The path to the executable is stored in lpszFile.
+ * Failure: FALSE. The path to the executable is unchanged.
+ */
+BOOL WINAPI PathFindOnPathExA(LPSTR lpszFile,LPCSTR *lppszOtherDirs,DWORD dwWhich)
+{
+ WCHAR szFile[MAX_PATH];
+ WCHAR buff[MAX_PATH];
+
+ TRACE("(%s,%p,%08x)\n", debugstr_a(lpszFile), lppszOtherDirs, dwWhich);
+
+ if (!lpszFile || !PathIsFileSpecA(lpszFile))
+ return FALSE;
+
+ MultiByteToWideChar(CP_ACP,0,lpszFile,-1,szFile,MAX_PATH);
+
+ /* Search provided directories first */
+ if (lppszOtherDirs && *lppszOtherDirs)
+ {
+ WCHAR szOther[MAX_PATH];
+ LPCSTR *lpszOtherPath = lppszOtherDirs;
+
+ while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0])
+ {
+ MultiByteToWideChar(CP_ACP,0,*lpszOtherPath,-1,szOther,MAX_PATH);
+ PathCombineW(buff, szOther, szFile);
+ if (PathFileExistsDefExtW(buff, dwWhich))
+ {
+ WideCharToMultiByte(CP_ACP,0,buff,-1,lpszFile,MAX_PATH,0,0);
+ return TRUE;
+ }
+ lpszOtherPath++;
+ }
+ }
+ /* Not found, try system and path dirs */
+ if (SHLWAPI_PathFindInOtherDirs(szFile, dwWhich))
+ {
+ WideCharToMultiByte(CP_ACP,0,szFile,-1,lpszFile,MAX_PATH,0,0);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * @ [SHLWAPI.6]
+ *
+ * Unicode version of PathFindOnPathExA.
+ */
+BOOL WINAPI PathFindOnPathExW(LPWSTR lpszFile,LPCWSTR *lppszOtherDirs,DWORD dwWhich)
+{
+ WCHAR buff[MAX_PATH];
+
+ TRACE("(%s,%p,%08x)\n", debugstr_w(lpszFile), lppszOtherDirs, dwWhich);
+
+ if (!lpszFile || !PathIsFileSpecW(lpszFile))
+ return FALSE;
+
+ /* Search provided directories first */
+ if (lppszOtherDirs && *lppszOtherDirs)
+ {
+ LPCWSTR *lpszOtherPath = lppszOtherDirs;
+ while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0])
+ {
+ PathCombineW(buff, *lpszOtherPath, lpszFile);
+ if (PathFileExistsDefExtW(buff, dwWhich))
+ {
+ strcpyW(lpszFile, buff);
+ return TRUE;
+ }
+ lpszOtherPath++;
+ }
+ }
+ /* Not found, try system and path dirs */
+ return SHLWAPI_PathFindInOtherDirs(lpszFile, dwWhich);
+}
+
+/*************************************************************************
+ * PathFindOnPathA [SHLWAPI.@]
+ *
+ * Search a range of paths for an executable.
+ *
+ * PARAMS
+ * lpszFile [I/O] File to search for
+ * lppszOtherDirs [I] Other directories to look in
+ *
+ * RETURNS
+ * Success: TRUE. The path to the executable is stored in lpszFile.
+ * Failure: FALSE. The path to the executable is unchanged.
+ */
+BOOL WINAPI PathFindOnPathA(LPSTR lpszFile, LPCSTR *lppszOtherDirs)
+{
+ TRACE("(%s,%p)\n", debugstr_a(lpszFile), lppszOtherDirs);
+ return PathFindOnPathExA(lpszFile, lppszOtherDirs, 0);
+ }
+
+/*************************************************************************
+ * PathFindOnPathW [SHLWAPI.@]
+ *
+ * See PathFindOnPathA.
+ */
+BOOL WINAPI PathFindOnPathW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs)
+{
+ TRACE("(%s,%p)\n", debugstr_w(lpszFile), lppszOtherDirs);
+ return PathFindOnPathExW(lpszFile,lppszOtherDirs, 0);
+}
+
+/*************************************************************************
+ * PathCompactPathExA [SHLWAPI.@]
+ *
+ * Compact a path into a given number of characters.
+ *
+ * PARAMS
+ * lpszDest [O] Destination for compacted path
+ * lpszPath [I] Source path
+ * cchMax [I] Maximum size of compacted path
+ * dwFlags [I] Reserved
+ *
+ * RETURNS
+ * Success: TRUE. The compacted path is written to lpszDest.
+ * Failure: FALSE. lpszPath is undefined.
+ *
+ * NOTES
+ * If cchMax is given as 0, lpszDest will still be NUL terminated.
+ *
+ * The Win32 version of this function contains a bug: When cchMax == 7,
+ * 8 bytes will be written to lpszDest. This bug is fixed in the Wine
+ * implementation.
+ *
+ * Some relative paths will be different when cchMax == 5 or 6. This occurs
+ * because Win32 will insert a "\" in lpszDest, even if one is
+ * not present in the original path.
+ */
+BOOL WINAPI PathCompactPathExA(LPSTR lpszDest, LPCSTR lpszPath,
+ UINT cchMax, DWORD dwFlags)
+{
+ BOOL bRet = FALSE;
+
+ TRACE("(%p,%s,%d,0x%08x)\n", lpszDest, debugstr_a(lpszPath), cchMax, dwFlags);
+
+ if (lpszPath && lpszDest)
+ {
+ WCHAR szPath[MAX_PATH];
+ WCHAR szDest[MAX_PATH];
+
+ MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
+ szDest[0] = '\0';
+ bRet = PathCompactPathExW(szDest, szPath, cchMax, dwFlags);
+ WideCharToMultiByte(CP_ACP,0,szDest,-1,lpszDest,MAX_PATH,0,0);
+ }
+ return bRet;
+}
+
+/*************************************************************************
+ * PathCompactPathExW [SHLWAPI.@]
+ *
+ * See PathCompactPathExA.
+ */
+BOOL WINAPI PathCompactPathExW(LPWSTR lpszDest, LPCWSTR lpszPath,
+ UINT cchMax, DWORD dwFlags)
+{
+ static const WCHAR szEllipses[] = { '.', '.', '.', '\0' };
+ LPCWSTR lpszFile;
+ DWORD dwLen, dwFileLen = 0;
+
+ TRACE("(%p,%s,%d,0x%08x)\n", lpszDest, debugstr_w(lpszPath), cchMax, dwFlags);
+
+ if (!lpszPath)
+ return FALSE;
+
+ if (!lpszDest)
+ {
+ WARN("Invalid lpszDest would crash under Win32!\n");
+ return FALSE;
+ }
+
+ *lpszDest = '\0';
+
+ if (cchMax < 2)
+ return TRUE;
+
+ dwLen = strlenW(lpszPath) + 1;
+
+ if (dwLen < cchMax)
+ {
+ /* Don't need to compact */
+ memcpy(lpszDest, lpszPath, dwLen * sizeof(WCHAR));
+ return TRUE;
+ }
+
+ /* Path must be compacted to fit into lpszDest */
+ lpszFile = PathFindFileNameW(lpszPath);
+ dwFileLen = lpszPath + dwLen - lpszFile;
+
+ if (dwFileLen == dwLen)
+ {
+ /* No root in psth */
+ if (cchMax <= 4)
+ {
+ while (--cchMax > 0) /* No room left for anything but ellipses */
+ *lpszDest++ = '.';
+ *lpszDest = '\0';
+ return TRUE;
+ }
+ /* Compact the file name with ellipses at the end */
+ cchMax -= 4;
+ memcpy(lpszDest, lpszFile, cchMax * sizeof(WCHAR));
+ strcpyW(lpszDest + cchMax, szEllipses);
+ return TRUE;
+ }
+ /* We have a root in the path */
+ lpszFile--; /* Start compacted filename with the path separator */
+ dwFileLen++;
+
+ if (dwFileLen + 3 > cchMax)
+ {
+ /* Compact the file name */
+ if (cchMax <= 4)
+ {
+ while (--cchMax > 0) /* No room left for anything but ellipses */
+ *lpszDest++ = '.';
+ *lpszDest = '\0';
+ return TRUE;
+ }
+ strcpyW(lpszDest, szEllipses);
+ lpszDest += 3;
+ cchMax -= 4;
+ *lpszDest++ = *lpszFile++;
+ if (cchMax <= 4)
+ {
+ while (--cchMax > 0) /* No room left for anything but ellipses */
+ *lpszDest++ = '.';
+ *lpszDest = '\0';
+ return TRUE;
+ }
+ cchMax -= 4;
+ memcpy(lpszDest, lpszFile, cchMax * sizeof(WCHAR));
+ strcpyW(lpszDest + cchMax, szEllipses);
+ return TRUE;
+ }
+
+ /* Only the root needs to be Compacted */
+ dwLen = cchMax - dwFileLen - 3;
+ memcpy(lpszDest, lpszPath, dwLen * sizeof(WCHAR));
+ strcpyW(lpszDest + dwLen, szEllipses);
+ strcpyW(lpszDest + dwLen + 3, lpszFile);
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathIsRelativeA [SHLWAPI.@]
+ *
+ * Determine if a path is a relative path.
+ *
+ * PARAMS
+ * lpszPath [I] Path to check
+ *
+ * RETURNS
+ * TRUE: The path is relative, or is invalid.
+ * FALSE: The path is not relative.
+ */
+BOOL WINAPI PathIsRelativeA (LPCSTR lpszPath)
+{
+ TRACE("(%s)\n",debugstr_a(lpszPath));
+
+ if (!lpszPath || !*lpszPath || IsDBCSLeadByte(*lpszPath))
+ return TRUE;
+ if (*lpszPath == '\\' || (*lpszPath && lpszPath[1] == ':'))
+ return FALSE;
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathIsRelativeW [SHLWAPI.@]
+ *
+ * See PathIsRelativeA.
+ */
+BOOL WINAPI PathIsRelativeW (LPCWSTR lpszPath)
+{
+ TRACE("(%s)\n",debugstr_w(lpszPath));
+
+ if (!lpszPath || !*lpszPath)
+ return TRUE;
+ if (*lpszPath == '\\' || (*lpszPath && lpszPath[1] == ':'))
+ return FALSE;
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathIsRootA [SHLWAPI.@]
+ *
+ * Determine if a path is a root path.
+ *
+ * PARAMS
+ * lpszPath [I] Path to check
+ *
+ * RETURNS
+ * TRUE If lpszPath is valid and a root path,
+ * FALSE Otherwise
+ */
+BOOL WINAPI PathIsRootA(LPCSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if (lpszPath && *lpszPath)
+ {
+ if (*lpszPath == '\\')
+ {
+ if (!lpszPath[1])
+ return TRUE; /* \ */
+ else if (lpszPath[1]=='\\')
+ {
+ BOOL bSeenSlash = FALSE;
+ lpszPath += 2;
+
+ /* Check for UNC root path */
+ while (*lpszPath)
+ {
+ if (*lpszPath == '\\')
+ {
+ if (bSeenSlash)
+ return FALSE;
+ bSeenSlash = TRUE;
+ }
+ lpszPath = CharNextA(lpszPath);
+ }
+ return TRUE;
+ }
+ }
+ else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0')
+ return TRUE; /* X:\ */
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathIsRootW [SHLWAPI.@]
+ *
+ * See PathIsRootA.
+ */
+BOOL WINAPI PathIsRootW(LPCWSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if (lpszPath && *lpszPath)
+ {
+ if (*lpszPath == '\\')
+ {
+ if (!lpszPath[1])
+ return TRUE; /* \ */
+ else if (lpszPath[1]=='\\')
+ {
+ BOOL bSeenSlash = FALSE;
+ lpszPath += 2;
+
+ /* Check for UNC root path */
+ while (*lpszPath)
+ {
+ if (*lpszPath == '\\')
+ {
+ if (bSeenSlash)
+ return FALSE;
+ bSeenSlash = TRUE;
+ }
+ lpszPath++;
+ }
+ return TRUE;
+ }
+ }
+ else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0')
+ return TRUE; /* X:\ */
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathIsDirectoryA [SHLWAPI.@]
+ *
+ * Determine if a path is a valid directory
+ *
+ * PARAMS
+ * lpszPath [I] Path to check.
+ *
+ * RETURNS
+ * FILE_ATTRIBUTE_DIRECTORY if lpszPath exists and can be read (See Notes)
+ * FALSE if lpszPath is invalid or not a directory.
+ *
+ * NOTES
+ * Although this function is prototyped as returning a BOOL, it returns
+ * FILE_ATTRIBUTE_DIRECTORY for success. This means that code such as:
+ *
+ *| if (PathIsDirectoryA("c:\\windows\\") == TRUE)
+ *| ...
+ *
+ * will always fail.
+ */
+BOOL WINAPI PathIsDirectoryA(LPCSTR lpszPath)
+{
+ DWORD dwAttr;
+
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if (!lpszPath || PathIsUNCServerA(lpszPath))
+ return FALSE;
+
+ if (PathIsUNCServerShareA(lpszPath))
+ {
+ FIXME("UNC Server Share not yet supported - FAILING\n");
+ return FALSE;
+ }
+
+ if ((dwAttr = GetFileAttributesA(lpszPath)) == INVALID_FILE_ATTRIBUTES)
+ return FALSE;
+ return dwAttr & FILE_ATTRIBUTE_DIRECTORY;
+}
+
+/*************************************************************************
+ * PathIsDirectoryW [SHLWAPI.@]
+ *
+ * See PathIsDirectoryA.
+ */
+BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
+{
+ DWORD dwAttr;
+
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if (!lpszPath || PathIsUNCServerW(lpszPath))
+ return FALSE;
+
+ if (PathIsUNCServerShareW(lpszPath))
+ {
+ FIXME("UNC Server Share not yet supported - FAILING\n");
+ return FALSE;
+ }
+
+ if ((dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES)
+ return FALSE;
+ return dwAttr & FILE_ATTRIBUTE_DIRECTORY;
+}
+
+/*************************************************************************
+ * PathFileExistsA [SHLWAPI.@]
+ *
+ * Determine if a file exists.
+ *
+ * PARAMS
+ * lpszPath [I] Path to check
+ *
+ * RETURNS
+ * TRUE If the file exists and is readable
+ * FALSE Otherwise
+ */
+BOOL WINAPI PathFileExistsA(LPCSTR lpszPath)
+{
+ UINT iPrevErrMode;
+ DWORD dwAttr;
+
+ TRACE("(%s)\n",debugstr_a(lpszPath));
+
+ if (!lpszPath)
+ return FALSE;
+
+ /* Prevent a dialog box if path is on a disk that has been ejected. */
+ iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ dwAttr = GetFileAttributesA(lpszPath);
+ SetErrorMode(iPrevErrMode);
+ return dwAttr != INVALID_FILE_ATTRIBUTES;
+}
+
+/*************************************************************************
+ * PathFileExistsW [SHLWAPI.@]
+ *
+ * See PathFileExistsA.
+ */
+BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
+{
+ UINT iPrevErrMode;
+ DWORD dwAttr;
+
+ TRACE("(%s)\n",debugstr_w(lpszPath));
+
+ if (!lpszPath)
+ return FALSE;
+
+ iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ dwAttr = GetFileAttributesW(lpszPath);
+ SetErrorMode(iPrevErrMode);
+ return dwAttr != INVALID_FILE_ATTRIBUTES;
+}
+
+/*************************************************************************
+ * PathFileExistsAndAttributesA [SHLWAPI.445]
+ *
+ * Determine if a file exists.
+ *
+ * PARAMS
+ * lpszPath [I] Path to check
+ * dwAttr [O] attributes of file
+ *
+ * RETURNS
+ * TRUE If the file exists and is readable
+ * FALSE Otherwise
+ */
+BOOL WINAPI PathFileExistsAndAttributesA(LPCSTR lpszPath, DWORD *dwAttr)
+{
+ UINT iPrevErrMode;
+ DWORD dwVal = 0;
+
+ TRACE("(%s %p)\n", debugstr_a(lpszPath), dwAttr);
+
+ if (dwAttr)
+ *dwAttr = INVALID_FILE_ATTRIBUTES;
+
+ if (!lpszPath)
+ return FALSE;
+
+ iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ dwVal = GetFileAttributesA(lpszPath);
+ SetErrorMode(iPrevErrMode);
+ if (dwAttr)
+ *dwAttr = dwVal;
+ return (dwVal != INVALID_FILE_ATTRIBUTES);
+}
+
+/*************************************************************************
+ * PathFileExistsAndAttributesW [SHLWAPI.446]
+ *
+ * See PathFileExistsA.
+ */
+BOOL WINAPI PathFileExistsAndAttributesW(LPCWSTR lpszPath, DWORD *dwAttr)
+{
+ UINT iPrevErrMode;
+ DWORD dwVal;
+
+ TRACE("(%s %p)\n", debugstr_w(lpszPath), dwAttr);
+
+ if (!lpszPath)
+ return FALSE;
+
+ iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ dwVal = GetFileAttributesW(lpszPath);
+ SetErrorMode(iPrevErrMode);
+ if (dwAttr)
+ *dwAttr = dwVal;
+ return (dwVal != INVALID_FILE_ATTRIBUTES);
+}
+
+/*************************************************************************
+ * PathMatchSingleMaskA [internal]
+ */
+static BOOL PathMatchSingleMaskA(LPCSTR name, LPCSTR mask)
+{
+ while (*name && *mask && *mask!=';')
+ {
+ if (*mask == '*')
+ {
+ do
+ {
+ if (PathMatchSingleMaskA(name,mask+1))
+ return TRUE; /* try substrings */
+ } while (*name++);
+ return FALSE;
+ }
+
+ if (toupper(*mask) != toupper(*name) && *mask != '?')
+ return FALSE;
+
+ name = CharNextA(name);
+ mask = CharNextA(mask);
+ }
+
+ if (!*name)
+ {
+ while (*mask == '*')
+ mask++;
+ if (!*mask || *mask == ';')
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathMatchSingleMaskW [internal]
+ */
+static BOOL PathMatchSingleMaskW(LPCWSTR name, LPCWSTR mask)
+{
+ while (*name && *mask && *mask != ';')
+ {
+ if (*mask == '*')
+ {
+ do
+ {
+ if (PathMatchSingleMaskW(name,mask+1))
+ return TRUE; /* try substrings */
+ } while (*name++);
+ return FALSE;
+ }
+
+ if (toupperW(*mask) != toupperW(*name) && *mask != '?')
+ return FALSE;
+
+ name++;
+ mask++;
+ }
+ if (!*name)
+ {
+ while (*mask == '*')
+ mask++;
+ if (!*mask || *mask == ';')
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathMatchSpecA [SHLWAPI.@]
+ *
+ * Determine if a path matches one or more search masks.
+ *
+ * PARAMS
+ * lpszPath [I] Path to check
+ * lpszMask [I] Search mask(s)
+ *
+ * RETURNS
+ * TRUE If lpszPath is valid and is matched
+ * FALSE Otherwise
+ *
+ * NOTES
+ * Multiple search masks may be given if they are separated by ";". The
+ * pattern "*.*" is treated specially in that it matches all paths (for
+ * backwards compatibility with DOS).
+ */
+BOOL WINAPI PathMatchSpecA(LPCSTR lpszPath, LPCSTR lpszMask)
+{
+ TRACE("(%s,%s)\n", lpszPath, lpszMask);
+
+ if (!lstrcmpA(lpszMask, "*.*"))
+ return TRUE; /* Matches every path */
+
+ while (*lpszMask)
+ {
+ while (*lpszMask == ' ')
+ lpszMask++; /* Eat leading spaces */
+
+ if (PathMatchSingleMaskA(lpszPath, lpszMask))
+ return TRUE; /* Matches the current mask */
+
+ while (*lpszMask && *lpszMask != ';')
+ lpszMask = CharNextA(lpszMask); /* masks separated by ';' */
+
+ if (*lpszMask == ';')
+ lpszMask++;
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathMatchSpecW [SHLWAPI.@]
+ *
+ * See PathMatchSpecA.
+ */
+BOOL WINAPI PathMatchSpecW(LPCWSTR lpszPath, LPCWSTR lpszMask)
+{
+ static const WCHAR szStarDotStar[] = { '*', '.', '*', '\0' };
+
+ TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszMask));
+
+ if (!lstrcmpW(lpszMask, szStarDotStar))
+ return TRUE; /* Matches every path */
+
+ while (*lpszMask)
+ {
+ while (*lpszMask == ' ')
+ lpszMask++; /* Eat leading spaces */
+
+ if (PathMatchSingleMaskW(lpszPath, lpszMask))
+ return TRUE; /* Matches the current path */
+
+ while (*lpszMask && *lpszMask != ';')
+ lpszMask++; /* masks separated by ';' */
+
+ if (*lpszMask == ';')
+ lpszMask++;
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathIsSameRootA [SHLWAPI.@]
+ *
+ * Determine if two paths share the same root.
+ *
+ * PARAMS
+ * lpszPath1 [I] Source path
+ * lpszPath2 [I] Path to compare with
+ *
+ * RETURNS
+ * TRUE If both paths are valid and share the same root.
+ * FALSE If either path is invalid or the paths do not share the same root.
+ */
+BOOL WINAPI PathIsSameRootA(LPCSTR lpszPath1, LPCSTR lpszPath2)
+{
+ LPCSTR lpszStart;
+ int dwLen;
+
+ TRACE("(%s,%s)\n", debugstr_a(lpszPath1), debugstr_a(lpszPath2));
+
+ if (!lpszPath1 || !lpszPath2 || !(lpszStart = PathSkipRootA(lpszPath1)))
+ return FALSE;
+
+ dwLen = PathCommonPrefixA(lpszPath1, lpszPath2, NULL) + 1;
+ if (lpszStart - lpszPath1 > dwLen)
+ return FALSE; /* Paths not common up to length of the root */
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathIsSameRootW [SHLWAPI.@]
+ *
+ * See PathIsSameRootA.
+ */
+BOOL WINAPI PathIsSameRootW(LPCWSTR lpszPath1, LPCWSTR lpszPath2)
+{
+ LPCWSTR lpszStart;
+ int dwLen;
+
+ TRACE("(%s,%s)\n", debugstr_w(lpszPath1), debugstr_w(lpszPath2));
+
+ if (!lpszPath1 || !lpszPath2 || !(lpszStart = PathSkipRootW(lpszPath1)))
+ return FALSE;
+
+ dwLen = PathCommonPrefixW(lpszPath1, lpszPath2, NULL) + 1;
+ if (lpszStart - lpszPath1 > dwLen)
+ return FALSE; /* Paths not common up to length of the root */
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathIsContentTypeA [SHLWAPI.@]
+ *
+ * Determine if a file is of a given registered content type.
+ *
+ * PARAMS
+ * lpszPath [I] File to check
+ * lpszContentType [I] Content type to check for
+ *
+ * RETURNS
+ * TRUE If lpszPath is a given registered content type,
+ * FALSE Otherwise.
+ *
+ * NOTES
+ * This function looks up the registered content type for lpszPath. If
+ * a content type is registered, it is compared (case insensitively) to
+ * lpszContentType. Only if this matches does the function succeed.
+ */
+BOOL WINAPI PathIsContentTypeA(LPCSTR lpszPath, LPCSTR lpszContentType)
+{
+ LPCSTR szExt;
+ DWORD dwDummy;
+ char szBuff[MAX_PATH];
+
+ TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszContentType));
+
+ if (lpszPath && (szExt = PathFindExtensionA(lpszPath)) && *szExt &&
+ !SHGetValueA(HKEY_CLASSES_ROOT, szExt, "Content Type",
+ REG_NONE, szBuff, &dwDummy) &&
+ !strcasecmp(lpszContentType, szBuff))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathIsContentTypeW [SHLWAPI.@]
+ *
+ * See PathIsContentTypeA.
+ */
+BOOL WINAPI PathIsContentTypeW(LPCWSTR lpszPath, LPCWSTR lpszContentType)
+{
+ static const WCHAR szContentType[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0' };
+ LPCWSTR szExt;
+ DWORD dwDummy;
+ WCHAR szBuff[MAX_PATH];
+
+ TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszContentType));
+
+ if (lpszPath && (szExt = PathFindExtensionW(lpszPath)) && *szExt &&
+ !SHGetValueW(HKEY_CLASSES_ROOT, szExt, szContentType,
+ REG_NONE, szBuff, &dwDummy) &&
+ !strcmpiW(lpszContentType, szBuff))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathIsFileSpecA [SHLWAPI.@]
+ *
+ * Determine if a path is a file specification.
+ *
+ * PARAMS
+ * lpszPath [I] Path to check
+ *
+ * RETURNS
+ * TRUE If lpszPath is a file specification (i.e. Contains no directories).
+ * FALSE Otherwise.
+ */
+BOOL WINAPI PathIsFileSpecA(LPCSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if (!lpszPath)
+ return FALSE;
+
+ while (*lpszPath)
+ {
+ if (*lpszPath == '\\' || *lpszPath == ':')
+ return FALSE;
+ lpszPath = CharNextA(lpszPath);
+ }
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathIsFileSpecW [SHLWAPI.@]
+ *
+ * See PathIsFileSpecA.
+ */
+BOOL WINAPI PathIsFileSpecW(LPCWSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if (!lpszPath)
+ return FALSE;
+
+ while (*lpszPath)
+ {
+ if (*lpszPath == '\\' || *lpszPath == ':')
+ return FALSE;
+ lpszPath++;
+ }
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathIsPrefixA [SHLWAPI.@]
+ *
+ * Determine if a path is a prefix of another.
+ *
+ * PARAMS
+ * lpszPrefix [I] Prefix
+ * lpszPath [I] Path to check
+ *
+ * RETURNS
+ * TRUE If lpszPath has lpszPrefix as its prefix,
+ * FALSE If either path is NULL or lpszPrefix is not a prefix
+ */
+BOOL WINAPI PathIsPrefixA (LPCSTR lpszPrefix, LPCSTR lpszPath)
+{
+ TRACE("(%s,%s)\n", debugstr_a(lpszPrefix), debugstr_a(lpszPath));
+
+ if (lpszPrefix && lpszPath &&
+ PathCommonPrefixA(lpszPath, lpszPrefix, NULL) == (int)strlen(lpszPrefix))
+ return TRUE;
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathIsPrefixW [SHLWAPI.@]
+ *
+ * See PathIsPrefixA.
+ */
+BOOL WINAPI PathIsPrefixW(LPCWSTR lpszPrefix, LPCWSTR lpszPath)
+{
+ TRACE("(%s,%s)\n", debugstr_w(lpszPrefix), debugstr_w(lpszPath));
+
+ if (lpszPrefix && lpszPath &&
+ PathCommonPrefixW(lpszPath, lpszPrefix, NULL) == (int)strlenW(lpszPrefix))
+ return TRUE;
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathIsSystemFolderA [SHLWAPI.@]
+ *
+ * Determine if a path or file attributes are a system folder.
+ *
+ * PARAMS
+ * lpszPath [I] Path to check.
+ * dwAttrib [I] Attributes to check, if lpszPath is NULL.
+ *
+ * RETURNS
+ * TRUE If lpszPath or dwAttrib are a system folder.
+ * FALSE If GetFileAttributesA() fails or neither parameter is a system folder.
+ */
+BOOL WINAPI PathIsSystemFolderA(LPCSTR lpszPath, DWORD dwAttrib)
+{
+ TRACE("(%s,0x%08x)\n", debugstr_a(lpszPath), dwAttrib);
+
+ if (lpszPath && *lpszPath)
+ dwAttrib = GetFileAttributesA(lpszPath);
+
+ if (dwAttrib == INVALID_FILE_ATTRIBUTES || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) ||
+ !(dwAttrib & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)))
+ return FALSE;
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathIsSystemFolderW [SHLWAPI.@]
+ *
+ * See PathIsSystemFolderA.
+ */
+BOOL WINAPI PathIsSystemFolderW(LPCWSTR lpszPath, DWORD dwAttrib)
+{
+ TRACE("(%s,0x%08x)\n", debugstr_w(lpszPath), dwAttrib);
+
+ if (lpszPath && *lpszPath)
+ dwAttrib = GetFileAttributesW(lpszPath);
+
+ if (dwAttrib == INVALID_FILE_ATTRIBUTES || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) ||
+ !(dwAttrib & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)))
+ return FALSE;
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathIsUNCA [SHLWAPI.@]
+ *
+ * Determine if a path is in UNC format.
+ *
+ * PARAMS
+ * lpszPath [I] Path to check
+ *
+ * RETURNS
+ * TRUE: The path is UNC.
+ * FALSE: The path is not UNC or is NULL.
+ */
+BOOL WINAPI PathIsUNCA(LPCSTR lpszPath)
+{
+ TRACE("(%s)\n",debugstr_a(lpszPath));
+
+ if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\') && (lpszPath[2]!='?'))
+ return TRUE;
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathIsUNCW [SHLWAPI.@]
+ *
+ * See PathIsUNCA.
+ */
+BOOL WINAPI PathIsUNCW(LPCWSTR lpszPath)
+{
+ TRACE("(%s)\n",debugstr_w(lpszPath));
+
+ if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\') && (lpszPath[2]!='?'))
+ return TRUE;
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathIsUNCServerA [SHLWAPI.@]
+ *
+ * Determine if a path is a UNC server name ("\\SHARENAME").
+ *
+ * PARAMS
+ * lpszPath [I] Path to check.
+ *
+ * RETURNS
+ * TRUE If lpszPath is a valid UNC server name.
+ * FALSE Otherwise.
+ *
+ * NOTES
+ * This routine is bug compatible with Win32: Server names with a
+ * trailing backslash (e.g. "\\FOO\"), return FALSE incorrectly.
+ * Fixing this bug may break other shlwapi functions!
+ */
+BOOL WINAPI PathIsUNCServerA(LPCSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\')
+ {
+ while (*lpszPath)
+ {
+ if (*lpszPath == '\\')
+ return FALSE;
+ lpszPath = CharNextA(lpszPath);
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathIsUNCServerW [SHLWAPI.@]
+ *
+ * See PathIsUNCServerA.
+ */
+BOOL WINAPI PathIsUNCServerW(LPCWSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if (lpszPath && lpszPath[0] == '\\' && lpszPath[1] == '\\')
+ {
+ return !strchrW( lpszPath + 2, '\\' );
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathIsUNCServerShareA [SHLWAPI.@]
+ *
+ * Determine if a path is a UNC server share ("\\SHARENAME\SHARE").
+ *
+ * PARAMS
+ * lpszPath [I] Path to check.
+ *
+ * RETURNS
+ * TRUE If lpszPath is a valid UNC server share.
+ * FALSE Otherwise.
+ *
+ * NOTES
+ * This routine is bug compatible with Win32: Server shares with a
+ * trailing backslash (e.g. "\\FOO\BAR\"), return FALSE incorrectly.
+ * Fixing this bug may break other shlwapi functions!
+ */
+BOOL WINAPI PathIsUNCServerShareA(LPCSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\')
+ {
+ BOOL bSeenSlash = FALSE;
+ while (*lpszPath)
+ {
+ if (*lpszPath == '\\')
+ {
+ if (bSeenSlash)
+ return FALSE;
+ bSeenSlash = TRUE;
+ }
+ lpszPath = CharNextA(lpszPath);
+ }
+ return bSeenSlash;
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathIsUNCServerShareW [SHLWAPI.@]
+ *
+ * See PathIsUNCServerShareA.
+ */
+BOOL WINAPI PathIsUNCServerShareW(LPCWSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\')
+ {
+ BOOL bSeenSlash = FALSE;
+ while (*lpszPath)
+ {
+ if (*lpszPath == '\\')
+ {
+ if (bSeenSlash)
+ return FALSE;
+ bSeenSlash = TRUE;
+ }
+ lpszPath++;
+ }
+ return bSeenSlash;
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * PathCanonicalizeA [SHLWAPI.@]
+ *
+ * Convert a path to its canonical form.
+ *
+ * PARAMS
+ * lpszBuf [O] Output path
+ * lpszPath [I] Path to canonicalize
+ *
+ * RETURNS
+ * Success: TRUE. lpszBuf contains the output path,
+ * Failure: FALSE, If input path is invalid. lpszBuf is undefined
+ */
+BOOL WINAPI PathCanonicalizeA(LPSTR lpszBuf, LPCSTR lpszPath)
+{
+ BOOL bRet = FALSE;
+
+ TRACE("(%p,%s)\n", lpszBuf, debugstr_a(lpszPath));
+
+ if (lpszBuf)
+ *lpszBuf = '\0';
+
+ if (!lpszBuf || !lpszPath)
+ SetLastError(ERROR_INVALID_PARAMETER);
+ else
+ {
+ WCHAR szPath[MAX_PATH];
+ WCHAR szBuff[MAX_PATH];
+ int ret = MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
+
+ if (!ret) {
+ WARN("Failed to convert string to widechar (too long?), LE %d.\n", GetLastError());
+ return FALSE;
+ }
+ bRet = PathCanonicalizeW(szBuff, szPath);
+ WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszBuf,MAX_PATH,0,0);
+ }
+ return bRet;
+}
+
+
+/*************************************************************************
+ * PathCanonicalizeW [SHLWAPI.@]
+ *
+ * See PathCanonicalizeA.
+ */
+BOOL WINAPI PathCanonicalizeW(LPWSTR lpszBuf, LPCWSTR lpszPath)
+{
+ LPWSTR lpszDst = lpszBuf;
+ LPCWSTR lpszSrc = lpszPath;
+
+ TRACE("(%p,%s)\n", lpszBuf, debugstr_w(lpszPath));
+
+ if (lpszBuf)
+ *lpszDst = '\0';
+
+ if (!lpszBuf || !lpszPath)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ if (!*lpszPath)
+ {
+ *lpszBuf++ = '\\';
+ *lpszBuf = '\0';
+ return TRUE;
+ }
+
+ /* Copy path root */
+ if (*lpszSrc == '\\')
+ {
+ *lpszDst++ = *lpszSrc++;
+ }
+ else if (*lpszSrc && lpszSrc[1] == ':')
+ {
+ /* X:\ */
+ *lpszDst++ = *lpszSrc++;
+ *lpszDst++ = *lpszSrc++;
+ if (*lpszSrc == '\\')
+ *lpszDst++ = *lpszSrc++;
+ }
+
+ /* Canonicalize the rest of the path */
+ while (*lpszSrc)
+ {
+ if (*lpszSrc == '.')
+ {
+ if (lpszSrc[1] == '\\' && (lpszSrc == lpszPath || lpszSrc[-1] == '\\' || lpszSrc[-1] == ':'))
+ {
+ lpszSrc += 2; /* Skip .\ */
+ }
+ else if (lpszSrc[1] == '.' && (lpszDst == lpszBuf || lpszDst[-1] == '\\'))
+ {
+ /* \.. backs up a directory, over the root if it has no \ following X:.
+ * .. is ignored if it would remove a UNC server name or initial \\
+ */
+ if (lpszDst != lpszBuf)
+ {
+ *lpszDst = '\0'; /* Allow PathIsUNCServerShareA test on lpszBuf */
+ if (lpszDst > lpszBuf+1 && lpszDst[-1] == '\\' &&
+ (lpszDst[-2] != '\\' || lpszDst > lpszBuf+2))
+ {
+ if (lpszDst[-2] == ':' && (lpszDst > lpszBuf+3 || lpszDst[-3] == ':'))
+ {
+ lpszDst -= 2;
+ while (lpszDst > lpszBuf && *lpszDst != '\\')
+ lpszDst--;
+ if (*lpszDst == '\\')
+ lpszDst++; /* Reset to last '\' */
+ else
+ lpszDst = lpszBuf; /* Start path again from new root */
+ }
+ else if (lpszDst[-2] != ':' && !PathIsUNCServerShareW(lpszBuf))
+ lpszDst -= 2;
+ }
+ while (lpszDst > lpszBuf && *lpszDst != '\\')
+ lpszDst--;
+ if (lpszDst == lpszBuf)
+ {
+ *lpszDst++ = '\\';
+ lpszSrc++;
+ }
+ }
+ lpszSrc += 2; /* Skip .. in src path */
+ }
+ else
+ *lpszDst++ = *lpszSrc++;
+ }
+ else
+ *lpszDst++ = *lpszSrc++;
+ }
+ /* Append \ to naked drive specs */
+ if (lpszDst - lpszBuf == 2 && lpszDst[-1] == ':')
+ *lpszDst++ = '\\';
+ *lpszDst++ = '\0';
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathFindNextComponentA [SHLWAPI.@]
+ *
+ * Find the next component in a path.
+ *
+ * PARAMS
+ * lpszPath [I] Path to find next component in
+ *
+ * RETURNS
+ * Success: A pointer to the next component, or the end of the string.
+ * Failure: NULL, If lpszPath is invalid
+ *
+ * NOTES
+ * A 'component' is either a backslash character (\) or UNC marker (\\).
+ * Because of this, relative paths (e.g "c:foo") are regarded as having
+ * only one component.
+ */
+LPSTR WINAPI PathFindNextComponentA(LPCSTR lpszPath)
+{
+ LPSTR lpszSlash;
+
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if(!lpszPath || !*lpszPath)
+ return NULL;
+
+ if ((lpszSlash = StrChrA(lpszPath, '\\')))
+ {
+ if (lpszSlash[1] == '\\')
+ lpszSlash++;
+ return lpszSlash + 1;
+ }
+ return (LPSTR)lpszPath + strlen(lpszPath);
+}
+
+/*************************************************************************
+ * PathFindNextComponentW [SHLWAPI.@]
+ *
+ * See PathFindNextComponentA.
+ */
+LPWSTR WINAPI PathFindNextComponentW(LPCWSTR lpszPath)
+{
+ LPWSTR lpszSlash;
+
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if(!lpszPath || !*lpszPath)
+ return NULL;
+
+ if ((lpszSlash = StrChrW(lpszPath, '\\')))
+ {
+ if (lpszSlash[1] == '\\')
+ lpszSlash++;
+ return lpszSlash + 1;
+ }
+ return (LPWSTR)lpszPath + strlenW(lpszPath);
+}
+
+/*************************************************************************
+ * PathAddExtensionA [SHLWAPI.@]
+ *
+ * Add a file extension to a path
+ *
+ * PARAMS
+ * lpszPath [I/O] Path to add extension to
+ * lpszExtension [I] Extension to add to lpszPath
+ *
+ * RETURNS
+ * TRUE If the path was modified,
+ * FALSE If lpszPath or lpszExtension are invalid, lpszPath has an
+ * extension already, or the new path length is too big.
+ *
+ * FIXME
+ * What version of shlwapi.dll adds "exe" if lpszExtension is NULL? Win2k
+ * does not do this, so the behaviour was removed.
+ */
+BOOL WINAPI PathAddExtensionA(LPSTR lpszPath, LPCSTR lpszExtension)
+{
+ size_t dwLen;
+
+ TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszExtension));
+
+ if (!lpszPath || !lpszExtension || *(PathFindExtensionA(lpszPath)))
+ return FALSE;
+
+ dwLen = strlen(lpszPath);
+
+ if (dwLen + strlen(lpszExtension) >= MAX_PATH)
+ return FALSE;
+
+ strcpy(lpszPath + dwLen, lpszExtension);
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathAddExtensionW [SHLWAPI.@]
+ *
+ * See PathAddExtensionA.
+ */
+BOOL WINAPI PathAddExtensionW(LPWSTR lpszPath, LPCWSTR lpszExtension)
+{
+ size_t dwLen;
+
+ TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszExtension));
+
+ if (!lpszPath || !lpszExtension || *(PathFindExtensionW(lpszPath)))
+ return FALSE;
+
+ dwLen = strlenW(lpszPath);
+
+ if (dwLen + strlenW(lpszExtension) >= MAX_PATH)
+ return FALSE;
+
+ strcpyW(lpszPath + dwLen, lpszExtension);
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathMakePrettyA [SHLWAPI.@]
+ *
+ * Convert an uppercase DOS filename into lowercase.
+ *
+ * PARAMS
+ * lpszPath [I/O] Path to convert.
+ *
+ * RETURNS
+ * TRUE If the path was an uppercase DOS path and was converted,
+ * FALSE Otherwise.
+ */
+BOOL WINAPI PathMakePrettyA(LPSTR lpszPath)
+{
+ LPSTR pszIter = lpszPath;
+
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if (!pszIter)
+ return FALSE;
+
+ if (*pszIter)
+ {
+ do
+ {
+ if (islower(*pszIter) || IsDBCSLeadByte(*pszIter))
+ return FALSE; /* Not DOS path */
+ pszIter++;
+ } while (*pszIter);
+ pszIter = lpszPath + 1;
+ while (*pszIter)
+ {
+ *pszIter = tolower(*pszIter);
+ pszIter++;
+ }
+ }
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathMakePrettyW [SHLWAPI.@]
+ *
+ * See PathMakePrettyA.
+ */
+BOOL WINAPI PathMakePrettyW(LPWSTR lpszPath)
+{
+ LPWSTR pszIter = lpszPath;
+
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if (!pszIter)
+ return FALSE;
+
+ if (*pszIter)
+ {
+ do
+ {
+ if (islowerW(*pszIter))
+ return FALSE; /* Not DOS path */
+ pszIter++;
+ } while (*pszIter);
+ pszIter = lpszPath + 1;
+ while (*pszIter)
+ {
+ *pszIter = tolowerW(*pszIter);
+ pszIter++;
+ }
+ }
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathCommonPrefixA [SHLWAPI.@]
+ *
+ * Determine the length of the common prefix between two paths.
+ *
+ * PARAMS
+ * lpszFile1 [I] First path for comparison
+ * lpszFile2 [I] Second path for comparison
+ * achPath [O] Destination for common prefix string
+ *
+ * RETURNS
+ * The length of the common prefix. This is 0 if there is no common
+ * prefix between the paths or if any parameters are invalid. If the prefix
+ * is non-zero and achPath is not NULL, achPath is filled with the common
+ * part of the prefix and NUL terminated.
+ *
+ * NOTES
+ * A common prefix of 2 is always returned as 3. It is thus possible for
+ * the length returned to be invalid (i.e. Longer than one or both of the
+ * strings given as parameters). This Win32 behaviour has been implemented
+ * here, and cannot be changed (fixed?) without breaking other SHLWAPI calls.
+ * To work around this when using this function, always check that the byte
+ * at [common_prefix_len-1] is not a NUL. If it is, deduct 1 from the prefix.
+ */
+int WINAPI PathCommonPrefixA(LPCSTR lpszFile1, LPCSTR lpszFile2, LPSTR achPath)
+{
+ size_t iLen = 0;
+ LPCSTR lpszIter1 = lpszFile1;
+ LPCSTR lpszIter2 = lpszFile2;
+
+ TRACE("(%s,%s,%p)\n", debugstr_a(lpszFile1), debugstr_a(lpszFile2), achPath);
+
+ if (achPath)
+ *achPath = '\0';
+
+ if (!lpszFile1 || !lpszFile2)
+ return 0;
+
+ /* Handle roots first */
+ if (PathIsUNCA(lpszFile1))
+ {
+ if (!PathIsUNCA(lpszFile2))
+ return 0;
+ lpszIter1 += 2;
+ lpszIter2 += 2;
+ }
+ else if (PathIsUNCA(lpszFile2))
+ return 0; /* Know already lpszFile1 is not UNC */
+
+ do
+ {
+ /* Update len */
+ if ((!*lpszIter1 || *lpszIter1 == '\\') &&
+ (!*lpszIter2 || *lpszIter2 == '\\'))
+ iLen = lpszIter1 - lpszFile1; /* Common to this point */
+
+ if (!*lpszIter1 || (tolower(*lpszIter1) != tolower(*lpszIter2)))
+ break; /* Strings differ at this point */
+
+ lpszIter1++;
+ lpszIter2++;
+ } while (1);
+
+ if (iLen == 2)
+ iLen++; /* Feature/Bug compatible with Win32 */
+
+ if (iLen && achPath)
+ {
+ memcpy(achPath,lpszFile1,iLen);
+ achPath[iLen] = '\0';
+ }
+ return iLen;
+}
+
+/*************************************************************************
+ * PathCommonPrefixW [SHLWAPI.@]
+ *
+ * See PathCommonPrefixA.
+ */
+int WINAPI PathCommonPrefixW(LPCWSTR lpszFile1, LPCWSTR lpszFile2, LPWSTR achPath)
+{
+ size_t iLen = 0;
+ LPCWSTR lpszIter1 = lpszFile1;
+ LPCWSTR lpszIter2 = lpszFile2;
+
+ TRACE("(%s,%s,%p)\n", debugstr_w(lpszFile1), debugstr_w(lpszFile2), achPath);
+
+ if (achPath)
+ *achPath = '\0';
+
+ if (!lpszFile1 || !lpszFile2)
+ return 0;
+
+ /* Handle roots first */
+ if (PathIsUNCW(lpszFile1))
+ {
+ if (!PathIsUNCW(lpszFile2))
+ return 0;
+ lpszIter1 += 2;
+ lpszIter2 += 2;
+ }
+ else if (PathIsUNCW(lpszFile2))
+ return 0; /* Know already lpszFile1 is not UNC */
+
+ do
+ {
+ /* Update len */
+ if ((!*lpszIter1 || *lpszIter1 == '\\') &&
+ (!*lpszIter2 || *lpszIter2 == '\\'))
+ iLen = lpszIter1 - lpszFile1; /* Common to this point */
+
+ if (!*lpszIter1 || (tolowerW(*lpszIter1) != tolowerW(*lpszIter2)))
+ break; /* Strings differ at this point */
+
+ lpszIter1++;
+ lpszIter2++;
+ } while (1);
+
+ if (iLen == 2)
+ iLen++; /* Feature/Bug compatible with Win32 */
+
+ if (iLen && achPath)
+ {
+ memcpy(achPath,lpszFile1,iLen * sizeof(WCHAR));
+ achPath[iLen] = '\0';
+ }
+ return iLen;
+}
+
+/*************************************************************************
+ * PathCompactPathA [SHLWAPI.@]
+ *
+ * Make a path fit into a given width when printed to a DC.
+ *
+ * PARAMS
+ * hDc [I] Destination DC
+ * lpszPath [I/O] Path to be printed to hDc
+ * dx [I] Desired width
+ *
+ * RETURNS
+ * TRUE If the path was modified/went well.
+ * FALSE Otherwise.
+ */
+BOOL WINAPI PathCompactPathA(HDC hDC, LPSTR lpszPath, UINT dx)
+{
+ BOOL bRet = FALSE;
+
+ TRACE("(%p,%s,%d)\n", hDC, debugstr_a(lpszPath), dx);
+
+ if (lpszPath)
+ {
+ WCHAR szPath[MAX_PATH];
+ MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
+ bRet = PathCompactPathW(hDC, szPath, dx);
+ WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0);
+ }
+ return bRet;
+}
+
+/*************************************************************************
+ * PathCompactPathW [SHLWAPI.@]
+ *
+ * See PathCompactPathA.
+ */
+BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR lpszPath, UINT dx)
+{
+ static const WCHAR szEllipses[] = { '.', '.', '.', '\0' };
+ BOOL bRet = TRUE;
+ HDC hdc = 0;
+ WCHAR buff[MAX_PATH];
+ SIZE size;
+ DWORD dwLen;
+
+ TRACE("(%p,%s,%d)\n", hDC, debugstr_w(lpszPath), dx);
+
+ if (!lpszPath)
+ return FALSE;
+
+ if (!hDC)
+ hdc = hDC = GetDC(0);
+
+ /* Get the length of the whole path */
+ dwLen = strlenW(lpszPath);
+ GetTextExtentPointW(hDC, lpszPath, dwLen, &size);
+
+ if ((UINT)size.cx > dx)
+ {
+ /* Path too big, must reduce it */
+ LPWSTR sFile;
+ DWORD dwEllipsesLen = 0, dwPathLen = 0;
+
+ sFile = PathFindFileNameW(lpszPath);
+ if (sFile != lpszPath) sFile--;
+
+ /* Get the size of ellipses */
+ GetTextExtentPointW(hDC, szEllipses, 3, &size);
+ dwEllipsesLen = size.cx;
+ /* Get the size of the file name */
+ GetTextExtentPointW(hDC, sFile, strlenW(sFile), &size);
+ dwPathLen = size.cx;
+
+ if (sFile != lpszPath)
+ {
+ LPWSTR sPath = sFile;
+ BOOL bEllipses = FALSE;
+
+ /* The path includes a file name. Include as much of the path prior to
+ * the file name as possible, allowing for the ellipses, e.g:
+ * c:\some very long path\filename ==> c:\some v...\filename
+ */
+ lstrcpynW(buff, sFile, MAX_PATH);
+
+ do
+ {
+ DWORD dwTotalLen = bEllipses? dwPathLen + dwEllipsesLen : dwPathLen;
+
+ GetTextExtentPointW(hDC, lpszPath, sPath - lpszPath, &size);
+ dwTotalLen += size.cx;
+ if (dwTotalLen <= dx)
+ break;
+ sPath--;
+ if (!bEllipses)
+ {
+ bEllipses = TRUE;
+ sPath -= 2;
+ }
+ } while (sPath > lpszPath);
+
+ if (sPath > lpszPath)
+ {
+ if (bEllipses)
+ {
+ strcpyW(sPath, szEllipses);
+ strcpyW(sPath+3, buff);
+ }
+ bRet = TRUE;
+ goto end;
+ }
+ strcpyW(lpszPath, szEllipses);
+ strcpyW(lpszPath+3, buff);
+ bRet = FALSE;
+ goto end;
+ }
+
+ /* Trim the path by adding ellipses to the end, e.g:
+ * A very long file name.txt ==> A very...
+ */
+ dwLen = strlenW(lpszPath);
+
+ if (dwLen > MAX_PATH - 3)
+ dwLen = MAX_PATH - 3;
+ lstrcpynW(buff, sFile, dwLen);
+
+ do {
+ dwLen--;
+ GetTextExtentPointW(hDC, buff, dwLen, &size);
+ } while (dwLen && size.cx + dwEllipsesLen > dx);
+
+ if (!dwLen)
+ {
+ DWORD dwWritten = 0;
+
+ dwEllipsesLen /= 3; /* Size of a single '.' */
+
+ /* Write as much of the Ellipses string as possible */
+ while (dwWritten + dwEllipsesLen < dx && dwLen < 3)
+ {
+ *lpszPath++ = '.';
+ dwWritten += dwEllipsesLen;
+ dwLen++;
+ }
+ *lpszPath = '\0';
+ bRet = FALSE;
+ }
+ else
+ {
+ strcpyW(buff + dwLen, szEllipses);
+ strcpyW(lpszPath, buff);
+ }
+ }
+
+end:
+ if (hdc)
+ ReleaseDC(0, hdc);
+
+ return bRet;
+}
+
+/*************************************************************************
+ * PathGetCharTypeA [SHLWAPI.@]
+ *
+ * Categorise a character from a file path.
+ *
+ * PARAMS
+ * ch [I] Character to get the type of
+ *
+ * RETURNS
+ * A set of GCT_ bit flags (from "shlwapi.h") indicating the character type.
+ */
+UINT WINAPI PathGetCharTypeA(UCHAR ch)
+{
+ return PathGetCharTypeW(ch);
+}
+
+/*************************************************************************
+ * PathGetCharTypeW [SHLWAPI.@]
+ *
+ * See PathGetCharTypeA.
+ */
+UINT WINAPI PathGetCharTypeW(WCHAR ch)
+{
+ UINT flags = 0;
+
+ TRACE("(%d)\n", ch);
+
+ if (!ch || ch < ' ' || ch == '<' || ch == '>' ||
+ ch == '"' || ch == '|' || ch == '/')
+ flags = GCT_INVALID; /* Invalid */
+ else if (ch == '*' || ch=='?')
+ flags = GCT_WILD; /* Wildchars */
+ else if ((ch == '\\') || (ch == ':'))
+ return GCT_SEPARATOR; /* Path separators */
+ else
+ {
+ if (ch < 126)
+ {
+ if (((ch & 0x1) && ch != ';') || !ch || isalnum(ch) || ch == '$' || ch == '&' || ch == '(' ||
+ ch == '.' || ch == '@' || ch == '^' ||
+ ch == '\'' || ch == 130 || ch == '`')
+ flags |= GCT_SHORTCHAR; /* All these are valid for DOS */
+ }
+ else
+ flags |= GCT_SHORTCHAR; /* Bug compatible with win32 */
+ flags |= GCT_LFNCHAR; /* Valid for long file names */
+ }
+ return flags;
+}
+
+/*************************************************************************
+ * SHLWAPI_UseSystemForSystemFolders
+ *
+ * Internal helper for PathMakeSystemFolderW.
+ */
+static BOOL SHLWAPI_UseSystemForSystemFolders(void)
+{
+ static BOOL bCheckedReg = FALSE;
+ static BOOL bUseSystemForSystemFolders = FALSE;
+
+ if (!bCheckedReg)
+ {
+ bCheckedReg = TRUE;
+
+ /* Key tells Win what file attributes to use on system folders */
+ if (SHGetValueA(HKEY_LOCAL_MACHINE,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
+ "UseSystemForSystemFolders", 0, 0, 0))
+ bUseSystemForSystemFolders = TRUE;
+ }
+ return bUseSystemForSystemFolders;
+}
+
+/*************************************************************************
+ * PathMakeSystemFolderA [SHLWAPI.@]
+ *
+ * Set system folder attribute for a path.
+ *
+ * PARAMS
+ * lpszPath [I] The path to turn into a system folder
+ *
+ * RETURNS
+ * TRUE If the path was changed to/already was a system folder
+ * FALSE If the path is invalid or SetFileAttributesA() fails
+ */
+BOOL WINAPI PathMakeSystemFolderA(LPCSTR lpszPath)
+{
+ BOOL bRet = FALSE;
+
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if (lpszPath && *lpszPath)
+ {
+ WCHAR szPath[MAX_PATH];
+ MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
+ bRet = PathMakeSystemFolderW(szPath);
+ }
+ return bRet;
+}
+
+/*************************************************************************
+ * PathMakeSystemFolderW [SHLWAPI.@]
+ *
+ * See PathMakeSystemFolderA.
+ */
+BOOL WINAPI PathMakeSystemFolderW(LPCWSTR lpszPath)
+{
+ DWORD dwDefaultAttr = FILE_ATTRIBUTE_READONLY, dwAttr;
+ WCHAR buff[MAX_PATH];
+
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if (!lpszPath || !*lpszPath)
+ return FALSE;
+
+ /* If the directory is already a system directory, don't do anything */
+ GetSystemDirectoryW(buff, MAX_PATH);
+ if (!strcmpW(buff, lpszPath))
+ return TRUE;
+
+ GetWindowsDirectoryW(buff, MAX_PATH);
+ if (!strcmpW(buff, lpszPath))
+ return TRUE;
+
+ /* "UseSystemForSystemFolders" Tells Win what attributes to use */
+ if (SHLWAPI_UseSystemForSystemFolders())
+ dwDefaultAttr = FILE_ATTRIBUTE_SYSTEM;
+
+ if ((dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES)
+ return FALSE;
+
+ /* Change file attributes to system attributes */
+ dwAttr &= ~(FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY);
+ return SetFileAttributesW(lpszPath, dwAttr | dwDefaultAttr);
+}
+
+/*************************************************************************
+ * PathRenameExtensionA [SHLWAPI.@]
+ *
+ * Swap the file extension in a path with another extension.
+ *
+ * PARAMS
+ * lpszPath [I/O] Path to swap the extension in
+ * lpszExt [I] The new extension
+ *
+ * RETURNS
+ * TRUE if lpszPath was modified,
+ * FALSE if lpszPath or lpszExt is NULL, or the new path is too long
+ */
+BOOL WINAPI PathRenameExtensionA(LPSTR lpszPath, LPCSTR lpszExt)
+{
+ LPSTR lpszExtension;
+
+ TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszExt));
+
+ lpszExtension = PathFindExtensionA(lpszPath);
+
+ if (!lpszExtension || (lpszExtension - lpszPath + strlen(lpszExt) >= MAX_PATH))
+ return FALSE;
+
+ strcpy(lpszExtension, lpszExt);
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathRenameExtensionW [SHLWAPI.@]
+ *
+ * See PathRenameExtensionA.
+ */
+BOOL WINAPI PathRenameExtensionW(LPWSTR lpszPath, LPCWSTR lpszExt)
+{
+ LPWSTR lpszExtension;
+
+ TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszExt));
+
+ lpszExtension = PathFindExtensionW(lpszPath);
+
+ if (!lpszExtension || (lpszExtension - lpszPath + strlenW(lpszExt) >= MAX_PATH))
+ return FALSE;
+
+ strcpyW(lpszExtension, lpszExt);
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathSearchAndQualifyA [SHLWAPI.@]
+ *
+ * Determine if a given path is correct and fully qualified.
+ *
+ * PARAMS
+ * lpszPath [I] Path to check
+ * lpszBuf [O] Output for correct path
+ * cchBuf [I] Size of lpszBuf
+ *
+ * RETURNS
+ * Unknown.
+ */
+BOOL WINAPI PathSearchAndQualifyA(LPCSTR lpszPath, LPSTR lpszBuf, UINT cchBuf)
+{
+ TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszPath), lpszBuf, cchBuf);
+
+ if(SearchPathA(NULL, lpszPath, NULL, cchBuf, lpszBuf, NULL))
+ return TRUE;
+ return !!GetFullPathNameA(lpszPath, cchBuf, lpszBuf, NULL);
+}
+
+/*************************************************************************
+ * PathSearchAndQualifyW [SHLWAPI.@]
+ *
+ * See PathSearchAndQualifyA.
+ */
+BOOL WINAPI PathSearchAndQualifyW(LPCWSTR lpszPath, LPWSTR lpszBuf, UINT cchBuf)
+{
+ TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszPath), lpszBuf, cchBuf);
+
+ if(SearchPathW(NULL, lpszPath, NULL, cchBuf, lpszBuf, NULL))
+ return TRUE;
+ return !!GetFullPathNameW(lpszPath, cchBuf, lpszBuf, NULL);
+}
+
+/*************************************************************************
+ * PathSkipRootA [SHLWAPI.@]
+ *
+ * Return the portion of a path following the drive letter or mount point.
+ *
+ * PARAMS
+ * lpszPath [I] The path to skip on
+ *
+ * RETURNS
+ * Success: A pointer to the next character after the root.
+ * Failure: NULL, if lpszPath is invalid, has no root or is a multibyte string.
+ */
+LPSTR WINAPI PathSkipRootA(LPCSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if (!lpszPath || !*lpszPath)
+ return NULL;
+
+ if (*lpszPath == '\\' && lpszPath[1] == '\\')
+ {
+ /* Network share: skip share server and mount point */
+ lpszPath += 2;
+ if ((lpszPath = StrChrA(lpszPath, '\\')) &&
+ (lpszPath = StrChrA(lpszPath + 1, '\\')))
+ lpszPath++;
+ return (LPSTR)lpszPath;
+ }
+
+ if (IsDBCSLeadByte(*lpszPath))
+ return NULL;
+
+ /* Check x:\ */
+ if (lpszPath[0] && lpszPath[1] == ':' && lpszPath[2] == '\\')
+ return (LPSTR)lpszPath + 3;
+ return NULL;
+}
+
+/*************************************************************************
+ * PathSkipRootW [SHLWAPI.@]
+ *
+ * See PathSkipRootA.
+ */
+LPWSTR WINAPI PathSkipRootW(LPCWSTR lpszPath)
+{
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if (!lpszPath || !*lpszPath)
+ return NULL;
+
+ if (*lpszPath == '\\' && lpszPath[1] == '\\')
+ {
+ /* Network share: skip share server and mount point */
+ lpszPath += 2;
+ if ((lpszPath = StrChrW(lpszPath, '\\')) &&
+ (lpszPath = StrChrW(lpszPath + 1, '\\')))
+ lpszPath++;
+ return (LPWSTR)lpszPath;
+ }
+
+ /* Check x:\ */
+ if (lpszPath[0] && lpszPath[1] == ':' && lpszPath[2] == '\\')
+ return (LPWSTR)lpszPath + 3;
+ return NULL;
+}
+
+/*************************************************************************
+ * PathCreateFromUrlA [SHLWAPI.@]
+ *
+ * See PathCreateFromUrlW
+ */
+HRESULT WINAPI PathCreateFromUrlA(LPCSTR pszUrl, LPSTR pszPath,
+ LPDWORD pcchPath, DWORD dwReserved)
+{
+ WCHAR bufW[MAX_PATH];
+ WCHAR *pathW = bufW;
+ UNICODE_STRING urlW;
+ HRESULT ret;
+ DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA;
+
+ if (!pszUrl || !pszPath || !pcchPath || !*pcchPath)
+ return E_INVALIDARG;
+
+ if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl))
+ return E_INVALIDARG;
+ if((ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved)) == E_POINTER) {
+ pathW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
+ ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved);
+ }
+ if(ret == S_OK) {
+ RtlUnicodeToMultiByteSize(&lenA, pathW, lenW * sizeof(WCHAR));
+ if(*pcchPath > lenA) {
+ RtlUnicodeToMultiByteN(pszPath, *pcchPath - 1, &lenA, pathW, lenW * sizeof(WCHAR));
+ pszPath[lenA] = 0;
+ *pcchPath = lenA;
+ } else {
+ *pcchPath = lenA + 1;
+ ret = E_POINTER;
+ }
+ }
+ if(pathW != bufW) HeapFree(GetProcessHeap(), 0, pathW);
+ RtlFreeUnicodeString(&urlW);
+ return ret;
+}
+
+/*************************************************************************
+ * PathCreateFromUrlW [SHLWAPI.@]
+ *
+ * Create a path from a URL
+ *
+ * PARAMS
+ * lpszUrl [I] URL to convert into a path
+ * lpszPath [O] Output buffer for the resulting Path
+ * pcchPath [I] Length of lpszPath
+ * dwFlags [I] Flags controlling the conversion
+ *
+ * RETURNS
+ * Success: S_OK. lpszPath contains the URL in path format,
+ * Failure: An HRESULT error code such as E_INVALIDARG.
+ */
+HRESULT WINAPI PathCreateFromUrlW(LPCWSTR pszUrl, LPWSTR pszPath,
+ LPDWORD pcchPath, DWORD dwReserved)
+{
+ static const WCHAR file_colon[] = { 'f','i','l','e',':',0 };
+ static const WCHAR localhost[] = { 'l','o','c','a','l','h','o','s','t',0 };
+ DWORD nslashes, unescape, len;
+ const WCHAR *src;
+ WCHAR *tpath, *dst;
+ HRESULT ret;
+
+ TRACE("(%s,%p,%p,0x%08x)\n", debugstr_w(pszUrl), pszPath, pcchPath, dwReserved);
+
+ if (!pszUrl || !pszPath || !pcchPath || !*pcchPath)
+ return E_INVALIDARG;
+
+ if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pszUrl, 5,
+ file_colon, 5) != CSTR_EQUAL)
+ return E_INVALIDARG;
+ pszUrl += 5;
+ ret = S_OK;
+
+ src = pszUrl;
+ nslashes = 0;
+ while (*src == '/' || *src == '\\') {
+ nslashes++;
+ src++;
+ }
+
+ /* We need a temporary buffer so we can compute what size to ask for.
+ * We know that the final string won't be longer than the current pszUrl
+ * plus at most two backslashes. All the other transformations make it
+ * shorter.
+ */
+ len = 2 + lstrlenW(pszUrl) + 1;
+ if (*pcchPath < len)
+ tpath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ else
+ tpath = pszPath;
+
+ len = 0;
+ dst = tpath;
+ unescape = 1;
+ switch (nslashes)
+ {
+ case 0:
+ /* 'file:' + escaped DOS path */
+ break;
+ case 1:
+ /* 'file:/' + escaped DOS path */
+ /* fall through */
+ case 3:
+ /* 'file:///' (implied localhost) + escaped DOS path */
+ if (!isalphaW(*src) || (src[1] != ':' && src[1] != '|'))
+ src -= 1;
+ break;
+ case 2:
+ if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, src, 9,
+ localhost, 9) == CSTR_EQUAL &&
+ (src[9] == '/' || src[9] == '\\'))
+ {
+ /* 'file://localhost/' + escaped DOS path */
+ src += 10;
+ }
+ else if (isalphaW(*src) && (src[1] == ':' || src[1] == '|'))
+ {
+ /* 'file://' + unescaped DOS path */
+ unescape = 0;
+ }
+ else
+ {
+ /* 'file://hostname:port/path' (where path is escaped)
+ * or 'file:' + escaped UNC path (\\server\share\path)
+ * The second form is clearly specific to Windows and it might
+ * even be doing a network lookup to try to figure it out.
+ */
+ while (*src && *src != '/' && *src != '\\')
+ src++;
+ len = src - pszUrl;
+ StrCpyNW(dst, pszUrl, len + 1);
+ dst += len;
+ if (isalphaW(src[1]) && (src[2] == ':' || src[2] == '|'))
+ {
+ /* 'Forget' to add a trailing '/', just like Windows */
+ src++;
+ }
+ }
+ break;
+ case 4:
+ /* 'file://' + unescaped UNC path (\\server\share\path) */
+ unescape = 0;
+ if (isalphaW(*src) && (src[1] == ':' || src[1] == '|'))
+ break;
+ /* fall through */
+ default:
+ /* 'file:/...' + escaped UNC path (\\server\share\path) */
+ src -= 2;
+ }
+
+ /* Copy the remainder of the path */
+ len += lstrlenW(src);
+ StrCpyW(dst, src);
+
+ /* First do the Windows-specific path conversions */
+ for (dst = tpath; *dst; dst++)
+ if (*dst == '/') *dst = '\\';
+ if (isalphaW(*tpath) && tpath[1] == '|')
+ tpath[1] = ':'; /* c| -> c: */
+
+ /* And only then unescape the path (i.e. escaped slashes are left as is) */
+ if (unescape)
+ {
+ ret = UrlUnescapeW(tpath, NULL, &len, URL_UNESCAPE_INPLACE);
+ if (ret == S_OK)
+ {
+ /* When working in-place UrlUnescapeW() does not set len */
+ len = lstrlenW(tpath);
+ }
+ }
+
+ if (*pcchPath < len + 1)
+ {
+ ret = E_POINTER;
+ *pcchPath = len + 1;
+ }
+ else
+ {
+ *pcchPath = len;
+ if (tpath != pszPath)
+ StrCpyW(pszPath, tpath);
+ }
+ if (tpath != pszPath)
+ HeapFree(GetProcessHeap(), 0, tpath);
+
+ TRACE("Returning (%u) %s\n", *pcchPath, debugstr_w(pszPath));
+ return ret;
+}
+
+/*************************************************************************
+ * PathCreateFromUrlAlloc [SHLWAPI.@]
+ */
+HRESULT WINAPI PathCreateFromUrlAlloc(LPCWSTR pszUrl, LPWSTR *pszPath,
+ DWORD dwReserved)
+{
+ WCHAR pathW[MAX_PATH];
+ DWORD size;
+ HRESULT hr;
+
+ size = MAX_PATH;
+ hr = PathCreateFromUrlW(pszUrl, pathW, &size, dwReserved);
+ if (SUCCEEDED(hr))
+ {
+ /* Yes, this is supposed to crash if pszPath is NULL */
+ *pszPath = StrDupW(pathW);
+ }
+ return hr;
+}
+
+/*************************************************************************
+ * PathRelativePathToA [SHLWAPI.@]
+ *
+ * Create a relative path from one path to another.
+ *
+ * PARAMS
+ * lpszPath [O] Destination for relative path
+ * lpszFrom [I] Source path
+ * dwAttrFrom [I] File attribute of source path
+ * lpszTo [I] Destination path
+ * dwAttrTo [I] File attributes of destination path
+ *
+ * RETURNS
+ * TRUE If a relative path can be formed. lpszPath contains the new path
+ * FALSE If the paths are not relative or any parameters are invalid
+ *
+ * NOTES
+ * lpszTo should be at least MAX_PATH in length.
+ *
+ * Calling this function with relative paths for lpszFrom or lpszTo may
+ * give erroneous results.
+ *
+ * The Win32 version of this function contains a bug where the lpszTo string
+ * may be referenced 1 byte beyond the end of the string. As a result random
+ * garbage may be written to the output path, depending on what lies beyond
+ * the last byte of the string. This bug occurs because of the behaviour of
+ * PathCommonPrefix() (see notes for that function), and no workaround seems
+ * possible with Win32.
+ *
+ * This bug has been fixed here, so for example the relative path from "\\"
+ * to "\\" is correctly determined as "." in this implementation.
+ */
+BOOL WINAPI PathRelativePathToA(LPSTR lpszPath, LPCSTR lpszFrom, DWORD dwAttrFrom,
+ LPCSTR lpszTo, DWORD dwAttrTo)
+{
+ BOOL bRet = FALSE;
+
+ TRACE("(%p,%s,0x%08x,%s,0x%08x)\n", lpszPath, debugstr_a(lpszFrom),
+ dwAttrFrom, debugstr_a(lpszTo), dwAttrTo);
+
+ if(lpszPath && lpszFrom && lpszTo)
+ {
+ WCHAR szPath[MAX_PATH];
+ WCHAR szFrom[MAX_PATH];
+ WCHAR szTo[MAX_PATH];
+ MultiByteToWideChar(CP_ACP,0,lpszFrom,-1,szFrom,MAX_PATH);
+ MultiByteToWideChar(CP_ACP,0,lpszTo,-1,szTo,MAX_PATH);
+ bRet = PathRelativePathToW(szPath,szFrom,dwAttrFrom,szTo,dwAttrTo);
+ WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0);
+ }
+ return bRet;
+}
+
+/*************************************************************************
+ * PathRelativePathToW [SHLWAPI.@]
+ *
+ * See PathRelativePathToA.
+ */
+BOOL WINAPI PathRelativePathToW(LPWSTR lpszPath, LPCWSTR lpszFrom, DWORD dwAttrFrom,
+ LPCWSTR lpszTo, DWORD dwAttrTo)
+{
+ static const WCHAR szPrevDirSlash[] = { '.', '.', '\\', '\0' };
+ static const WCHAR szPrevDir[] = { '.', '.', '\0' };
+ WCHAR szFrom[MAX_PATH];
+ WCHAR szTo[MAX_PATH];
+ DWORD dwLen;
+
+ TRACE("(%p,%s,0x%08x,%s,0x%08x)\n", lpszPath, debugstr_w(lpszFrom),
+ dwAttrFrom, debugstr_w(lpszTo), dwAttrTo);
+
+ if(!lpszPath || !lpszFrom || !lpszTo)
+ return FALSE;
+
+ *lpszPath = '\0';
+ lstrcpynW(szFrom, lpszFrom, MAX_PATH);
+ lstrcpynW(szTo, lpszTo, MAX_PATH);
+
+ if(!(dwAttrFrom & FILE_ATTRIBUTE_DIRECTORY))
+ PathRemoveFileSpecW(szFrom);
++ if(!(dwAttrTo & FILE_ATTRIBUTE_DIRECTORY))
+ PathRemoveFileSpecW(szTo);
+
+ /* Paths can only be relative if they have a common root */
+ if(!(dwLen = PathCommonPrefixW(szFrom, szTo, 0)))
+ return FALSE;
+
+ /* Strip off lpszFrom components to the root, by adding "..\" */
+ lpszFrom = szFrom + dwLen;
+ if (!*lpszFrom)
+ {
+ lpszPath[0] = '.';
+ lpszPath[1] = '\0';
+ }
+ if (*lpszFrom == '\\')
+ lpszFrom++;
+
+ while (*lpszFrom)
+ {
+ lpszFrom = PathFindNextComponentW(lpszFrom);
+ strcatW(lpszPath, *lpszFrom ? szPrevDirSlash : szPrevDir);
+ }
+
+ /* From the root add the components of lpszTo */
+ lpszTo += dwLen;
+ /* We check lpszTo[-1] to avoid skipping end of string. See the notes for
+ * this function.
+ */
+ if (*lpszTo && lpszTo[-1])
+ {
+ if (*lpszTo != '\\')
+ lpszTo--;
+ dwLen = strlenW(lpszPath);
+ if (dwLen + strlenW(lpszTo) >= MAX_PATH)
+ {
+ *lpszPath = '\0';
+ return FALSE;
+ }
+ strcpyW(lpszPath + dwLen, lpszTo);
+ }
+ return TRUE;
+}
+
+/*************************************************************************
+ * PathUnmakeSystemFolderA [SHLWAPI.@]
+ *
+ * Remove the system folder attributes from a path.
+ *
+ * PARAMS
+ * lpszPath [I] The path to remove attributes from
+ *
+ * RETURNS
+ * Success: TRUE.
+ * Failure: FALSE, if lpszPath is NULL, empty, not a directory, or calling
+ * SetFileAttributesA() fails.
+ */
+BOOL WINAPI PathUnmakeSystemFolderA(LPCSTR lpszPath)
+{
+ DWORD dwAttr;
+
+ TRACE("(%s)\n", debugstr_a(lpszPath));
+
+ if (!lpszPath || !*lpszPath || (dwAttr = GetFileAttributesA(lpszPath)) == INVALID_FILE_ATTRIBUTES ||
+ !(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
+ return FALSE;
+
+ dwAttr &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
+ return SetFileAttributesA(lpszPath, dwAttr);
+}
+
+/*************************************************************************
+ * PathUnmakeSystemFolderW [SHLWAPI.@]
+ *
+ * See PathUnmakeSystemFolderA.
+ */
+BOOL WINAPI PathUnmakeSystemFolderW(LPCWSTR lpszPath)
+{
+ DWORD dwAttr;
+
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if (!lpszPath || !*lpszPath || (dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES ||
+ !(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
+ return FALSE;
+
+ dwAttr &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
+ return SetFileAttributesW(lpszPath, dwAttr);
+}
+
+
+/*************************************************************************
+ * PathSetDlgItemPathA [SHLWAPI.@]
+ *
+ * Set the text of a dialog item to a path, shrinking the path to fit
+ * if it is too big for the item.
+ *
+ * PARAMS
+ * hDlg [I] Dialog handle
+ * id [I] ID of item in the dialog
+ * lpszPath [I] Path to set as the items text
+ *
+ * RETURNS
+ * Nothing.
+ *
+ * NOTES
+ * If lpszPath is NULL, a blank string ("") is set (i.e. The previous
+ * window text is erased).
+ */
+VOID WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR lpszPath)
+{
+ WCHAR szPath[MAX_PATH];
+
+ TRACE("(%p,%8x,%s)\n",hDlg, id, debugstr_a(lpszPath));
+
+ if (lpszPath)
+ MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
+ else
+ szPath[0] = '\0';
+ PathSetDlgItemPathW(hDlg, id, szPath);
+}
+
+/*************************************************************************
+ * PathSetDlgItemPathW [SHLWAPI.@]
+ *
+ * See PathSetDlgItemPathA.
+ */
+VOID WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR lpszPath)
+{
+ WCHAR path[MAX_PATH + 1];
+ HWND hwItem;
+ RECT rect;
+ HDC hdc;
+ HGDIOBJ hPrevObj;
+
+ TRACE("(%p,%8x,%s)\n",hDlg, id, debugstr_w(lpszPath));
+
+ if (!(hwItem = GetDlgItem(hDlg, id)))
+ return;
+
+ if (lpszPath)
+ lstrcpynW(path, lpszPath, sizeof(path) / sizeof(WCHAR));
+ else
+ path[0] = '\0';
+
+ GetClientRect(hwItem, &rect);
+ hdc = GetDC(hDlg);
+ hPrevObj = SelectObject(hdc, (HGDIOBJ)SendMessageW(hwItem,WM_GETFONT,0,0));
+
+ if (hPrevObj)
+ {
+ PathCompactPathW(hdc, path, rect.right);
+ SelectObject(hdc, hPrevObj);
+ }
+
+ ReleaseDC(hDlg, hdc);
+ SetWindowTextW(hwItem, path);
+}
+
+/*************************************************************************
+ * PathIsNetworkPathA [SHLWAPI.@]
+ *
+ * Determine if the given path is a network path.
+ *
+ * PARAMS
+ * lpszPath [I] Path to check
+ *
+ * RETURNS
+ * TRUE If lpszPath is a UNC share or mapped network drive, or
+ * FALSE If lpszPath is a local drive or cannot be determined
+ */
+BOOL WINAPI PathIsNetworkPathA(LPCSTR lpszPath)
+{
+ int dwDriveNum;
+
+ TRACE("(%s)\n",debugstr_a(lpszPath));
+
+ if (!lpszPath)
+ return FALSE;
+ if (*lpszPath == '\\' && lpszPath[1] == '\\')
+ return TRUE;
+ dwDriveNum = PathGetDriveNumberA(lpszPath);
+ if (dwDriveNum == -1)
+ return FALSE;
+ GET_FUNC(pIsNetDrive, shell32, (LPCSTR)66, FALSE); /* ord 66 = shell32.IsNetDrive */
+ return pIsNetDrive(dwDriveNum);
+}
+
+/*************************************************************************
+ * PathIsNetworkPathW [SHLWAPI.@]
+ *
+ * See PathIsNetworkPathA.
+ */
+BOOL WINAPI PathIsNetworkPathW(LPCWSTR lpszPath)
+{
+ int dwDriveNum;
+
+ TRACE("(%s)\n", debugstr_w(lpszPath));
+
+ if (!lpszPath)
+ return FALSE;
+ if (*lpszPath == '\\' && lpszPath[1] == '\\')
+ return TRUE;
+ dwDriveNum = PathGetDriveNumberW(lpszPath);
+ if (dwDriveNum == -1)
+ return FALSE;
+ GET_FUNC(pIsNetDrive, shell32, (LPCSTR)66, FALSE); /* ord 66 = shell32.IsNetDrive */
+ return pIsNetDrive(dwDriveNum);
+}
+
+/*************************************************************************
+ * PathIsLFNFileSpecA [SHLWAPI.@]
+ *
+ * Determine if the given path is a long file name
+ *
+ * PARAMS
+ * lpszPath [I] Path to check
+ *
+ * RETURNS
+ * TRUE If path is a long file name,
+ * FALSE If path is a valid DOS short file name
+ */
+BOOL WINAPI PathIsLFNFileSpecA(LPCSTR lpszPath)
+{
+ DWORD dwNameLen = 0, dwExtLen = 0;
+
+ TRACE("(%s)\n",debugstr_a(lpszPath));
+
+ if (!lpszPath)
+ return FALSE;
+
+ while (*lpszPath)
+ {
+ if (*lpszPath == ' ')
+ return TRUE; /* DOS names cannot have spaces */
+ if (*lpszPath == '.')
+ {
+ if (dwExtLen)
+ return TRUE; /* DOS names have only one dot */
+ dwExtLen = 1;
+ }
+ else if (dwExtLen)
+ {
+ dwExtLen++;
+ if (dwExtLen > 4)
+ return TRUE; /* DOS extensions are <= 3 chars*/
+ }
+ else
+ {
+ dwNameLen++;
+ if (dwNameLen > 8)
+ return TRUE; /* DOS names are <= 8 chars */
+ }
+ lpszPath += IsDBCSLeadByte(*lpszPath) ? 2 : 1;
+ }
+ return FALSE; /* Valid DOS path */
+}
+
+/*************************************************************************
+ * PathIsLFNFileSpecW [SHLWAPI.@]
+ *
+ * See PathIsLFNFileSpecA.
+ */
+BOOL WINAPI PathIsLFNFileSpecW(LPCWSTR lpszPath)
+{
+ DWORD dwNameLen = 0, dwExtLen = 0;
+
+ TRACE("(%s)\n",debugstr_w(lpszPath));
+
+ if (!lpszPath)
+ return FALSE;
+
+ while (*lpszPath)
+ {
+ if (*lpszPath == ' ')
+ return TRUE; /* DOS names cannot have spaces */
+ if (*lpszPath == '.')
+ {
+ if (dwExtLen)
+ return TRUE; /* DOS names have only one dot */
+ dwExtLen = 1;
+ }
+ else if (dwExtLen)
+ {
+ dwExtLen++;
+ if (dwExtLen > 4)
+ return TRUE; /* DOS extensions are <= 3 chars*/
+ }
+ else
+ {
+ dwNameLen++;
+ if (dwNameLen > 8)
+ return TRUE; /* DOS names are <= 8 chars */
+ }
+ lpszPath++;
+ }
+ return FALSE; /* Valid DOS path */
+}
+
+/*************************************************************************
+ * PathIsDirectoryEmptyA [SHLWAPI.@]
+ *
+ * Determine if a given directory is empty.
+ *
+ * PARAMS
+ * lpszPath [I] Directory to check
+ *
+ * RETURNS
+ * TRUE If the directory exists and contains no files,
+ * FALSE Otherwise
+ */
+BOOL WINAPI PathIsDirectoryEmptyA(LPCSTR lpszPath)
+{
+ BOOL bRet = FALSE;
+
+ TRACE("(%s)\n",debugstr_a(lpszPath));
+
+ if (lpszPath)
+ {
+ WCHAR szPath[MAX_PATH];
+ MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
+ bRet = PathIsDirectoryEmptyW(szPath);
+ }
+ return bRet;
+}
+
+/*************************************************************************
+ * PathIsDirectoryEmptyW [SHLWAPI.@]
+ *
+ * See PathIsDirectoryEmptyA.
+ */
+BOOL WINAPI PathIsDirectoryEmptyW(LPCWSTR lpszPath)
+{
+ static const WCHAR szAllFiles[] = { '*', '.', '*', '\0' };
+ WCHAR szSearch[MAX_PATH];
+ DWORD dwLen;
+ HANDLE hfind;
+ BOOL retVal = FALSE;
+ WIN32_FIND_DATAW find_data;
+
+ TRACE("(%s)\n",debugstr_w(lpszPath));
+
+ if (!lpszPath || !PathIsDirectoryW(lpszPath))
+ return FALSE;
+
+ lstrcpynW(szSearch, lpszPath, MAX_PATH);
+ PathAddBackslashW(szSearch);
+ dwLen = strlenW(szSearch);
+ if (dwLen > MAX_PATH - 4)
+ return FALSE;
+
+ strcpyW(szSearch + dwLen, szAllFiles);
+ hfind = FindFirstFileW(szSearch, &find_data);
+ if (hfind != INVALID_HANDLE_VALUE)
+ {
+ if (find_data.cFileName[0] == '.' && find_data.cFileName[1] == '.')
+ /* The only directory entry should be the parent */
+ retVal = !FindNextFileW(hfind, &find_data);
+ FindClose(hfind);
+ }
+
+ return retVal;
+}
+
+
+/*************************************************************************
+ * PathFindSuffixArrayA [SHLWAPI.@]
+ *
+ * Find a suffix string in an array of suffix strings
+ *
+ * PARAMS
+ * lpszSuffix [I] Suffix string to search for
+ * lppszArray [I] Array of suffix strings to search
+ * dwCount [I] Number of elements in lppszArray
+ *
+ * RETURNS
+ * Success: The index of the position of lpszSuffix in lppszArray
+ * Failure: 0, if any parameters are invalid or lpszSuffix is not found
+ *
+ * NOTES
+ * The search is case sensitive.
+ * The match is made against the end of the suffix string, so for example:
+ * lpszSuffix="fooBAR" matches "BAR", but lpszSuffix="fooBARfoo" does not.
+ */
+LPCSTR WINAPI PathFindSuffixArrayA(LPCSTR lpszSuffix, LPCSTR *lppszArray, int dwCount)
+{
+ size_t dwLen;
+ int dwRet = 0;
+
+ TRACE("(%s,%p,%d)\n",debugstr_a(lpszSuffix), lppszArray, dwCount);
+
+ if (lpszSuffix && lppszArray && dwCount > 0)
+ {
+ dwLen = strlen(lpszSuffix);
+
+ while (dwRet < dwCount)
+ {
+ size_t dwCompareLen = strlen(*lppszArray);
+ if (dwCompareLen < dwLen)
+ {
+ if (!strcmp(lpszSuffix + dwLen - dwCompareLen, *lppszArray))
+ return *lppszArray; /* Found */
+ }
+ dwRet++;
+ lppszArray++;
+ }
+ }
+ return NULL;
+}
+
+/*************************************************************************
+ * PathFindSuffixArrayW [SHLWAPI.@]
+ *
+ * See PathFindSuffixArrayA.
+ */
+LPCWSTR WINAPI PathFindSuffixArrayW(LPCWSTR lpszSuffix, LPCWSTR *lppszArray, int dwCount)
+{
+ size_t dwLen;
+ int dwRet = 0;
+
+ TRACE("(%s,%p,%d)\n",debugstr_w(lpszSuffix), lppszArray, dwCount);
+
+ if (lpszSuffix && lppszArray && dwCount > 0)
+ {
+ dwLen = strlenW(lpszSuffix);
+
+ while (dwRet < dwCount)
+ {
+ size_t dwCompareLen = strlenW(*lppszArray);
+ if (dwCompareLen < dwLen)
+ {
+ if (!strcmpW(lpszSuffix + dwLen - dwCompareLen, *lppszArray))
+ return *lppszArray; /* Found */
+ }
+ dwRet++;
+ lppszArray++;
+ }
+ }
+ return NULL;
+}
+
+/*************************************************************************
+ * PathUndecorateA [SHLWAPI.@]
+ *
+ * Undecorate a file path
+ *
+ * PARAMS
+ * lpszPath [I/O] Path to remove any decoration from
+ *
+ * RETURNS
+ * Nothing
+ *
+ * NOTES
+ * A decorations form is "path[n].ext" where "n" is an optional decimal number.
+ */
+VOID WINAPI PathUndecorateA(LPSTR lpszPath)
+{
+ TRACE("(%s)\n",debugstr_a(lpszPath));
+
+ if (lpszPath)
+ {
+ LPSTR lpszExt = PathFindExtensionA(lpszPath);
+ if (lpszExt > lpszPath && lpszExt[-1] == ']')
+ {
+ LPSTR lpszSkip = lpszExt - 2;
+ if (*lpszSkip == '[')
+ lpszSkip++; /* [] (no number) */
+ else
+ while (lpszSkip > lpszPath && isdigit(lpszSkip[-1]))
+ lpszSkip--;
+ if (lpszSkip > lpszPath && lpszSkip[-1] == '[' && lpszSkip[-2] != '\\')
+ {
+ /* remove the [n] */
+ lpszSkip--;
+ while (*lpszExt)
+ *lpszSkip++ = *lpszExt++;
+ *lpszSkip = '\0';
+ }
+ }
+ }
+}
+
+/*************************************************************************
+ * PathUndecorateW [SHLWAPI.@]
+ *
+ * See PathUndecorateA.
+ */
+VOID WINAPI PathUndecorateW(LPWSTR lpszPath)
+{
+ TRACE("(%s)\n",debugstr_w(lpszPath));
+
+ if (lpszPath)
+ {
+ LPWSTR lpszExt = PathFindExtensionW(lpszPath);
+ if (lpszExt > lpszPath && lpszExt[-1] == ']')
+ {
+ LPWSTR lpszSkip = lpszExt - 2;
+ if (*lpszSkip == '[')
+ lpszSkip++; /* [] (no number) */
+ else
+ while (lpszSkip > lpszPath && isdigitW(lpszSkip[-1]))
+ lpszSkip--;
+ if (lpszSkip > lpszPath && lpszSkip[-1] == '[' && lpszSkip[-2] != '\\')
+ {
+ /* remove the [n] */
+ lpszSkip--;
+ while (*lpszExt)
+ *lpszSkip++ = *lpszExt++;
+ *lpszSkip = '\0';
+ }
+ }
+ }
+}
+
+/*************************************************************************
+ * PathUnExpandEnvStringsA [SHLWAPI.@]
+ *
+ * Substitute folder names in a path with their corresponding environment
+ * strings.
+ *
+ * PARAMS
+ * path [I] Buffer containing the path to unexpand.
+ * buffer [O] Buffer to receive the unexpanded path.
+ * buf_len [I] Size of pszBuf in characters.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ */
+BOOL WINAPI PathUnExpandEnvStringsA(LPCSTR path, LPSTR buffer, UINT buf_len)
+{
+ WCHAR bufferW[MAX_PATH], *pathW;
+ DWORD len;
+ BOOL ret;
+
+ TRACE("(%s, %p, %d)\n", debugstr_a(path), buffer, buf_len);
+
+ pathW = heap_strdupAtoW(path);
+ if (!pathW) return FALSE;
+
+ ret = PathUnExpandEnvStringsW(pathW, bufferW, MAX_PATH);
+ HeapFree(GetProcessHeap(), 0, pathW);
+ if (!ret) return FALSE;
+
+ len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
+ if (buf_len < len + 1) return FALSE;
+
+ WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, buf_len, NULL, NULL);
+ return TRUE;
+}
+
+static const WCHAR allusersprofileW[] = {'%','A','L','L','U','S','E','R','S','P','R','O','F','I','L','E','%',0};
+static const WCHAR appdataW[] = {'%','A','P','P','D','A','T','A','%',0};
+static const WCHAR computernameW[] = {'%','C','O','M','P','U','T','E','R','N','A','M','E','%',0};
+static const WCHAR programfilesW[] = {'%','P','r','o','g','r','a','m','F','i','l','e','s','%',0};
+static const WCHAR systemrootW[] = {'%','S','y','s','t','e','m','R','o','o','t','%',0};
+static const WCHAR systemdriveW[] = {'%','S','y','s','t','e','m','D','r','i','v','e','%',0};
+static const WCHAR userprofileW[] = {'%','U','S','E','R','P','R','O','F','I','L','E','%',0};
+
+struct envvars_map
+{
+ const WCHAR *var;
+ UINT varlen;
+ WCHAR path[MAX_PATH];
+ DWORD len;
+};
+
+static void init_envvars_map(struct envvars_map *map)
+{
+ while (map->var)
+ {
+ map->len = ExpandEnvironmentStringsW(map->var, map->path, sizeof(map->path)/sizeof(WCHAR));
+ /* exclude null from length */
+ if (map->len) map->len--;
+ map++;
+ }
+}
+
+/*************************************************************************
+ * PathUnExpandEnvStringsW [SHLWAPI.@]
+ *
+ * Unicode version of PathUnExpandEnvStringsA.
+ */
+BOOL WINAPI PathUnExpandEnvStringsW(LPCWSTR path, LPWSTR buffer, UINT buf_len)
+{
+ static struct envvars_map null_var = {NULL, 0, {0}, 0};
+ struct envvars_map *match = &null_var, *cur;
+ struct envvars_map envvars[] = {
+ { allusersprofileW, sizeof(allusersprofileW)/sizeof(WCHAR) },
+ { appdataW, sizeof(appdataW)/sizeof(WCHAR) },
+ { computernameW, sizeof(computernameW)/sizeof(WCHAR) },
+ { programfilesW, sizeof(programfilesW)/sizeof(WCHAR) },
+ { systemrootW, sizeof(systemrootW)/sizeof(WCHAR) },
+ { systemdriveW, sizeof(systemdriveW)/sizeof(WCHAR) },
+ { userprofileW, sizeof(userprofileW)/sizeof(WCHAR) },
+ { NULL }
+ };
+ DWORD pathlen;
+ UINT needed;
+
+ TRACE("(%s, %p, %d)\n", debugstr_w(path), buffer, buf_len);
+
+ pathlen = strlenW(path);
+ init_envvars_map(envvars);
+ cur = envvars;
+ while (cur->var)
+ {
+ /* path can't contain expanded value or value wasn't retrieved */
+ if (cur->len == 0 || cur->len > pathlen || strncmpiW(cur->path, path, cur->len))
+ {
+ cur++;
+ continue;
+ }
+
+ if (cur->len > match->len)
+ match = cur;
+ cur++;
+ }
+
+ /* 'varlen' includes NULL termination char */
+ needed = match->varlen + pathlen - match->len;
+ if (match->len == 0 || needed > buf_len) return FALSE;
+
+ strcpyW(buffer, match->var);
+ strcatW(buffer, &path[match->len]);
+ TRACE("ret %s\n", debugstr_w(buffer));
+
+ return TRUE;
+}
+
+/*************************************************************************
+ * @ [SHLWAPI.440]
+ *
+ * Find localised or default web content in "%WINDOWS%\web\".
+ *
+ * PARAMS
+ * lpszFile [I] File name containing content to look for
+ * lpszPath [O] Buffer to contain the full path to the file
+ * dwPathLen [I] Length of lpszPath
+ *
+ * RETURNS
+ * Success: S_OK. lpszPath contains the full path to the content.
+ * Failure: E_FAIL. The content does not exist or lpszPath is too short.
+ */
+HRESULT WINAPI SHGetWebFolderFilePathA(LPCSTR lpszFile, LPSTR lpszPath, DWORD dwPathLen)
+{
+ WCHAR szFile[MAX_PATH], szPath[MAX_PATH];
+ HRESULT hRet;
+
+ TRACE("(%s,%p,%d)\n", lpszFile, lpszPath, dwPathLen);
+
+ MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, szFile, MAX_PATH);
+ szPath[0] = '\0';
+ hRet = SHGetWebFolderFilePathW(szFile, szPath, dwPathLen);
+ WideCharToMultiByte(CP_ACP, 0, szPath, -1, lpszPath, dwPathLen, 0, 0);
+ return hRet;
+}
+
+/*************************************************************************
+ * @ [SHLWAPI.441]
+ *
+ * Unicode version of SHGetWebFolderFilePathA.
+ */
+HRESULT WINAPI SHGetWebFolderFilePathW(LPCWSTR lpszFile, LPWSTR lpszPath, DWORD dwPathLen)
+{
+ static const WCHAR szWeb[] = {'\\','W','e','b','\\','\0'};
+ static const WCHAR szWebMui[] = {'m','u','i','\\','%','0','4','x','\\','\0'};
+#define szWebLen (sizeof(szWeb)/sizeof(WCHAR))
+#define szWebMuiLen ((sizeof(szWebMui)+1)/sizeof(WCHAR))
+ DWORD dwLen, dwFileLen;
+ LANGID lidSystem, lidUser;
+
+ TRACE("(%s,%p,%d)\n", debugstr_w(lpszFile), lpszPath, dwPathLen);
+
+ /* Get base directory for web content */
+ dwLen = GetSystemWindowsDirectoryW(lpszPath, dwPathLen);
+ if (dwLen > 0 && lpszPath[dwLen-1] == '\\')
+ dwLen--;
+
+ dwFileLen = strlenW(lpszFile);
+
+ if (dwLen + dwFileLen + szWebLen >= dwPathLen)
+ return E_FAIL; /* lpszPath too short */
+
+ strcpyW(lpszPath+dwLen, szWeb);
+ dwLen += szWebLen;
+ dwPathLen = dwPathLen - dwLen; /* Remaining space */
+
+ lidSystem = GetSystemDefaultUILanguage();
+ lidUser = GetUserDefaultUILanguage();
+
+ if (lidSystem != lidUser)
+ {
+ if (dwFileLen + szWebMuiLen < dwPathLen)
+ {
+ /* Use localised content in the users UI language if present */
+ wsprintfW(lpszPath + dwLen, szWebMui, lidUser);
+ strcpyW(lpszPath + dwLen + szWebMuiLen, lpszFile);
+ if (PathFileExistsW(lpszPath))
+ return S_OK;
+ }
+ }
+
+ /* Fall back to OS default installed content */
+ strcpyW(lpszPath + dwLen, lpszFile);
+ if (PathFileExistsW(lpszPath))
+ return S_OK;
+ return E_FAIL;
+}
+
+#define PATH_CHAR_CLASS_LETTER 0x00000001
+#define PATH_CHAR_CLASS_ASTERIX 0x00000002
+#define PATH_CHAR_CLASS_DOT 0x00000004
+#define PATH_CHAR_CLASS_BACKSLASH 0x00000008
+#define PATH_CHAR_CLASS_COLON 0x00000010
+#define PATH_CHAR_CLASS_SEMICOLON 0x00000020
+#define PATH_CHAR_CLASS_COMMA 0x00000040
+#define PATH_CHAR_CLASS_SPACE 0x00000080
+#define PATH_CHAR_CLASS_OTHER_VALID 0x00000100
+#define PATH_CHAR_CLASS_DOUBLEQUOTE 0x00000200
+
+#define PATH_CHAR_CLASS_INVALID 0x00000000
+#define PATH_CHAR_CLASS_ANY 0xffffffff
+
+static const DWORD SHELL_charclass[] =
+{
+ /* 0x00 */ PATH_CHAR_CLASS_INVALID, /* 0x01 */ PATH_CHAR_CLASS_INVALID,
+ /* 0x02 */ PATH_CHAR_CLASS_INVALID, /* 0x03 */ PATH_CHAR_CLASS_INVALID,
+ /* 0x04 */ PATH_CHAR_CLASS_INVALID, /* 0x05 */ PATH_CHAR_CLASS_INVALID,
+ /* 0x06 */ PATH_CHAR_CLASS_INVALID, /* 0x07 */ PATH_CHAR_CLASS_INVALID,
+ /* 0x08 */ PATH_CHAR_CLASS_INVALID, /* 0x09 */ PATH_CHAR_CLASS_INVALID,
+ /* 0x0a */ PATH_CHAR_CLASS_INVALID, /* 0x0b */ PATH_CHAR_CLASS_INVALID,
+ /* 0x0c */ PATH_CHAR_CLASS_INVALID, /* 0x0d */ PATH_CHAR_CLASS_INVALID,
+ /* 0x0e */ PATH_CHAR_CLASS_INVALID, /* 0x0f */ PATH_CHAR_CLASS_INVALID,
+ /* 0x10 */ PATH_CHAR_CLASS_INVALID, /* 0x11 */ PATH_CHAR_CLASS_INVALID,
+ /* 0x12 */ PATH_CHAR_CLASS_INVALID, /* 0x13 */ PATH_CHAR_CLASS_INVALID,
+ /* 0x14 */ PATH_CHAR_CLASS_INVALID, /* 0x15 */ PATH_CHAR_CLASS_INVALID,
+ /* 0x16 */ PATH_CHAR_CLASS_INVALID, /* 0x17 */ PATH_CHAR_CLASS_INVALID,
+ /* 0x18 */ PATH_CHAR_CLASS_INVALID, /* 0x19 */ PATH_CHAR_CLASS_INVALID,
+ /* 0x1a */ PATH_CHAR_CLASS_INVALID, /* 0x1b */ PATH_CHAR_CLASS_INVALID,
+ /* 0x1c */ PATH_CHAR_CLASS_INVALID, /* 0x1d */ PATH_CHAR_CLASS_INVALID,
+ /* 0x1e */ PATH_CHAR_CLASS_INVALID, /* 0x1f */ PATH_CHAR_CLASS_INVALID,
+ /* ' ' */ PATH_CHAR_CLASS_SPACE, /* '!' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* '"' */ PATH_CHAR_CLASS_DOUBLEQUOTE, /* '#' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* '$' */ PATH_CHAR_CLASS_OTHER_VALID, /* '%' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* '&' */ PATH_CHAR_CLASS_OTHER_VALID, /* '\'' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* '(' */ PATH_CHAR_CLASS_OTHER_VALID, /* ')' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* '*' */ PATH_CHAR_CLASS_ASTERIX, /* '+' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* ',' */ PATH_CHAR_CLASS_COMMA, /* '-' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* '.' */ PATH_CHAR_CLASS_DOT, /* '/' */ PATH_CHAR_CLASS_INVALID,
+ /* '0' */ PATH_CHAR_CLASS_OTHER_VALID, /* '1' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* '2' */ PATH_CHAR_CLASS_OTHER_VALID, /* '3' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* '4' */ PATH_CHAR_CLASS_OTHER_VALID, /* '5' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* '6' */ PATH_CHAR_CLASS_OTHER_VALID, /* '7' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* '8' */ PATH_CHAR_CLASS_OTHER_VALID, /* '9' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* ':' */ PATH_CHAR_CLASS_COLON, /* ';' */ PATH_CHAR_CLASS_SEMICOLON,
+ /* '<' */ PATH_CHAR_CLASS_INVALID, /* '=' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* '>' */ PATH_CHAR_CLASS_INVALID, /* '?' */ PATH_CHAR_CLASS_LETTER,
+ /* '@' */ PATH_CHAR_CLASS_OTHER_VALID, /* 'A' */ PATH_CHAR_CLASS_ANY,
+ /* 'B' */ PATH_CHAR_CLASS_ANY, /* 'C' */ PATH_CHAR_CLASS_ANY,
+ /* 'D' */ PATH_CHAR_CLASS_ANY, /* 'E' */ PATH_CHAR_CLASS_ANY,
+ /* 'F' */ PATH_CHAR_CLASS_ANY, /* 'G' */ PATH_CHAR_CLASS_ANY,
+ /* 'H' */ PATH_CHAR_CLASS_ANY, /* 'I' */ PATH_CHAR_CLASS_ANY,
+ /* 'J' */ PATH_CHAR_CLASS_ANY, /* 'K' */ PATH_CHAR_CLASS_ANY,
+ /* 'L' */ PATH_CHAR_CLASS_ANY, /* 'M' */ PATH_CHAR_CLASS_ANY,
+ /* 'N' */ PATH_CHAR_CLASS_ANY, /* 'O' */ PATH_CHAR_CLASS_ANY,
+ /* 'P' */ PATH_CHAR_CLASS_ANY, /* 'Q' */ PATH_CHAR_CLASS_ANY,
+ /* 'R' */ PATH_CHAR_CLASS_ANY, /* 'S' */ PATH_CHAR_CLASS_ANY,
+ /* 'T' */ PATH_CHAR_CLASS_ANY, /* 'U' */ PATH_CHAR_CLASS_ANY,
+ /* 'V' */ PATH_CHAR_CLASS_ANY, /* 'W' */ PATH_CHAR_CLASS_ANY,
+ /* 'X' */ PATH_CHAR_CLASS_ANY, /* 'Y' */ PATH_CHAR_CLASS_ANY,
+ /* 'Z' */ PATH_CHAR_CLASS_ANY, /* '[' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* '\\' */ PATH_CHAR_CLASS_BACKSLASH, /* ']' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* '^' */ PATH_CHAR_CLASS_OTHER_VALID, /* '_' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* '`' */ PATH_CHAR_CLASS_OTHER_VALID, /* 'a' */ PATH_CHAR_CLASS_ANY,
+ /* 'b' */ PATH_CHAR_CLASS_ANY, /* 'c' */ PATH_CHAR_CLASS_ANY,
+ /* 'd' */ PATH_CHAR_CLASS_ANY, /* 'e' */ PATH_CHAR_CLASS_ANY,
+ /* 'f' */ PATH_CHAR_CLASS_ANY, /* 'g' */ PATH_CHAR_CLASS_ANY,
+ /* 'h' */ PATH_CHAR_CLASS_ANY, /* 'i' */ PATH_CHAR_CLASS_ANY,
+ /* 'j' */ PATH_CHAR_CLASS_ANY, /* 'k' */ PATH_CHAR_CLASS_ANY,
+ /* 'l' */ PATH_CHAR_CLASS_ANY, /* 'm' */ PATH_CHAR_CLASS_ANY,
+ /* 'n' */ PATH_CHAR_CLASS_ANY, /* 'o' */ PATH_CHAR_CLASS_ANY,
+ /* 'p' */ PATH_CHAR_CLASS_ANY, /* 'q' */ PATH_CHAR_CLASS_ANY,
+ /* 'r' */ PATH_CHAR_CLASS_ANY, /* 's' */ PATH_CHAR_CLASS_ANY,
+ /* 't' */ PATH_CHAR_CLASS_ANY, /* 'u' */ PATH_CHAR_CLASS_ANY,
+ /* 'v' */ PATH_CHAR_CLASS_ANY, /* 'w' */ PATH_CHAR_CLASS_ANY,
+ /* 'x' */ PATH_CHAR_CLASS_ANY, /* 'y' */ PATH_CHAR_CLASS_ANY,
+ /* 'z' */ PATH_CHAR_CLASS_ANY, /* '{' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* '|' */ PATH_CHAR_CLASS_INVALID, /* '}' */ PATH_CHAR_CLASS_OTHER_VALID,
+ /* '~' */ PATH_CHAR_CLASS_OTHER_VALID
+};
+
+/*************************************************************************
+ * @ [SHLWAPI.455]
+ *
+ * Check if an ASCII char is of a certain class
+ */
+BOOL WINAPI PathIsValidCharA( char c, DWORD class )
+{
+ if ((unsigned)c > 0x7e)
+ return class & PATH_CHAR_CLASS_OTHER_VALID;
+
+ return class & SHELL_charclass[(unsigned)c];
+}
+
+/*************************************************************************
+ * @ [SHLWAPI.456]
+ *
+ * Check if a Unicode char is of a certain class
+ */
+BOOL WINAPI PathIsValidCharW( WCHAR c, DWORD class )
+{
+ if (c > 0x7e)
+ return class & PATH_CHAR_CLASS_OTHER_VALID;
+
+ return class & SHELL_charclass[c];
+}
--- /dev/null
- _In_ PUNICODE_STRING SectionName,
+/*++ NDK Version: 0098
+
+Copyright (c) Alex Ionescu. All rights reserved.
+
+Header Name:
+
+ rtlfuncs.h
+
+Abstract:
+
+ Function definitions for the Run-Time Library
+
+Author:
+
+ Alex Ionescu (alexi@tinykrnl.org) - Updated - 27-Feb-2006
+
+--*/
+
+#ifndef _RTLFUNCS_H
+#define _RTLFUNCS_H
+
+//
+// Dependencies
+//
+#include <umtypes.h>
+#include <ntnls.h>
+#include <rtltypes.h>
+#include <pstypes.h>
+#include <extypes.h>
+#include "in6addr.h"
+#include "inaddr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef NTOS_MODE_USER
+
+//
+// List Functions
+//
+FORCEINLINE
+VOID
+InitializeListHead(
+ _Out_ PLIST_ENTRY ListHead
+)
+{
+ ListHead->Flink = ListHead->Blink = ListHead;
+}
+
+FORCEINLINE
+VOID
+InsertHeadList(
+ _Inout_ PLIST_ENTRY ListHead,
+ _Inout_ PLIST_ENTRY Entry
+)
+{
+ PLIST_ENTRY OldFlink;
+ OldFlink = ListHead->Flink;
+ Entry->Flink = OldFlink;
+ Entry->Blink = ListHead;
+ OldFlink->Blink = Entry;
+ ListHead->Flink = Entry;
+}
+
+FORCEINLINE
+VOID
+InsertTailList(
+ _Inout_ PLIST_ENTRY ListHead,
+ _Inout_ PLIST_ENTRY Entry
+)
+{
+ PLIST_ENTRY OldBlink;
+ OldBlink = ListHead->Blink;
+ Entry->Flink = ListHead;
+ Entry->Blink = OldBlink;
+ OldBlink->Flink = Entry;
+ ListHead->Blink = Entry;
+}
+
+_Must_inspect_result_
+FORCEINLINE
+BOOLEAN
+IsListEmpty(
+ _In_ const LIST_ENTRY * ListHead
+)
+{
+ return (BOOLEAN)(ListHead->Flink == ListHead);
+}
+
+FORCEINLINE
+PSINGLE_LIST_ENTRY
+PopEntryList(
+ _Inout_ PSINGLE_LIST_ENTRY ListHead
+)
+{
+ PSINGLE_LIST_ENTRY FirstEntry;
+ FirstEntry = ListHead->Next;
+ if (FirstEntry != NULL) {
+ ListHead->Next = FirstEntry->Next;
+ }
+
+ return FirstEntry;
+}
+
+FORCEINLINE
+VOID
+PushEntryList(
+ _Inout_ PSINGLE_LIST_ENTRY ListHead,
+ _Inout_ PSINGLE_LIST_ENTRY Entry
+)
+{
+ Entry->Next = ListHead->Next;
+ ListHead->Next = Entry;
+}
+
+FORCEINLINE
+BOOLEAN
+RemoveEntryList(
+ _In_ PLIST_ENTRY Entry)
+{
+ PLIST_ENTRY OldFlink;
+ PLIST_ENTRY OldBlink;
+
+ OldFlink = Entry->Flink;
+ OldBlink = Entry->Blink;
+ OldFlink->Blink = OldBlink;
+ OldBlink->Flink = OldFlink;
+ return (BOOLEAN)(OldFlink == OldBlink);
+}
+
+FORCEINLINE
+PLIST_ENTRY
+RemoveHeadList(
+ _Inout_ PLIST_ENTRY ListHead)
+{
+ PLIST_ENTRY Flink;
+ PLIST_ENTRY Entry;
+
+ Entry = ListHead->Flink;
+ Flink = Entry->Flink;
+ ListHead->Flink = Flink;
+ Flink->Blink = ListHead;
+ return Entry;
+}
+
+FORCEINLINE
+PLIST_ENTRY
+RemoveTailList(
+ _Inout_ PLIST_ENTRY ListHead)
+{
+ PLIST_ENTRY Blink;
+ PLIST_ENTRY Entry;
+
+ Entry = ListHead->Blink;
+ Blink = Entry->Blink;
+ ListHead->Blink = Blink;
+ Blink->Flink = ListHead;
+ return Entry;
+}
+
+//
+// Unicode string macros
+//
+_At_(UnicodeString->Buffer, _Post_equal_to_(Buffer))
+_At_(UnicodeString->Length, _Post_equal_to_(0))
+_At_(UnicodeString->MaximumLength, _Post_equal_to_(BufferSize))
+FORCEINLINE
+VOID
+RtlInitEmptyUnicodeString(
+ _Out_ PUNICODE_STRING UnicodeString,
+ _When_(BufferSize != 0, _Notnull_) _Writable_bytes_(BufferSize) __drv_aliasesMem PWCHAR Buffer,
+ _In_ USHORT BufferSize)
+{
+ UnicodeString->Length = 0;
+ UnicodeString->MaximumLength = BufferSize;
+ UnicodeString->Buffer = Buffer;
+}
+
+_At_(AnsiString->Buffer, _Post_equal_to_(Buffer))
+_At_(AnsiString->Length, _Post_equal_to_(0))
+_At_(AnsiString->MaximumLength, _Post_equal_to_(BufferSize))
+FORCEINLINE
+VOID
+RtlInitEmptyAnsiString(
+ _Out_ PANSI_STRING AnsiString,
+ _When_(BufferSize != 0, _Notnull_) _Writable_bytes_(BufferSize) __drv_aliasesMem PCHAR Buffer,
+ _In_ USHORT BufferSize)
+{
+ AnsiString->Length = 0;
+ AnsiString->MaximumLength = BufferSize;
+ AnsiString->Buffer = Buffer;
+}
+
+//
+// LUID Macros
+//
+#define RtlEqualLuid(L1, L2) (((L1)->HighPart == (L2)->HighPart) && \
+ ((L1)->LowPart == (L2)->LowPart))
+FORCEINLINE
+LUID
+NTAPI_INLINE
+RtlConvertUlongToLuid(
+ _In_ ULONG Ulong)
+{
+ LUID TempLuid;
+
+ TempLuid.LowPart = Ulong;
+ TempLuid.HighPart = 0;
+ return TempLuid;
+}
+
+//
+// ASSERT Macros
+//
+#ifndef ASSERT
+#if DBG
+
+#define ASSERT( exp ) \
+ ((void)((!(exp)) ? \
+ (RtlAssert( (PVOID)#exp, (PVOID)__FILE__, __LINE__, NULL ),FALSE) : \
+ TRUE))
+
+#define ASSERTMSG( msg, exp ) \
+ ((void)((!(exp)) ? \
+ (RtlAssert( (PVOID)#exp, (PVOID)__FILE__, __LINE__, (PCHAR)msg ),FALSE) : \
+ TRUE))
+
+#else
+
+#define ASSERT( exp ) ((void) 0)
+#define ASSERTMSG( msg, exp ) ((void) 0)
+
+#endif
+#endif
+
+#ifdef NTOS_KERNEL_RUNTIME
+
+//
+// Executing RTL functions at DISPATCH_LEVEL or higher will result in a
+// bugcheck.
+//
+#define RTL_PAGED_CODE PAGED_CODE
+
+#else
+
+//
+// This macro does nothing in user mode
+//
+#define RTL_PAGED_CODE NOP_FUNCTION
+
+#endif
+
+//
+// RTL Splay Tree Functions
+//
+#ifndef RTL_USE_AVL_TABLES
+
+NTSYSAPI
+VOID
+NTAPI
+RtlInitializeGenericTable(
+ _Out_ PRTL_GENERIC_TABLE Table,
+ _In_ PRTL_GENERIC_COMPARE_ROUTINE CompareRoutine,
+ _In_opt_ PRTL_GENERIC_ALLOCATE_ROUTINE AllocateRoutine,
+ _In_opt_ PRTL_GENERIC_FREE_ROUTINE FreeRoutine,
+ _In_opt_ PVOID TableContext
+);
+
+NTSYSAPI
+PVOID
+NTAPI
+RtlInsertElementGenericTable(
+ _In_ PRTL_GENERIC_TABLE Table,
+ _In_reads_bytes_(BufferSize) PVOID Buffer,
+ _In_ CLONG BufferSize,
+ _Out_opt_ PBOOLEAN NewElement
+);
+
+NTSYSAPI
+PVOID
+NTAPI
+RtlInsertElementGenericTableFull(
+ _In_ PRTL_GENERIC_TABLE Table,
+ _In_reads_bytes_(BufferSize) PVOID Buffer,
+ _In_ CLONG BufferSize,
+ _Out_opt_ PBOOLEAN NewElement,
+ _In_ PVOID NodeOrParent,
+ _In_ TABLE_SEARCH_RESULT SearchResult
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlDeleteElementGenericTable(
+ _In_ PRTL_GENERIC_TABLE Table,
+ _In_ PVOID Buffer
+);
+
+_Must_inspect_result_
+NTSYSAPI
+PVOID
+NTAPI
+RtlLookupElementGenericTable(
+ _In_ PRTL_GENERIC_TABLE Table,
+ _In_ PVOID Buffer
+);
+
+NTSYSAPI
+PVOID
+NTAPI
+RtlLookupElementGenericTableFull(
+ _In_ PRTL_GENERIC_TABLE Table,
+ _In_ PVOID Buffer,
+ _Out_ PVOID *NodeOrParent,
+ _Out_ TABLE_SEARCH_RESULT *SearchResult
+);
+
+_Must_inspect_result_
+NTSYSAPI
+PVOID
+NTAPI
+RtlEnumerateGenericTable(
+ _In_ PRTL_GENERIC_TABLE Table,
+ _In_ BOOLEAN Restart
+);
+
+_Must_inspect_result_
+NTSYSAPI
+PVOID
+NTAPI
+RtlEnumerateGenericTableWithoutSplaying(
+ _In_ PRTL_GENERIC_TABLE Table,
+ _Inout_ PVOID *RestartKey
+);
+
+_Must_inspect_result_
+NTSYSAPI
+PVOID
+NTAPI
+RtlGetElementGenericTable(
+ _In_ PRTL_GENERIC_TABLE Table,
+ _In_ ULONG I
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlNumberGenericTableElements(
+ _In_ PRTL_GENERIC_TABLE Table
+);
+
+_Must_inspect_result_
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlIsGenericTableEmpty(
+ _In_ PRTL_GENERIC_TABLE Table
+);
+
+#endif /* !RTL_USE_AVL_TABLES */
+
+NTSYSAPI
+PRTL_SPLAY_LINKS
+NTAPI
+RtlSplay(
+ _Inout_ PRTL_SPLAY_LINKS Links
+);
+
+NTSYSAPI
+PRTL_SPLAY_LINKS
+NTAPI
+RtlDelete(
+ _In_ PRTL_SPLAY_LINKS Links
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlDeleteNoSplay(
+ _In_ PRTL_SPLAY_LINKS Links,
+ _Inout_ PRTL_SPLAY_LINKS *Root
+);
+
+_Must_inspect_result_
+NTSYSAPI
+PRTL_SPLAY_LINKS
+NTAPI
+RtlSubtreeSuccessor(
+ _In_ PRTL_SPLAY_LINKS Links
+);
+
+_Must_inspect_result_
+NTSYSAPI
+PRTL_SPLAY_LINKS
+NTAPI
+RtlSubtreePredecessor(
+ _In_ PRTL_SPLAY_LINKS Links
+);
+
+_Must_inspect_result_
+NTSYSAPI
+PRTL_SPLAY_LINKS
+NTAPI
+RtlRealSuccessor(
+ _In_ PRTL_SPLAY_LINKS Links
+);
+
+_Must_inspect_result_
+NTSYSAPI
+PRTL_SPLAY_LINKS
+NTAPI
+RtlRealPredecessor(
+ _In_ PRTL_SPLAY_LINKS Links
+);
+
+#define RtlIsLeftChild(Links) \
+ (RtlLeftChild(RtlParent(Links)) == (PRTL_SPLAY_LINKS)(Links))
+
+#define RtlIsRightChild(Links) \
+ (RtlRightChild(RtlParent(Links)) == (PRTL_SPLAY_LINKS)(Links))
+
+#define RtlRightChild(Links) \
+ ((PRTL_SPLAY_LINKS)(Links))->RightChild
+
+#define RtlIsRoot(Links) \
+ (RtlParent(Links) == (PRTL_SPLAY_LINKS)(Links))
+
+#define RtlLeftChild(Links) \
+ ((PRTL_SPLAY_LINKS)(Links))->LeftChild
+
+#define RtlParent(Links) \
+ ((PRTL_SPLAY_LINKS)(Links))->Parent
+
+// FIXME: use inline function
+
+#define RtlInitializeSplayLinks(Links) \
+ { \
+ PRTL_SPLAY_LINKS _SplayLinks; \
+ _SplayLinks = (PRTL_SPLAY_LINKS)(Links); \
+ _SplayLinks->Parent = _SplayLinks; \
+ _SplayLinks->LeftChild = NULL; \
+ _SplayLinks->RightChild = NULL; \
+ }
+
+#define RtlInsertAsLeftChild(ParentLinks,ChildLinks) \
+ { \
+ PRTL_SPLAY_LINKS _SplayParent; \
+ PRTL_SPLAY_LINKS _SplayChild; \
+ _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \
+ _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \
+ _SplayParent->LeftChild = _SplayChild; \
+ _SplayChild->Parent = _SplayParent; \
+ }
+
+#define RtlInsertAsRightChild(ParentLinks,ChildLinks) \
+ { \
+ PRTL_SPLAY_LINKS _SplayParent; \
+ PRTL_SPLAY_LINKS _SplayChild; \
+ _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \
+ _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \
+ _SplayParent->RightChild = _SplayChild; \
+ _SplayChild->Parent = _SplayParent; \
+ }
+
+//
+// RTL AVL Tree Functions
+//
+NTSYSAPI
+VOID
+NTAPI
+RtlInitializeGenericTableAvl(
+ _Out_ PRTL_AVL_TABLE Table,
+ _In_ PRTL_AVL_COMPARE_ROUTINE CompareRoutine,
+ _In_opt_ PRTL_AVL_ALLOCATE_ROUTINE AllocateRoutine,
+ _In_opt_ PRTL_AVL_FREE_ROUTINE FreeRoutine,
+ _In_opt_ PVOID TableContext
+);
+
+NTSYSAPI
+PVOID
+NTAPI
+RtlInsertElementGenericTableAvl(
+ _In_ PRTL_AVL_TABLE Table,
+ _In_reads_bytes_(BufferSize) PVOID Buffer,
+ _In_ CLONG BufferSize,
+ _Out_opt_ PBOOLEAN NewElement
+);
+
+NTSYSAPI
+PVOID
+NTAPI
+RtlInsertElementGenericTableFullAvl(
+ _In_ PRTL_AVL_TABLE Table,
+ _In_reads_bytes_(BufferSize) PVOID Buffer,
+ _In_ CLONG BufferSize,
+ _Out_opt_ PBOOLEAN NewElement,
+ _In_ PVOID NodeOrParent,
+ _In_ TABLE_SEARCH_RESULT SearchResult
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlDeleteElementGenericTableAvl(
+ _In_ PRTL_AVL_TABLE Table,
+ _In_ PVOID Buffer
+);
+
+_Must_inspect_result_
+NTSYSAPI
+PVOID
+NTAPI
+RtlLookupElementGenericTableAvl(
+ _In_ PRTL_AVL_TABLE Table,
+ _In_ PVOID Buffer
+);
+
+NTSYSAPI
+PVOID
+NTAPI
+RtlLookupElementGenericTableFullAvl(
+ _In_ PRTL_AVL_TABLE Table,
+ _In_ PVOID Buffer,
+ _Out_ PVOID *NodeOrParent,
+ _Out_ TABLE_SEARCH_RESULT *SearchResult
+);
+
+_Must_inspect_result_
+NTSYSAPI
+PVOID
+NTAPI
+RtlEnumerateGenericTableAvl(
+ _In_ PRTL_AVL_TABLE Table,
+ _In_ BOOLEAN Restart
+);
+
+_Must_inspect_result_
+NTSYSAPI
+PVOID
+NTAPI
+RtlEnumerateGenericTableWithoutSplayingAvl(
+ _In_ PRTL_AVL_TABLE Table,
+ _Inout_ PVOID *RestartKey
+);
+
+_Must_inspect_result_
+NTSYSAPI
+PVOID
+NTAPI
+RtlLookupFirstMatchingElementGenericTableAvl(
+ _In_ PRTL_AVL_TABLE Table,
+ _In_ PVOID Buffer,
+ _Out_ PVOID *RestartKey
+);
+
+_Must_inspect_result_
+NTSYSAPI
+PVOID
+NTAPI
+RtlEnumerateGenericTableLikeADirectory(
+ _In_ PRTL_AVL_TABLE Table,
+ _In_opt_ PRTL_AVL_MATCH_FUNCTION MatchFunction,
+ _In_opt_ PVOID MatchData,
+ _In_ ULONG NextFlag,
+ _Inout_ PVOID *RestartKey,
+ _Inout_ PULONG DeleteCount,
+ _In_ PVOID Buffer
+);
+
+_Must_inspect_result_
+NTSYSAPI
+PVOID
+NTAPI
+RtlGetElementGenericTableAvl(
+ _In_ PRTL_AVL_TABLE Table,
+ _In_ ULONG I
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlNumberGenericTableElementsAvl(
+ _In_ PRTL_AVL_TABLE Table
+);
+
+_Must_inspect_result_
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlIsGenericTableEmptyAvl(
+ _In_ PRTL_AVL_TABLE Table
+);
+
+#ifdef RTL_USE_AVL_TABLES
+
+#define RtlInitializeGenericTable RtlInitializeGenericTableAvl
+#define RtlInsertElementGenericTable RtlInsertElementGenericTableAvl
+#define RtlInsertElementGenericTableFull RtlInsertElementGenericTableFullAvl
+#define RtlDeleteElementGenericTable RtlDeleteElementGenericTableAvl
+#define RtlLookupElementGenericTable RtlLookupElementGenericTableAvl
+#define RtlLookupElementGenericTableFull RtlLookupElementGenericTableFullAvl
+#define RtlEnumerateGenericTable RtlEnumerateGenericTableAvl
+#define RtlEnumerateGenericTableWithoutSplaying RtlEnumerateGenericTableWithoutSplayingAvl
+#define RtlGetElementGenericTable RtlGetElementGenericTableAvl
+#define RtlNumberGenericTableElements RtlNumberGenericTableElementsAvl
+#define RtlIsGenericTableEmpty RtlIsGenericTableEmptyAvl
+
+#endif /* RTL_USE_AVL_TABLES */
+
+//
+// Error and Exception Functions
+//
+NTSYSAPI
+PVOID
+NTAPI
+RtlAddVectoredExceptionHandler(
+ _In_ ULONG FirstHandler,
+ _In_ PVECTORED_EXCEPTION_HANDLER VectoredHandler
+);
+
+__analysis_noreturn
+NTSYSAPI
+VOID
+NTAPI
+RtlAssert(
+ _In_ PVOID FailedAssertion,
+ _In_ PVOID FileName,
+ _In_ ULONG LineNumber,
+ _In_opt_z_ PCHAR Message
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlSetUnhandledExceptionFilter(
+ _In_ PRTLP_UNHANDLED_EXCEPTION_FILTER TopLevelExceptionFilter
+);
+
+#endif /* NTOS_MODE_USER */
+
+NTSYSAPI
+VOID
+NTAPI
+RtlCaptureContext(
+ _Out_ PCONTEXT ContextRecord
+);
+
+NTSYSAPI
+PVOID
+NTAPI
+RtlEncodePointer(
+ _In_ PVOID Pointer
+);
+
+NTSYSAPI
+PVOID
+NTAPI
+RtlDecodePointer(
+ _In_ PVOID Pointer
+);
+
+NTSYSAPI
+PVOID
+NTAPI
+RtlEncodeSystemPointer(
+ _In_ PVOID Pointer
+);
+
+NTSYSAPI
+PVOID
+NTAPI
+RtlDecodeSystemPointer(
+ _In_ PVOID Pointer
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlDispatchException(
+ _In_ PEXCEPTION_RECORD ExceptionRecord,
+ _In_ PCONTEXT Context
+);
+
+_IRQL_requires_max_(APC_LEVEL)
+_When_(Status < 0, _Out_range_(>, 0))
+_When_(Status >= 0, _Out_range_(==, 0))
+NTSYSAPI
+ULONG
+NTAPI
+RtlNtStatusToDosError(
+ _In_ NTSTATUS Status
+);
+
+_When_(Status < 0, _Out_range_(>, 0))
+_When_(Status >= 0, _Out_range_(==, 0))
+NTSYSAPI
+ULONG
+NTAPI
+RtlNtStatusToDosErrorNoTeb(
+ _In_ NTSTATUS Status
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlSetLastWin32ErrorAndNtStatusFromNtStatus(
+ _In_ NTSTATUS Status
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlRaiseException(
+ _In_ PEXCEPTION_RECORD ExceptionRecord
+);
+
+DECLSPEC_NORETURN
+NTSYSAPI
+VOID
+NTAPI
+RtlRaiseStatus(
+ _In_ NTSTATUS Status
+);
+
+NTSYSAPI
+LONG
+NTAPI
+RtlUnhandledExceptionFilter(
+ _In_ struct _EXCEPTION_POINTERS* ExceptionInfo
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlUnwind(
+ _In_opt_ PVOID TargetFrame,
+ _In_opt_ PVOID TargetIp,
+ _In_opt_ PEXCEPTION_RECORD ExceptionRecord,
+ _In_ PVOID ReturnValue
+);
+
+#define RTL_STACK_WALKING_MODE_FRAMES_TO_SKIP_SHIFT 8
+
+//
+// Tracing Functions
+//
+NTSYSAPI
+ULONG
+NTAPI
+RtlWalkFrameChain(
+ _Out_writes_(Count - (Flags >> RTL_STACK_WALKING_MODE_FRAMES_TO_SKIP_SHIFT)) PVOID *Callers,
+ _In_ ULONG Count,
+ _In_ ULONG Flags
+);
+
+NTSYSAPI
+USHORT
+NTAPI
+RtlLogStackBackTrace(
+ VOID
+);
+
+#ifdef NTOS_MODE_USER
+//
+// Heap Functions
+//
+_Must_inspect_result_
+_Ret_maybenull_
+_Post_writable_byte_size_(Size)
+NTSYSAPI
+PVOID
+NTAPI
+RtlAllocateHeap(
+ _In_ PVOID HeapHandle,
+ _In_opt_ ULONG Flags,
+ _In_ SIZE_T Size
+);
+
+_Must_inspect_result_
+NTSYSAPI
+PVOID
+NTAPI
+RtlCreateHeap(
+ _In_ ULONG Flags,
+ _In_opt_ PVOID BaseAddress,
+ _In_opt_ SIZE_T SizeToReserve,
+ _In_opt_ SIZE_T SizeToCommit,
+ _In_opt_ PVOID Lock,
+ _In_opt_ PRTL_HEAP_PARAMETERS Parameters
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlCreateTagHeap(
+ _In_ HANDLE HeapHandle,
+ _In_ ULONG Flags,
+ _In_ PWSTR TagName,
+ _In_ PWSTR TagSubName
+);
+
+ULONG
+NTAPI
+RtlCompactHeap(
+ _In_ HANDLE Heap,
+ _In_ ULONG Flags
+);
+
+_Must_inspect_result_
+NTSYSAPI
+PVOID
+NTAPI
+RtlDebugCreateHeap(
+ _In_ ULONG Flags,
+ _In_opt_ PVOID BaseAddress,
+ _In_opt_ SIZE_T SizeToReserve,
+ _In_opt_ SIZE_T SizeToCommit,
+ _In_opt_ PVOID Lock,
+ _In_opt_ PRTL_HEAP_PARAMETERS Parameters
+);
+
+NTSYSAPI
+HANDLE
+NTAPI
+RtlDestroyHeap(
+ _In_ _Post_invalid_ HANDLE Heap
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlExtendHeap(
+ _In_ HANDLE Heap,
+ _In_ ULONG Flags,
+ _In_ PVOID P,
+ _In_ SIZE_T Size
+);
+
+_Success_(return != 0)
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlFreeHeap(
+ _In_ HANDLE HeapHandle,
+ _In_opt_ ULONG Flags,
+ _In_ _Post_invalid_ PVOID P
+);
+
+ULONG
+NTAPI
+RtlGetProcessHeaps(
+ _In_ ULONG HeapCount,
+ _Out_cap_(HeapCount) HANDLE *HeapArray
+);
+
+_Success_(return != 0)
+BOOLEAN
+NTAPI
+RtlGetUserInfoHeap(
+ _In_ PVOID HeapHandle,
+ _In_ ULONG Flags,
+ _In_ PVOID BaseAddress,
+ _Inout_opt_ PVOID *UserValue,
+ _Out_opt_ PULONG UserFlags
+);
+
+NTSYSAPI
+PVOID
+NTAPI
+RtlProtectHeap(
+ _In_ PVOID HeapHandle,
+ _In_ BOOLEAN Protect
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlQueryHeapInformation(
+ _In_ PVOID HeapHandle,
+ _In_ HEAP_INFORMATION_CLASS HeapInformationClass,
+ _Out_ PVOID HeapInformation,
+ _In_ SIZE_T HeapInformationLength,
+ _When_(HeapInformationClass==HeapCompatibilityInformation, _On_failure_(_Out_opt_))
+ _Out_opt_ PSIZE_T ReturnLength
+);
+
+_Ret_opt_z_
+NTSYSAPI
+PWSTR
+NTAPI
+RtlQueryTagHeap(
+ _In_ PVOID HeapHandle,
+ _In_ ULONG Flags,
+ _In_ USHORT TagIndex,
+ _In_ BOOLEAN ResetCounters,
+ _Out_ PRTL_HEAP_TAG_INFO HeapTagInfo
+);
+
+_Must_inspect_result_
+_Ret_maybenull_
+_Post_writable_byte_size_(Size)
+NTSYSAPI
+PVOID
+NTAPI
+RtlReAllocateHeap(
+ _In_ HANDLE Heap,
+ _In_opt_ ULONG Flags,
+ _In_ _Post_invalid_ PVOID Ptr,
+ _In_ SIZE_T Size
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlSetHeapInformation(
+ _In_ PVOID HeapHandle,
+ _In_ HEAP_INFORMATION_CLASS HeapInformationClass,
+ _When_(HeapInformationClass==HeapCompatibilityInformation,_In_) PVOID HeapInformation,
+ _In_ SIZE_T HeapInformationLength
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlLockHeap(
+ _In_ HANDLE Heap
+);
+
+_Must_inspect_result_
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlMultipleAllocateHeap (
+ _In_ HANDLE HeapHandle,
+ _In_ ULONG Flags,
+ _In_ SIZE_T Size,
+ _In_ ULONG Count,
+ _Out_cap_(Count) _Deref_post_bytecap_(Size) PVOID * Array
+ );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlMultipleFreeHeap (
+ _In_ HANDLE HeapHandle,
+ _In_ ULONG Flags,
+ _In_ ULONG Count,
+ _In_count_(Count) /* _Deref_ _Post_invalid_ */ PVOID * Array
+ );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlUsageHeap(
+ _In_ HANDLE Heap,
+ _In_ ULONG Flags,
+ _Out_ PRTL_HEAP_USAGE Usage
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlUnlockHeap(
+ _In_ HANDLE Heap
+);
+
+BOOLEAN
+NTAPI
+RtlSetUserValueHeap(
+ _In_ PVOID HeapHandle,
+ _In_ ULONG Flags,
+ _In_ PVOID BaseAddress,
+ _In_ PVOID UserValue
+);
+
+BOOLEAN
+NTAPI
+RtlSetUserFlagsHeap(
+ _In_ PVOID HeapHandle,
+ _In_ ULONG Flags,
+ _In_ PVOID BaseAddress,
+ _In_ ULONG UserFlagsReset,
+ _In_ ULONG UserFlagsSet
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlValidateHeap(
+ _In_ HANDLE Heap,
+ _In_ ULONG Flags,
+ _In_opt_ PVOID P
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlWalkHeap(
+ _In_ HANDLE HeapHandle,
+ _In_ PVOID HeapEntry
+);
+
+#define RtlGetProcessHeap() (NtCurrentPeb()->ProcessHeap)
+
+#endif // NTOS_MODE_USER
+
+NTSYSAPI
+SIZE_T
+NTAPI
+RtlSizeHeap(
+ _In_ PVOID HeapHandle,
+ _In_ ULONG Flags,
+ _In_ PVOID MemoryPointer
+);
+
+
+//
+// Security Functions
+//
+_IRQL_requires_max_(APC_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAbsoluteToSelfRelativeSD(
+ _In_ PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor,
+ _Out_writes_bytes_to_opt_(*BufferLength, *BufferLength) PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor,
+ _Inout_ PULONG BufferLength
+);
+
+_IRQL_requires_max_(APC_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAddAccessAllowedAce(
+ _Inout_ PACL Acl,
+ _In_ ULONG Revision,
+ _In_ ACCESS_MASK AccessMask,
+ _In_ PSID Sid
+);
+
+_IRQL_requires_max_(APC_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAddAccessAllowedAceEx(
+ _Inout_ PACL pAcl,
+ _In_ ULONG dwAceRevision,
+ _In_ ULONG AceFlags,
+ _In_ ACCESS_MASK AccessMask,
+ _In_ PSID pSid
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAddAccessAllowedObjectAce(
+ _Inout_ PACL pAcl,
+ _In_ ULONG dwAceRevision,
+ _In_ ULONG AceFlags,
+ _In_ ACCESS_MASK AccessMask,
+ _In_opt_ GUID *ObjectTypeGuid,
+ _In_opt_ GUID *InheritedObjectTypeGuid,
+ _In_ PSID pSid
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAddAccessDeniedAce(
+ _Inout_ PACL Acl,
+ _In_ ULONG Revision,
+ _In_ ACCESS_MASK AccessMask,
+ _In_ PSID Sid
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAddAccessDeniedAceEx(
+ _Inout_ PACL Acl,
+ _In_ ULONG Revision,
+ _In_ ULONG Flags,
+ _In_ ACCESS_MASK AccessMask,
+ _In_ PSID Sid
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAddAccessDeniedObjectAce(
+ _Inout_ PACL pAcl,
+ _In_ ULONG dwAceRevision,
+ _In_ ULONG AceFlags,
+ _In_ ACCESS_MASK AccessMask,
+ _In_opt_ GUID *ObjectTypeGuid,
+ _In_opt_ GUID *InheritedObjectTypeGuid,
+ _In_ PSID pSid
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAddAce(
+ _Inout_ PACL Acl,
+ _In_ ULONG AceRevision,
+ _In_ ULONG StartingAceIndex,
+ _In_reads_bytes_(AceListLength) PVOID AceList,
+ _In_ ULONG AceListLength
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAddAuditAccessAce(
+ _Inout_ PACL Acl,
+ _In_ ULONG Revision,
+ _In_ ACCESS_MASK AccessMask,
+ _In_ PSID Sid,
+ _In_ BOOLEAN Success,
+ _In_ BOOLEAN Failure
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAcquirePrivilege(
+ _In_ PULONG Privilege,
+ _In_ ULONG NumPriv,
+ _In_ ULONG Flags,
+ _Out_ PVOID *ReturnedState
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAddAuditAccessAceEx(
+ _Inout_ PACL Acl,
+ _In_ ULONG Revision,
+ _In_ ULONG Flags,
+ _In_ ACCESS_MASK AccessMask,
+ _In_ PSID Sid,
+ _In_ BOOLEAN Success,
+ _In_ BOOLEAN Failure
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAddAuditAccessObjectAce(
+ _Inout_ PACL Acl,
+ _In_ ULONG Revision,
+ _In_ ULONG Flags,
+ _In_ ACCESS_MASK AccessMask,
+ _In_opt_ GUID *ObjectTypeGuid,
+ _In_opt_ GUID *InheritedObjectTypeGuid,
+ _In_ PSID Sid,
+ _In_ BOOLEAN Success,
+ _In_ BOOLEAN Failure
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAddMandatoryAce(
+ _Inout_ PACL Acl,
+ _In_ ULONG Revision,
+ _In_ ULONG Flags,
+ _In_ ULONG MandatoryFlags,
+ _In_ UCHAR AceType,
+ _In_ PSID LabelSid);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAdjustPrivilege(
+ _In_ ULONG Privilege,
+ _In_ BOOLEAN NewValue,
+ _In_ BOOLEAN ForThread,
+ _Out_ PBOOLEAN OldValue
+);
+
+_Must_inspect_result_
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAllocateAndInitializeSid(
+ _In_ PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,
+ _In_ UCHAR SubAuthorityCount,
+ _In_ ULONG SubAuthority0,
+ _In_ ULONG SubAuthority1,
+ _In_ ULONG SubAuthority2,
+ _In_ ULONG SubAuthority3,
+ _In_ ULONG SubAuthority4,
+ _In_ ULONG SubAuthority5,
+ _In_ ULONG SubAuthority6,
+ _In_ ULONG SubAuthority7,
+ _Outptr_ PSID *Sid
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlAreAllAccessesGranted(
+ ACCESS_MASK GrantedAccess,
+ ACCESS_MASK DesiredAccess
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlAreAnyAccessesGranted(
+ ACCESS_MASK GrantedAccess,
+ ACCESS_MASK DesiredAccess
+);
+
+_IRQL_requires_max_(APC_LEVEL)
+NTSYSAPI
+VOID
+NTAPI
+RtlCopyLuid (
+ _Out_ PLUID DestinationLuid,
+ _In_ PLUID SourceLuid
+ );
+
+NTSYSAPI
+VOID
+NTAPI
+RtlCopyLuidAndAttributesArray(
+ ULONG Count,
+ PLUID_AND_ATTRIBUTES Src,
+ PLUID_AND_ATTRIBUTES Dest
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCopySidAndAttributesArray(
+ ULONG Count,
+ PSID_AND_ATTRIBUTES Src,
+ ULONG SidAreaSize,
+ PSID_AND_ATTRIBUTES Dest,
+ PVOID SidArea,
+ PVOID* RemainingSidArea,
+ PULONG RemainingSidAreaSize
+);
+
+_IRQL_requires_max_(APC_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlConvertSidToUnicodeString(
+ _Inout_ PUNICODE_STRING UnicodeString,
+ _In_ PSID Sid,
+ _In_ BOOLEAN AllocateDestinationString
+);
+
+_IRQL_requires_max_(APC_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCopySid(
+ _In_ ULONG DestinationSidLength,
+ _Out_writes_bytes_(DestinationSidLength) PSID DestinationSid,
+ _In_ PSID SourceSid
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCreateAcl(
+ PACL Acl,
+ ULONG AclSize,
+ ULONG AclRevision
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCreateSecurityDescriptor(
+ _Out_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_ ULONG Revision
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCreateSecurityDescriptorRelative(
+ _Out_ PISECURITY_DESCRIPTOR_RELATIVE SecurityDescriptor,
+ _In_ ULONG Revision
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCopySecurityDescriptor(
+ _In_ PSECURITY_DESCRIPTOR pSourceSecurityDescriptor,
+ _Out_ PSECURITY_DESCRIPTOR *pDestinationSecurityDescriptor
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDeleteAce(
+ PACL Acl,
+ ULONG AceIndex
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlEqualPrefixSid(
+ PSID Sid1,
+ PSID Sid2
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlEqualSid (
+ _In_ PSID Sid1,
+ _In_ PSID Sid2
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlFirstFreeAce(
+ PACL Acl,
+ PACE* Ace
+);
+
+NTSYSAPI
+PVOID
+NTAPI
+RtlFreeSid(
+ _In_ _Post_invalid_ PSID Sid
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlGetAce(
+ PACL Acl,
+ ULONG AceIndex,
+ PVOID *Ace
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlGetControlSecurityDescriptor(
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _Out_ PSECURITY_DESCRIPTOR_CONTROL Control,
+ _Out_ PULONG Revision
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlGetDaclSecurityDescriptor(
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _Out_ PBOOLEAN DaclPresent,
+ _Out_ PACL *Dacl,
+ _Out_ PBOOLEAN DaclDefaulted
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlGetSaclSecurityDescriptor(
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _Out_ PBOOLEAN SaclPresent,
+ _Out_ PACL* Sacl,
+ _Out_ PBOOLEAN SaclDefaulted
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlGetGroupSecurityDescriptor(
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _Out_ PSID *Group,
+ _Out_ PBOOLEAN GroupDefaulted
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlGetOwnerSecurityDescriptor(
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _Out_ PSID *Owner,
+ _Out_ PBOOLEAN OwnerDefaulted
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlGetSecurityDescriptorRMControl(
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _Out_ PUCHAR RMControl
+);
+
+NTSYSAPI
+PSID_IDENTIFIER_AUTHORITY
+NTAPI
+RtlIdentifierAuthoritySid(PSID Sid);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlImpersonateSelf(IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
+
+_IRQL_requires_max_(APC_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlInitializeSid(
+ _Out_ PSID Sid,
+ _In_ PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,
+ _In_ UCHAR SubAuthorityCount
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlLengthRequiredSid(IN ULONG SubAuthorityCount);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlLengthSid(IN PSID Sid);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlMakeSelfRelativeSD(
+ _In_ PSECURITY_DESCRIPTOR AbsoluteSD,
+ _Out_ PSECURITY_DESCRIPTOR SelfRelativeSD,
+ _Inout_ PULONG BufferLength);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlMapGenericMask(
+ PACCESS_MASK AccessMask,
+ PGENERIC_MAPPING GenericMapping
+);
+
+#ifdef NTOS_MODE_USER
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlQueryInformationAcl(
+ PACL Acl,
+ PVOID Information,
+ ULONG InformationLength,
+ ACL_INFORMATION_CLASS InformationClass
+);
+
+#endif
+
+NTSYSAPI
+VOID
+NTAPI
+RtlReleasePrivilege(
+ _In_ PVOID ReturnedState
+);
+
+_IRQL_requires_max_(APC_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlSelfRelativeToAbsoluteSD(
+ _In_ PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor,
+ _Out_writes_bytes_to_opt_(*AbsoluteSecurityDescriptorSize, *AbsoluteSecurityDescriptorSize) PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor,
+ _Inout_ PULONG AbsoluteSecurityDescriptorSize,
+ _Out_writes_bytes_to_opt_(*DaclSize, *DaclSize) PACL Dacl,
+ _Inout_ PULONG DaclSize,
+ _Out_writes_bytes_to_opt_(*SaclSize, *SaclSize) PACL Sacl,
+ _Inout_ PULONG SaclSize,
+ _Out_writes_bytes_to_opt_(*OwnerSize, *OwnerSize) PSID Owner,
+ _Inout_ PULONG OwnerSize,
+ _Out_writes_bytes_to_opt_(*PrimaryGroupSize, *PrimaryGroupSize) PSID PrimaryGroup,
+ _Inout_ PULONG PrimaryGroupSize
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlSelfRelativeToAbsoluteSD2(
+ _Inout_ PSECURITY_DESCRIPTOR SelfRelativeSD,
+ _Out_ PULONG BufferSize
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlSetAttributesSecurityDescriptor(
+ _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_ SECURITY_DESCRIPTOR_CONTROL Control,
+ _Out_ PULONG Revision
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlSetControlSecurityDescriptor(
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_ SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,
+ _In_ SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet
+);
+
+_IRQL_requires_max_(APC_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlSetDaclSecurityDescriptor(
+ _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_ BOOLEAN DaclPresent,
+ _In_opt_ PACL Dacl,
+ _In_opt_ BOOLEAN DaclDefaulted
+);
+
+_IRQL_requires_max_(APC_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlSetGroupSecurityDescriptor(
+ _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_opt_ PSID Group,
+ _In_opt_ BOOLEAN GroupDefaulted
+);
+
+#ifdef NTOS_MODE_USER
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlSetInformationAcl(
+ PACL Acl,
+ PVOID Information,
+ ULONG InformationLength,
+ ACL_INFORMATION_CLASS InformationClass
+);
+
+#endif
+
+_IRQL_requires_max_(APC_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlSetOwnerSecurityDescriptor(
+ _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_opt_ PSID Owner,
+ _In_opt_ BOOLEAN OwnerDefaulted
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlSetSaclSecurityDescriptor(
+ _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_ BOOLEAN SaclPresent,
+ _In_ PACL Sacl,
+ _In_ BOOLEAN SaclDefaulted
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlSetSecurityDescriptorRMControl(
+ _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_ PUCHAR RMControl
+);
+
+NTSYSAPI
+PUCHAR
+NTAPI
+RtlSubAuthorityCountSid(
+ _In_ PSID Sid
+);
+
+NTSYSAPI
+PULONG
+NTAPI
+RtlSubAuthoritySid(
+ _In_ PSID Sid,
+ _In_ ULONG SubAuthority
+);
+
+_IRQL_requires_max_(APC_LEVEL)
+_Must_inspect_result_
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlValidRelativeSecurityDescriptor(
+ _In_reads_bytes_(SecurityDescriptorLength) PSECURITY_DESCRIPTOR SecurityDescriptorInput,
+ _In_ ULONG SecurityDescriptorLength,
+ _In_ SECURITY_INFORMATION RequiredInformation
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlValidSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlValidSid(IN PSID Sid);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlValidAcl(PACL Acl);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDeleteSecurityObject(
+ _In_ PSECURITY_DESCRIPTOR *ObjectDescriptor
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlNewSecurityObject(
+ _In_ PSECURITY_DESCRIPTOR ParentDescriptor,
+ _In_ PSECURITY_DESCRIPTOR CreatorDescriptor,
+ _Out_ PSECURITY_DESCRIPTOR *NewDescriptor,
+ _In_ BOOLEAN IsDirectoryObject,
+ _In_ HANDLE Token,
+ _In_ PGENERIC_MAPPING GenericMapping
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlQuerySecurityObject(
+ _In_ PSECURITY_DESCRIPTOR ObjectDescriptor,
+ _In_ SECURITY_INFORMATION SecurityInformation,
+ _Out_ PSECURITY_DESCRIPTOR ResultantDescriptor,
+ _In_ ULONG DescriptorLength,
+ _Out_ PULONG ReturnLength
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlSetSecurityObject(
+ _In_ SECURITY_INFORMATION SecurityInformation,
+ _In_ PSECURITY_DESCRIPTOR ModificationDescriptor,
+ _Out_ PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
+ _In_ PGENERIC_MAPPING GenericMapping,
+ _In_ HANDLE Token
+);
+
+//
+// Single-Character Functions
+//
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlLargeIntegerToChar(
+ _In_ PLARGE_INTEGER Value,
+ _In_ ULONG Base,
+ _In_ ULONG Length,
+ _Out_ PCHAR String
+);
+
+NTSYSAPI
+CHAR
+NTAPI
+RtlUpperChar(CHAR Source);
+
+NTSYSAPI
+WCHAR
+NTAPI
+RtlUpcaseUnicodeChar(WCHAR Source);
+
+NTSYSAPI
+WCHAR
+NTAPI
+RtlDowncaseUnicodeChar(IN WCHAR Source);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlIntegerToChar(
+ _In_ ULONG Value,
+ _In_ ULONG Base,
+ _In_ ULONG Length,
+ _Out_ PCHAR String
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlIntegerToUnicode(
+ _In_ ULONG Value,
+ _In_opt_ ULONG Base,
+ _In_opt_ ULONG Length,
+ _Inout_ LPWSTR String
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+_At_(String->MaximumLength, _Const_)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlIntegerToUnicodeString(
+ _In_ ULONG Value,
+ _In_opt_ ULONG Base,
+ _Inout_ PUNICODE_STRING String
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCharToInteger(
+ PCSZ String,
+ ULONG Base,
+ PULONG Value
+);
+
+//
+// Byte Swap Functions
+//
+#ifdef NTOS_MODE_USER
+
+#if (defined(_M_IX86) && (_MSC_FULL_VER > 13009037)) || \
+ ((defined(_M_AMD64) || \
+ defined(_M_IA64)) && (_MSC_FULL_VER > 13009175))
+
+unsigned short __cdecl _byteswap_ushort(unsigned short);
+unsigned long __cdecl _byteswap_ulong (unsigned long);
+unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64);
+#pragma intrinsic(_byteswap_ushort)
+#pragma intrinsic(_byteswap_ulong)
+#pragma intrinsic(_byteswap_uint64)
+#define RtlUshortByteSwap(_x) _byteswap_ushort((USHORT)(_x))
+#define RtlUlongByteSwap(_x) _byteswap_ulong((_x))
+#define RtlUlonglongByteSwap(_x) _byteswap_uint64((_x))
+
+#elif defined (__GNUC__)
+
+#define RtlUshortByteSwap(_x) _byteswap_ushort((USHORT)(_x))
+#define RtlUlongByteSwap(_x) _byteswap_ulong((_x))
+#define RtlUlonglongByteSwap(_x) _byteswap_uint64((_x))
+
+#else
+
+#if (NTDDI_VERSION >= NTDDI_WIN2K)
+NTSYSAPI
+USHORT
+FASTCALL
+RtlUshortByteSwap(IN USHORT Source);
+
+NTSYSAPI
+ULONG
+FASTCALL
+RtlUlongByteSwap(IN ULONG Source);
+
+NTSYSAPI
+ULONGLONG
+FASTCALL
+RtlUlonglongByteSwap(IN ULONGLONG Source);
+#endif
+
+#endif
+#endif // NTOS_MODE_USER
+
+//
+// Unicode->Ansi String Functions
+//
+NTSYSAPI
+ULONG
+NTAPI
+RtlxUnicodeStringToAnsiSize(IN PCUNICODE_STRING UnicodeString);
+
+#ifdef NTOS_MODE_USER
+
+#define RtlUnicodeStringToAnsiSize(STRING) ( \
+ NLS_MB_CODE_PAGE_TAG ? \
+ RtlxUnicodeStringToAnsiSize(STRING) : \
+ ((STRING)->Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR) \
+)
+
+#endif
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlUnicodeStringToAnsiString(
+ PANSI_STRING DestinationString,
+ PCUNICODE_STRING SourceString,
+ BOOLEAN AllocateDestinationString
+);
+
+//
+// Unicode->OEM String Functions
+//
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlUpcaseUnicodeStringToOemString(
+ POEM_STRING DestinationString,
+ PCUNICODE_STRING SourceString,
+ BOOLEAN AllocateDestinationString
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+_Must_inspect_result_
+//_At_(DestinationString->Buffer, _Post_bytecount_(DestinationString->Length))
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlUpcaseUnicodeStringToCountedOemString(
+ _When_(AllocateDestinationString, _Out_ _At_(DestinationString->Buffer, __drv_allocatesMem(Mem)))
+ _When_(!AllocateDestinationString, _Inout_)
+ POEM_STRING DestinationString,
+ _In_ PCUNICODE_STRING SourceString,
+ _In_ BOOLEAN AllocateDestinationString
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlUnicodeStringToOemString(
+ POEM_STRING DestinationString,
+ PCUNICODE_STRING SourceString,
+ BOOLEAN AllocateDestinationString
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlUpcaseUnicodeToOemN(
+ PCHAR OemString,
+ ULONG OemSize,
+ PULONG ResultSize,
+ PCWCH UnicodeString,
+ ULONG UnicodeSize
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlxUnicodeStringToOemSize(IN PCUNICODE_STRING UnicodeString);
+
+#ifdef NTOS_MODE_USER
+
+#define RtlUnicodeStringToOemSize(STRING) ( \
+ NLS_MB_OEM_CODE_PAGE_TAG ? \
+ RtlxUnicodeStringToOemSize(STRING) : \
+ ((STRING)->Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR) \
+)
+
+#define RtlUnicodeStringToCountedOemSize(STRING) ( \
+ (ULONG)(RtlUnicodeStringToOemSize(STRING) - sizeof(ANSI_NULL)) \
+)
+
+#endif
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlUnicodeToOemN(
+ PCHAR OemString,
+ ULONG OemSize,
+ PULONG ResultSize,
+ PCWCH UnicodeString,
+ ULONG UnicodeSize
+);
+
+//
+// Unicode->MultiByte String Functions
+//
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlUnicodeToMultiByteN(
+ PCHAR MbString,
+ ULONG MbSize,
+ PULONG ResultSize,
+ PCWCH UnicodeString,
+ ULONG UnicodeSize
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlUpcaseUnicodeToMultiByteN(
+ PCHAR MbString,
+ ULONG MbSize,
+ PULONG ResultSize,
+ PCWCH UnicodeString,
+ ULONG UnicodeSize
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlUnicodeToMultiByteSize(
+ PULONG MbSize,
+ PCWCH UnicodeString,
+ ULONG UnicodeSize
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlxOemStringToUnicodeSize(IN PCOEM_STRING OemString);
+
+//
+// OEM to Unicode Functions
+//
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlOemStringToUnicodeString(
+ PUNICODE_STRING DestinationString,
+ PCOEM_STRING SourceString,
+ BOOLEAN AllocateDestinationString
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlOemToUnicodeN(
+ _Out_writes_bytes_to_(MaxBytesInUnicodeString, *BytesInUnicodeString) PWCH UnicodeString,
+ _In_ ULONG MaxBytesInUnicodeString,
+ _Out_opt_ PULONG BytesInUnicodeString,
+ _In_reads_bytes_(BytesInOemString) PCCH OemString,
+ _In_ ULONG BytesInOemString
+);
+
+#ifdef NTOS_MODE_USER
+
+#define RtlOemStringToUnicodeSize(STRING) ( \
+ NLS_MB_OEM_CODE_PAGE_TAG ? \
+ RtlxOemStringToUnicodeSize(STRING) : \
+ ((STRING)->Length + sizeof(ANSI_NULL)) * sizeof(WCHAR) \
+)
+
+#define RtlOemStringToCountedUnicodeSize(STRING) ( \
+ (ULONG)(RtlOemStringToUnicodeSize(STRING) - sizeof(UNICODE_NULL)) \
+)
+
+#endif
+
+//
+// Ansi->Unicode String Functions
+//
+NTSYSAPI
+ULONG
+NTAPI
+RtlxAnsiStringToUnicodeSize(
+ PCANSI_STRING AnsiString
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAnsiStringToUnicodeString(
+ PUNICODE_STRING DestinationString,
+ PCANSI_STRING SourceString,
+ BOOLEAN AllocateDestinationString
+);
+
+#ifdef NTOS_MODE_USER
+
+#define RtlAnsiStringToUnicodeSize(STRING) ( \
+ NLS_MB_CODE_PAGE_TAG ? \
+ RtlxAnsiStringToUnicodeSize(STRING) : \
+ ((STRING)->Length + sizeof(ANSI_NULL)) * sizeof(WCHAR) \
+)
+
+#endif
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlCreateUnicodeStringFromAsciiz(
+ _Out_ PUNICODE_STRING Destination,
+ _In_ PCSZ Source
+);
+
+//
+// Unicode String Functions
+//
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAppendUnicodeToString(
+ PUNICODE_STRING Destination,
+ PCWSTR Source
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAppendUnicodeStringToString(
+ PUNICODE_STRING Destination,
+ PCUNICODE_STRING Source
+);
+
+NTSYSAPI
+LONG
+NTAPI
+RtlCompareUnicodeString(
+ PCUNICODE_STRING String1,
+ PCUNICODE_STRING String2,
+ BOOLEAN CaseInsensitive
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlCopyUnicodeString(
+ PUNICODE_STRING DestinationString,
+ PCUNICODE_STRING SourceString
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlCreateUnicodeString(
+ PUNICODE_STRING DestinationString,
+ PCWSTR SourceString
+);
+
+#ifdef NTOS_MODE_USER
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDowncaseUnicodeString(
+ _Inout_ PUNICODE_STRING UniDest,
+ _In_ PCUNICODE_STRING UniSource,
+ _In_ BOOLEAN AllocateDestinationString
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDuplicateUnicodeString(
+ _In_ ULONG Flags,
+ _In_ PCUNICODE_STRING SourceString,
+ _Out_ PUNICODE_STRING DestinationString
+);
+
+//
+// Memory Functions
+//
+NTSYSAPI
+VOID
+NTAPI
+RtlFillMemoryUlong(
+ _In_ PVOID Destination,
+ _In_ SIZE_T Length,
+ _In_ ULONG Fill
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlFillMemoryUlonglong(
+ _Out_ PVOID Destination,
+ _In_ SIZE_T Length,
+ _In_ ULONGLONG Pattern
+);
+
+
+NTSYSAPI
+SIZE_T
+NTAPI
+RtlCompareMemoryUlong(
+ _In_ PVOID Source,
+ _In_ SIZE_T Length,
+ _In_ ULONG Pattern
+);
+
+#define RtlEqualMemory(Destination, Source, Length) \
+ (!memcmp(Destination, Source, Length))
+
+#define RtlCopyBytes RtlCopyMemory
+#define RtlFillBytes RtlFillMemory
+#define RtlZeroBytes RtlZeroMemory
+
+#endif
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlEqualUnicodeString(
+ PCUNICODE_STRING String1,
+ PCUNICODE_STRING String2,
+ BOOLEAN CaseInsensitive
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlFindCharInUnicodeString(
+ _In_ ULONG Flags,
+ _In_ PCUNICODE_STRING SearchString,
+ _In_ PCUNICODE_STRING MatchString,
+ _Out_ PUSHORT Position
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSYSAPI
+VOID
+NTAPI
+RtlFreeUnicodeString(
+ _Inout_ _At_(UnicodeString->Buffer, __drv_freesMem(Mem))
+ PUNICODE_STRING UnicodeString
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlEraseUnicodeString(
+ _Inout_ PUNICODE_STRING String
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlHashUnicodeString(
+ _In_ CONST UNICODE_STRING *String,
+ _In_ BOOLEAN CaseInSensitive,
+ _In_ ULONG HashAlgorithm,
+ _Out_ PULONG HashValue
+);
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+_At_(DestinationString->Buffer, _Post_equal_to_(SourceString))
+_When_(SourceString != NULL,
+_At_(DestinationString->Length, _Post_equal_to_(_String_length_(SourceString) * sizeof(WCHAR)))
+_At_(DestinationString->MaximumLength, _Post_equal_to_(DestinationString->Length + sizeof(WCHAR))))
+_When_(SourceString == NULL,
+_At_(DestinationString->Length, _Post_equal_to_(0))
+_At_(DestinationString->MaximumLength, _Post_equal_to_(0)))
+NTSYSAPI
+VOID
+NTAPI
+RtlInitUnicodeString(
+ _Out_ PUNICODE_STRING DestinationString,
+ _In_opt_z_ __drv_aliasesMem PCWSTR SourceString
+);
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlInitUnicodeStringEx(
+ _Out_ PUNICODE_STRING DestinationString,
+ _In_opt_z_ __drv_aliasesMem PCWSTR SourceString
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlIsTextUnicode(
+ PVOID Buffer,
+ INT Length,
+ INT *Flags
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+_Must_inspect_result_
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlPrefixString(
+ _In_ const STRING *String1,
+ _In_ const STRING *String2,
+ _In_ BOOLEAN CaseInsensitive
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+_Must_inspect_result_
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlPrefixUnicodeString(
+ _In_ PCUNICODE_STRING String1,
+ _In_ PCUNICODE_STRING String2,
+ _In_ BOOLEAN CaseInsensitive
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSYSAPI
+VOID
+NTAPI
+RtlUpperString(
+ _Inout_ PSTRING DestinationString,
+ _In_ const STRING *SourceString
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+_Must_inspect_result_
+NTSYSAPI
+LONG
+NTAPI
+RtlCompareString(
+ _In_ const STRING *String1,
+ _In_ const STRING *String2,
+ _In_ BOOLEAN CaseInSensitive
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlCopyString(
+ _Out_ PSTRING DestinationString,
+ _In_opt_ const STRING *SourceString
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+_Must_inspect_result_
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlEqualString(
+ _In_ const STRING *String1,
+ _In_ const STRING *String2,
+ _In_ BOOLEAN CaseInSensitive
+);
+
+_IRQL_requires_max_(APC_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAppendStringToString(
+ _Inout_ PSTRING Destination,
+ _In_ const STRING *Source
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+_When_(AllocateDestinationString, _Must_inspect_result_)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlUpcaseUnicodeString(
+ _When_(AllocateDestinationString, _Out_ _At_(DestinationString->Buffer, __drv_allocatesMem(Mem)))
+ _When_(!AllocateDestinationString, _Inout_)
+ PUNICODE_STRING DestinationString,
+ _In_ PCUNICODE_STRING SourceString,
+ _In_ BOOLEAN AllocateDestinationString
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlUnicodeStringToInteger(
+ _In_ PCUNICODE_STRING String,
+ _In_opt_ ULONG Base,
+ _Out_ PULONG Value
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlValidateUnicodeString(
+ _In_ ULONG Flags,
+ _In_ PCUNICODE_STRING String
+);
+
+//
+// Ansi String Functions
+//
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSYSAPI
+VOID
+NTAPI
+RtlFreeAnsiString(
+ _Inout_ _At_(AnsiString->Buffer, __drv_freesMem(Mem))
+ PANSI_STRING AnsiString
+);
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSYSAPI
+VOID
+NTAPI
+RtlInitAnsiString(
+ _Out_ PANSI_STRING DestinationString,
+ _In_opt_z_ __drv_aliasesMem PCSZ SourceString
+);
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlInitAnsiStringEx(
+ _Out_ PANSI_STRING DestinationString,
+ _In_opt_z_ __drv_aliasesMem PCSZ SourceString
+);
+
+//
+// OEM String Functions
+//
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSYSAPI
+VOID
+NTAPI
+RtlFreeOemString(
+ _Inout_ _At_(OemString->Buffer, __drv_freesMem(Mem))
+ POEM_STRING OemString
+);
+
+//
+// MultiByte->Unicode String Functions
+//
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlMultiByteToUnicodeN(
+ _Out_writes_bytes_to_(MaxBytesInUnicodeString, *BytesInUnicodeString) PWCH UnicodeString,
+ _In_ ULONG MaxBytesInUnicodeString,
+ _Out_opt_ PULONG BytesInUnicodeString,
+ _In_reads_bytes_(BytesInMultiByteString) const CHAR *MultiByteString,
+ _In_ ULONG BytesInMultiByteString
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlMultiByteToUnicodeSize(
+ _Out_ PULONG BytesInUnicodeString,
+ _In_reads_bytes_(BytesInMultiByteString) const CHAR *MultiByteString,
+ _In_ ULONG BytesInMultiByteString
+);
+
+//
+// Atom Functions
+//
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAddAtomToAtomTable(
+ _In_ PRTL_ATOM_TABLE AtomTable,
+ _In_ PWSTR AtomName,
+ _Out_ PRTL_ATOM Atom
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCreateAtomTable(
+ _In_ ULONG TableSize,
+ _Inout_ PRTL_ATOM_TABLE *AtomTable
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDeleteAtomFromAtomTable(
+ _In_ PRTL_ATOM_TABLE AtomTable,
+ _In_ RTL_ATOM Atom
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDestroyAtomTable(IN PRTL_ATOM_TABLE AtomTable);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlQueryAtomInAtomTable(
+ _In_ PRTL_ATOM_TABLE AtomTable,
+ _In_ RTL_ATOM Atom,
+ _Out_opt_ PULONG RefCount,
+ _Out_opt_ PULONG PinCount,
+ _Out_opt_z_bytecap_(*NameLength) PWSTR AtomName,
+ _Inout_opt_ PULONG NameLength
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlPinAtomInAtomTable(
+ _In_ PRTL_ATOM_TABLE AtomTable,
+ _In_ RTL_ATOM Atom
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlLookupAtomInAtomTable(
+ _In_ PRTL_ATOM_TABLE AtomTable,
+ _In_ PWSTR AtomName,
+ _Out_ PRTL_ATOM Atom
+);
+
+//
+// Process Management Functions
+//
+NTSYSAPI
+PPEB
+NTAPI
+RtlGetCurrentPeb(
+ VOID
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlAcquirePebLock(VOID);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCreateProcessParameters (
+ _Out_ PRTL_USER_PROCESS_PARAMETERS *ProcessParameters,
+ _In_ PUNICODE_STRING ImagePathName,
+ _In_opt_ PUNICODE_STRING DllPath,
+ _In_opt_ PUNICODE_STRING CurrentDirectory,
+ _In_opt_ PUNICODE_STRING CommandLine,
+ _In_opt_ PWSTR Environment,
+ _In_opt_ PUNICODE_STRING WindowTitle,
+ _In_opt_ PUNICODE_STRING DesktopInfo,
+ _In_opt_ PUNICODE_STRING ShellInfo,
+ _In_opt_ PUNICODE_STRING RuntimeInfo
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCreateUserProcess(
+ _In_ PUNICODE_STRING ImageFileName,
+ _In_ ULONG Attributes,
+ _In_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
+ _In_opt_ PSECURITY_DESCRIPTOR ProcessSecutityDescriptor,
+ _In_opt_ PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,
+ _In_opt_ HANDLE ParentProcess,
+ _In_ BOOLEAN CurrentDirectory,
+ _In_opt_ HANDLE DebugPort,
+ _In_opt_ HANDLE ExceptionPort,
+ _Out_ PRTL_USER_PROCESS_INFORMATION ProcessInfo
+);
+
+#if (NTDDI_VERSION >= NTDDI_WIN7)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCreateUserThread(
+ _In_ PVOID ThreadContext,
+ _Out_ HANDLE *OutThreadHandle,
+ _Reserved_ PVOID Reserved1,
+ _Reserved_ PVOID Reserved2,
+ _Reserved_ PVOID Reserved3,
+ _Reserved_ PVOID Reserved4,
+ _Reserved_ PVOID Reserved5,
+ _Reserved_ PVOID Reserved6,
+ _Reserved_ PVOID Reserved7,
+ _Reserved_ PVOID Reserved8
+);
+#else
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCreateUserThread(
+ _In_ HANDLE ProcessHandle,
+ _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_ BOOLEAN CreateSuspended,
+ _In_ ULONG StackZeroBits,
+ _In_ SIZE_T StackReserve,
+ _In_ SIZE_T StackCommit,
+ _In_ PTHREAD_START_ROUTINE StartAddress,
+ _In_ PVOID Parameter,
+ _Out_opt_ PHANDLE ThreadHandle,
+ _Out_opt_ PCLIENT_ID ClientId
+);
+#endif
+
+NTSYSAPI
+PRTL_USER_PROCESS_PARAMETERS
+NTAPI
+RtlDeNormalizeProcessParams(
+ _In_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDestroyProcessParameters(
+ _In_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlExitUserThread(
+ _In_ NTSTATUS Status);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlInitializeContext(
+ _In_ HANDLE ProcessHandle,
+ _Out_ PCONTEXT ThreadContext,
+ _In_opt_ PVOID ThreadStartParam,
+ _In_ PTHREAD_START_ROUTINE ThreadStartAddress,
+ _In_ PINITIAL_TEB InitialTeb
+);
+
+#ifdef _M_AMD64
+typedef struct _WOW64_CONTEXT *PWOW64_CONTEXT;
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlWow64GetThreadContext(
+ _In_ HANDLE ThreadHandle,
+ _Inout_ PWOW64_CONTEXT ThreadContext
+);
+
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlWow64SetThreadContext(
+ _In_ HANDLE ThreadHandle,
+ _In_ PWOW64_CONTEXT ThreadContext
+);
+#endif
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlIsThreadWithinLoaderCallout(VOID);
+
+NTSYSAPI
+PRTL_USER_PROCESS_PARAMETERS
+NTAPI
+RtlNormalizeProcessParams(
+ _In_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlReleasePebLock(VOID);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlRemoteCall(
+ _In_ HANDLE Process,
+ _In_ HANDLE Thread,
+ _In_ PVOID CallSite,
+ _In_ ULONG ArgumentCount,
+ _In_ PULONG Arguments,
+ _In_ BOOLEAN PassContext,
+ _In_ BOOLEAN AlreadySuspended
+);
+
+NTSYSAPI
+NTSTATUS
+__cdecl
+RtlSetProcessIsCritical(
+ _In_ BOOLEAN NewValue,
+ _Out_opt_ PBOOLEAN OldValue,
+ _In_ BOOLEAN NeedBreaks
+);
+
+NTSYSAPI
+NTSTATUS
+__cdecl
+RtlSetThreadIsCritical(
+ _In_ BOOLEAN NewValue,
+ _Out_opt_ PBOOLEAN OldValue,
+ _In_ BOOLEAN NeedBreaks
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlGetCurrentProcessorNumber(
+ VOID
+);
+
+#define NtCurrentPeb() (NtCurrentTeb()->ProcessEnvironmentBlock)
+
+//
+// Thread Pool Functions
+//
+//
+NTSTATUS
+NTAPI
+RtlSetThreadPoolStartFunc(
+ _In_ PRTL_START_POOL_THREAD StartPoolThread,
+ _In_ PRTL_EXIT_POOL_THREAD ExitPoolThread
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDeregisterWaitEx(
+ _In_ HANDLE hWaitHandle,
+ _In_opt_ HANDLE hCompletionEvent
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDeregisterWait(
+ _In_ HANDLE hWaitHandle
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlQueueWorkItem(
+ _In_ WORKERCALLBACKFUNC Function,
+ _In_opt_ PVOID Context,
+ _In_ ULONG Flags
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlSetIoCompletionCallback(
+ _In_ HANDLE FileHandle,
+ _In_ PIO_APC_ROUTINE Callback,
+ _In_ ULONG Flags
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlRegisterWait(
+ _In_ PHANDLE phNewWaitObject,
+ _In_ HANDLE hObject,
+ _In_ WAITORTIMERCALLBACKFUNC Callback,
+ _In_ PVOID pvContext,
+ _In_ ULONG ulMilliseconds,
+ _In_ ULONG ulFlags
+);
+
+//
+// Environment/Path Functions
+//
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCreateEnvironment(
+ _In_ BOOLEAN Inherit,
+ _Out_ PWSTR *Environment
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlComputePrivatizedDllName_U(
+ _In_ PUNICODE_STRING DllName,
+ _Out_ PUNICODE_STRING RealName,
+ _Out_ PUNICODE_STRING LocalName
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlDestroyEnvironment(
+ _In_ PWSTR Environment
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlDoesFileExists_U(
+ _In_ PCWSTR FileName
+);
+
+NTSYSAPI
+RTL_PATH_TYPE
+NTAPI
+RtlDetermineDosPathNameType_U(
+ _In_ PCWSTR Path
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlDosSearchPath_U(
+ _In_ PCWSTR Path,
+ _In_ PCWSTR FileName,
+ _In_ PCWSTR Extension,
+ _In_ ULONG BufferSize,
+ _Out_ PWSTR Buffer,
+ _Out_ PWSTR *PartName
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDosSearchPath_Ustr(
+ _In_ ULONG Flags,
+ _In_ PUNICODE_STRING PathString,
+ _In_ PUNICODE_STRING FileNameString,
+ _In_ PUNICODE_STRING ExtensionString,
+ _In_ PUNICODE_STRING CallerBuffer,
+ _Inout_opt_ PUNICODE_STRING DynamicString,
+ _Out_opt_ PUNICODE_STRING* FullNameOut,
+ _Out_opt_ PSIZE_T FilePartSize,
+ _Out_opt_ PSIZE_T LengthNeeded
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlDosPathNameToNtPathName_U(
+ _In_opt_z_ PCWSTR DosPathName,
+ _Out_ PUNICODE_STRING NtPathName,
+ _Out_opt_ PCWSTR *NtFileNamePart,
+ _Out_opt_ PRTL_RELATIVE_NAME_U DirectoryInfo
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlDosPathNameToRelativeNtPathName_U(
+ _In_ PCWSTR DosName,
+ _Out_ PUNICODE_STRING NtName,
+ _Out_ PCWSTR *PartName,
+ _Out_ PRTL_RELATIVE_NAME_U RelativeName
+);
+
+_At_(Destination->Buffer, _Out_bytecap_(Destination->MaximumLength))
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlExpandEnvironmentStrings_U(
+ _In_z_ PWSTR Environment,
+ _In_ PUNICODE_STRING Source,
+ _Inout_ PUNICODE_STRING Destination,
+ _Out_ PULONG Length
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlGetCurrentDirectory_U(
+ _In_ ULONG MaximumLength,
+ _Out_bytecap_(MaximumLength) PWSTR Buffer
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlGetFullPathName_U(
+ _In_ PCWSTR FileName,
+ _In_ ULONG Size,
+ _Out_z_bytecap_(Size) PWSTR Buffer,
+ _Out_opt_ PWSTR *ShortName
+);
+
+#if (NTDDI_VERSION >= NTDDI_WIN7)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlGetFullPathName_UEx(
+ _In_ PWSTR FileName,
+ _In_ ULONG BufferLength,
+ _Out_ PWSTR Buffer,
+ _Out_opt_ PWSTR *FilePart,
+ _Out_opt_ RTL_PATH_TYPE *InputPathType
+ );
+#endif
+
+NTSTATUS
+NTAPI
+RtlGetFullPathName_UstrEx(
+ _In_ PUNICODE_STRING FileName,
+ _In_opt_ PUNICODE_STRING StaticString,
+ _In_opt_ PUNICODE_STRING DynamicString,
+ _Out_opt_ PUNICODE_STRING *StringUsed,
+ _Out_opt_ PSIZE_T FilePartSize,
+ _Out_opt_ PBOOLEAN NameInvalid,
+ _Out_ RTL_PATH_TYPE* PathType,
+ _Out_opt_ PSIZE_T LengthNeeded
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlGetLengthWithoutTrailingPathSeperators(
+ _Reserved_ ULONG Flags,
+ _In_ PCUNICODE_STRING PathString,
+ _Out_ PULONG Length
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlGetLongestNtPathLength(
+ VOID
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlIsDosDeviceName_U(
+ _In_ PCWSTR Name
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlIsDosDeviceName_Ustr(
+ _In_ PCUNICODE_STRING Name
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+_Must_inspect_result_
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlIsNameLegalDOS8Dot3(
+ _In_ PCUNICODE_STRING Name,
+ _Inout_opt_ POEM_STRING OemName,
+ _Out_opt_ PBOOLEAN NameContainsSpaces
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlQueryEnvironmentVariable_U(
+ _In_opt_ PWSTR Environment,
+ _In_ PUNICODE_STRING Name,
+ _Out_ PUNICODE_STRING Value
+);
+
+VOID
+NTAPI
+RtlReleaseRelativeName(
+ _In_ PRTL_RELATIVE_NAME_U RelativeName
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlSetCurrentDirectory_U(
+ _In_ PUNICODE_STRING name
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlSetEnvironmentVariable(
+ _In_z_ PWSTR *Environment,
+ _In_ PUNICODE_STRING Name,
+ _In_ PUNICODE_STRING Value
+);
+
+//
+// Critical Section/Resource Functions
+//
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDeleteCriticalSection (
+ _In_ PRTL_CRITICAL_SECTION CriticalSection
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlEnterCriticalSection(
+ _In_ PRTL_CRITICAL_SECTION CriticalSection
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlInitializeCriticalSection(
+ _In_ PRTL_CRITICAL_SECTION CriticalSection
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlInitializeCriticalSectionAndSpinCount(
+ _In_ PRTL_CRITICAL_SECTION CriticalSection,
+ _In_ ULONG SpinCount
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlLeaveCriticalSection(
+ _In_ PRTL_CRITICAL_SECTION CriticalSection
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlTryEnterCriticalSection(
+ _In_ PRTL_CRITICAL_SECTION CriticalSection
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlpUnWaitCriticalSection(
+ _In_ PRTL_CRITICAL_SECTION CriticalSection
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlpWaitForCriticalSection(
+ _In_ PRTL_CRITICAL_SECTION CriticalSection
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlAcquireResourceExclusive(
+ _In_ PRTL_RESOURCE Resource,
+ _In_ BOOLEAN Wait
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlAcquireResourceShared(
+ _In_ PRTL_RESOURCE Resource,
+ _In_ BOOLEAN Wait
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlConvertExclusiveToShared(
+ _In_ PRTL_RESOURCE Resource
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlConvertSharedToExclusive(
+ _In_ PRTL_RESOURCE Resource
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlDeleteResource(
+ _In_ PRTL_RESOURCE Resource
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlDumpResource(
+ _In_ PRTL_RESOURCE Resource
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlInitializeResource(
+ _In_ PRTL_RESOURCE Resource
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlReleaseResource(
+ _In_ PRTL_RESOURCE Resource
+);
+
+//
+// Compression Functions
+//
+NTSYSAPI //NT_RTL_COMPRESS_API
+NTSTATUS
+NTAPI
+RtlCompressBuffer(
+ _In_ USHORT CompressionFormatAndEngine,
+ _In_reads_bytes_(UncompressedBufferSize) PUCHAR UncompressedBuffer,
+ _In_ ULONG UncompressedBufferSize,
+ _Out_writes_bytes_to_(CompressedBufferSize, *FinalCompressedSize) PUCHAR CompressedBuffer,
+ _In_ ULONG CompressedBufferSize,
+ _In_ ULONG UncompressedChunkSize,
+ _Out_ PULONG FinalCompressedSize,
+ _In_ PVOID WorkSpace
+);
+
+_IRQL_requires_max_(APC_LEVEL)
+NTSYSAPI //NT_RTL_COMPRESS_API
+NTSTATUS
+NTAPI
+RtlDecompressBuffer(
+ _In_ USHORT CompressionFormat,
+ _Out_writes_bytes_to_(UncompressedBufferSize, *FinalUncompressedSize) PUCHAR UncompressedBuffer,
+ _In_ ULONG UncompressedBufferSize,
+ _In_reads_bytes_(CompressedBufferSize) PUCHAR CompressedBuffer,
+ _In_ ULONG CompressedBufferSize,
+ _Out_ PULONG FinalUncompressedSize
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlGetCompressionWorkSpaceSize(
+ _In_ USHORT CompressionFormatAndEngine,
+ _Out_ PULONG CompressBufferWorkSpaceSize,
+ _Out_ PULONG CompressFragmentWorkSpaceSize
+);
+
+//
+// Debug Info Functions
+//
+NTSYSAPI
+PRTL_DEBUG_INFORMATION
+NTAPI
+RtlCreateQueryDebugBuffer(
+ _In_ ULONG Size,
+ _In_ BOOLEAN EventPair
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDestroyQueryDebugBuffer(IN PRTL_DEBUG_INFORMATION DebugBuffer);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlQueryProcessDebugInformation(
+ _In_ ULONG ProcessId,
+ _In_ ULONG DebugInfoClassMask,
+ _Inout_ PRTL_DEBUG_INFORMATION DebugBuffer
+);
+
+//
+// Bitmap Functions
+//
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlAreBitsClear(
+ _In_ PRTL_BITMAP BitMapHeader,
+ _In_ ULONG StartingIndex,
+ _In_ ULONG Length
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlAreBitsSet(
+ _In_ PRTL_BITMAP BitMapHeader,
+ _In_ ULONG StartingIndex,
+ _In_ ULONG Length
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlClearAllBits(
+ _In_ PRTL_BITMAP BitMapHeader
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlClearBits(
+ _In_ PRTL_BITMAP BitMapHeader,
+ _In_range_(0, BitMapHeader->SizeOfBitMap - NumberToClear) ULONG StartingIndex,
+ _In_range_(0, BitMapHeader->SizeOfBitMap - StartingIndex) ULONG NumberToClear
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlFindClearBits(
+ _In_ PRTL_BITMAP BitMapHeader,
+ _In_ ULONG NumberToFind,
+ _In_ ULONG HintIndex
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlFindClearBitsAndSet(
+ _In_ PRTL_BITMAP BitMapHeader,
+ _In_ ULONG NumberToFind,
+ _In_ ULONG HintIndex
+);
+
+NTSYSAPI
+CCHAR
+NTAPI
+RtlFindLeastSignificantBit(
+ _In_ ULONGLONG Value
+);
+
+NTSYSAPI
+CCHAR
+NTAPI
+RtlFindMostSignificantBit(
+ _In_ ULONGLONG Value
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlFindNextForwardRunClear(
+ _In_ PRTL_BITMAP BitMapHeader,
+ _In_ ULONG FromIndex,
+ _Out_ PULONG StartingRunIndex
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlFindNextForwardRunSet(
+ _In_ PRTL_BITMAP BitMapHeader,
+ _In_ ULONG FromIndex,
+ _Out_ PULONG StartingRunIndex
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlFindSetBits(
+ _In_ PRTL_BITMAP BitMapHeader,
+ _In_ ULONG NumberToFind,
+ _In_ ULONG HintIndex
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlFindSetBitsAndClear(
+ _In_ PRTL_BITMAP BitMapHeader,
+ _In_ ULONG NumberToFind,
+ _In_ ULONG HintIndex
+);
+
+#ifdef _REACTOS_ // ReactOS improvement
+_At_(BitMapHeader->SizeOfBitMap, _Post_equal_to_(SizeOfBitMap))
+_At_(BitMapHeader->Buffer, _Post_equal_to_(BitMapBuffer))
+#endif
+NTSYSAPI
+VOID
+NTAPI
+RtlInitializeBitMap(
+ _Out_ PRTL_BITMAP BitMapHeader,
+ _In_opt_ __drv_aliasesMem PULONG BitMapBuffer,
+ _In_opt_ ULONG SizeOfBitMap
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlNumberOfClearBits(
+ _In_ PRTL_BITMAP BitMapHeader
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlNumberOfSetBits(
+ _In_ PRTL_BITMAP BitMapHeader
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlSetBit(
+ _In_ PRTL_BITMAP BitMapHeader,
+ _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlSetBits(
+ _In_ PRTL_BITMAP BitMapHeader,
+ _In_range_(0, BitMapHeader->SizeOfBitMap - NumberToSet) ULONG StartingIndex,
+ _In_range_(0, BitMapHeader->SizeOfBitMap - StartingIndex) ULONG NumberToSet
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlSetAllBits(
+ _In_ PRTL_BITMAP BitMapHeader
+);
+
+_Must_inspect_result_
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlTestBit(
+ _In_ PRTL_BITMAP BitMapHeader,
+ _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber
+);
+
+//
+// Timer Functions
+//
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCreateTimer(
+ _In_ HANDLE TimerQueue,
+ _In_ PHANDLE phNewTimer,
+ _In_ WAITORTIMERCALLBACKFUNC Callback,
+ _In_ PVOID Parameter,
+ _In_ ULONG DueTime,
+ _In_ ULONG Period,
+ _In_ ULONG Flags
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCreateTimerQueue(PHANDLE TimerQueue);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDeleteTimer(
+ _In_ HANDLE TimerQueue,
+ _In_ HANDLE Timer,
+ _In_ HANDLE CompletionEvent
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlUpdateTimer(
+ _In_ HANDLE TimerQueue,
+ _In_ HANDLE Timer,
+ _In_ ULONG DueTime,
+ _In_ ULONG Period
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDeleteTimerQueueEx(
+ _In_ HANDLE TimerQueue,
+ _In_opt_ HANDLE CompletionEvent
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDeleteTimerQueue(HANDLE TimerQueue);
+
+//
+// SList functions
+//
+PSLIST_ENTRY
+FASTCALL
+InterlockedPushListSList(
+ _Inout_ PSLIST_HEADER ListHead,
+ _Inout_ __drv_aliasesMem PSLIST_ENTRY List,
+ _Inout_ PSLIST_ENTRY ListEnd,
+ _In_ ULONG Count
+);
+
+//
+// Range List functions
+//
+NTSYSAPI
+VOID
+NTAPI
+RtlInitializeRangeList(
+ _Inout_ PRTL_RANGE_LIST RangeList
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlFreeRangeList(
+ _In_ PRTL_RANGE_LIST RangeList
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAddRange(
+ _Inout_ PRTL_RANGE_LIST RangeList,
+ _In_ ULONGLONG Start,
+ _In_ ULONGLONG End,
+ _In_ UCHAR Attributes,
+ _In_ ULONG Flags,
+ _In_opt_ PVOID UserData,
+ _In_opt_ PVOID Owner
+);
+
+//
+// Debug Functions
+//
+ULONG
+__cdecl
+DbgPrint(
+ _In_z_ _Printf_format_string_ PCSTR Format,
+ ...
+);
+
+NTSYSAPI
+ULONG
+__cdecl
+DbgPrintEx(
+ _In_ ULONG ComponentId,
+ _In_ ULONG Level,
+ _In_z_ _Printf_format_string_ PCSTR Format,
+ ...
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+DbgPrompt(
+ _In_z_ PCCH Prompt,
+ _Out_writes_bytes_(MaximumResponseLength) PCH Response,
+ _In_ ULONG MaximumResponseLength
+);
+
+#undef DbgBreakPoint
+VOID
+NTAPI
+DbgBreakPoint(
+ VOID
+);
+
+VOID
+NTAPI
+DbgLoadImageSymbols(
+ _In_ PSTRING Name,
+ _In_ PVOID Base,
+ _In_ ULONG_PTR ProcessId
+);
+
+VOID
+NTAPI
+DbgUnLoadImageSymbols(
+ _In_ PSTRING Name,
+ _In_ PVOID Base,
+ _In_ ULONG_PTR ProcessId
+);
+
+VOID
+NTAPI
+DbgCommandString(
+ _In_ PCCH Name,
+ _In_ PCCH Command
+);
+
+//
+// Generic Table Functions
+//
+#if defined(NTOS_MODE_USER) || defined(_NTIFS_)
+NTSYSAPI
+PVOID
+NTAPI
+RtlInsertElementGenericTable(
+ _In_ PRTL_GENERIC_TABLE Table,
+ _In_reads_bytes_(BufferSize) PVOID Buffer,
+ _In_ CLONG BufferSize,
+ _Out_opt_ PBOOLEAN NewElement
+);
+
+NTSYSAPI
+PVOID
+NTAPI
+RtlInsertElementGenericTableFull(
+ _In_ PRTL_GENERIC_TABLE Table,
+ _In_reads_bytes_(BufferSize) PVOID Buffer,
+ _In_ CLONG BufferSize,
+ _Out_opt_ PBOOLEAN NewElement,
+ _In_ PVOID NodeOrParent,
+ _In_ TABLE_SEARCH_RESULT SearchResult
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlIsGenericTableEmpty(
+ _In_ PRTL_GENERIC_TABLE Table
+);
+
+NTSYSAPI
+PVOID
+NTAPI
+RtlLookupElementGenericTableFull(
+ _In_ PRTL_GENERIC_TABLE Table,
+ _In_ PVOID Buffer,
+ _Out_ PVOID *NodeOrParent,
+ _Out_ TABLE_SEARCH_RESULT *SearchResult
+);
+#endif
+
+//
+// Handle Table Functions
+//
+NTSYSAPI
+PRTL_HANDLE_TABLE_ENTRY
+NTAPI
+RtlAllocateHandle(
+ _In_ PRTL_HANDLE_TABLE HandleTable,
+ _Inout_ PULONG Index
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlDestroyHandleTable(
+ _Inout_ PRTL_HANDLE_TABLE HandleTable);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlFreeHandle(
+ _In_ PRTL_HANDLE_TABLE HandleTable,
+ _In_ PRTL_HANDLE_TABLE_ENTRY Handle
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlInitializeHandleTable(
+ _In_ ULONG TableSize,
+ _In_ ULONG HandleSize,
+ _In_ PRTL_HANDLE_TABLE HandleTable
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlIsValidHandle(
+ _In_ PRTL_HANDLE_TABLE HandleTable,
+ _In_ PRTL_HANDLE_TABLE_ENTRY Handle
+);
+
+_Success_(return!=FALSE)
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlIsValidIndexHandle(
+ _In_ PRTL_HANDLE_TABLE HandleTable,
+ _In_ ULONG Index,
+ _Out_ PRTL_HANDLE_TABLE_ENTRY *Handle
+);
+
+//
+// PE Functions
+//
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlFindMessage(
+ _In_ PVOID BaseAddress,
+ _In_ ULONG Type,
+ _In_ ULONG Language,
+ _In_ ULONG MessageId,
+ _Out_ PMESSAGE_RESOURCE_ENTRY *MessageResourceEntry
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlGetNtGlobalFlags(VOID);
+
+_Success_(return!=NULL)
+NTSYSAPI
+PVOID
+NTAPI
+RtlImageDirectoryEntryToData(
+ _In_ PVOID BaseAddress,
+ _In_ BOOLEAN MappedAsImage,
+ _In_ USHORT Directory,
+ _Out_ PULONG Size
+);
+
+NTSYSAPI
+PVOID
+NTAPI
+RtlImageRvaToVa(
+ _In_ PIMAGE_NT_HEADERS NtHeader,
+ _In_ PVOID BaseAddress,
+ _In_ ULONG Rva,
+ _Inout_opt_ PIMAGE_SECTION_HEADER *SectionHeader
+);
+
+NTSYSAPI
+PIMAGE_NT_HEADERS
+NTAPI
+RtlImageNtHeader(
+ _In_ PVOID BaseAddress);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlImageNtHeaderEx(
+ _In_ ULONG Flags,
+ _In_ PVOID BaseAddress,
+ _In_ ULONGLONG Size,
+ _Out_ PIMAGE_NT_HEADERS *NtHeader
+);
+
+NTSYSAPI
+PIMAGE_SECTION_HEADER
+NTAPI
+RtlImageRvaToSection(
+ _In_ PIMAGE_NT_HEADERS NtHeader,
+ _In_ PVOID BaseAddress,
+ _In_ ULONG Rva
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+LdrRelocateImageWithBias(
+ _In_ PVOID NewAddress,
+ _In_ LONGLONG AdditionalBias,
+ _In_ PCCH LoaderName,
+ _In_ ULONG Success,
+ _In_ ULONG Conflict,
+ _In_ ULONG Invalid
+);
+
+//
+// Activation Context Functions
+//
+#ifdef NTOS_MODE_USER
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlActivateActivationContextEx(
+ _In_ ULONG Flags,
+ _In_ PTEB Teb,
+ _In_ PVOID Context,
+ _Out_ PULONG_PTR Cookie
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlActivateActivationContext(
+ _In_ ULONG Flags,
+ _In_ HANDLE Handle,
+ _Out_ PULONG_PTR Cookie
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlAddRefActivationContext(
+ _In_ PVOID Context
+);
+
+NTSYSAPI
+PRTL_ACTIVATION_CONTEXT_STACK_FRAME
+FASTCALL
+RtlActivateActivationContextUnsafeFast(
+ _In_ PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame,
+ _In_ PVOID Context
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlAllocateActivationContextStack(
+ _In_ PACTIVATION_CONTEXT_STACK *Stack
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCreateActivationContext(
+ _In_ ULONG Flags,
+ _In_ PACTIVATION_CONTEXT_DATA ActivationContextData,
+ _In_ ULONG ExtraBytes,
+ _In_ PVOID NotificationRoutine,
+ _In_ PVOID NotificationContext,
+ _Out_ PACTIVATION_CONTEXT *ActCtx
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlGetActiveActivationContext(
+ _In_ PVOID *Context
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlReleaseActivationContext(
+ _In_ HANDLE handle
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDeactivateActivationContext(
+ _In_ ULONG dwFlags,
+ _In_ ULONG_PTR ulCookie
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlFreeActivationContextStack(
+ _In_ PACTIVATION_CONTEXT_STACK Stack
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlFreeThreadActivationContextStack(VOID);
+
+NTSYSAPI
+PRTL_ACTIVATION_CONTEXT_STACK_FRAME
+FASTCALL
+RtlDeactivateActivationContextUnsafeFast(
+ _In_ PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlDosApplyFileIsolationRedirection_Ustr(
+ _In_ ULONG Flags,
+ _In_ PUNICODE_STRING OriginalName,
+ _In_ PUNICODE_STRING Extension,
+ _Inout_ PUNICODE_STRING StaticString,
+ _Inout_ PUNICODE_STRING DynamicString,
+ _Inout_ PUNICODE_STRING *NewName,
+ _In_ PULONG NewFlags,
+ _In_ PSIZE_T FileNameSize,
+ _In_ PSIZE_T RequiredLength
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlFindActivationContextSectionString(
+ _In_ ULONG dwFlags,
+ _In_ const GUID *ExtensionGuid,
+ _In_ ULONG SectionType,
++ _In_ const UNICODE_STRING *SectionName,
+ _Inout_ PVOID ReturnedData
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlQueryInformationActivationContext(
+ _In_ DWORD dwFlags,
+ _In_opt_ PVOID Context,
+ _In_opt_ PVOID pvSubInstance,
+ _In_ ULONG ulInfoClass,
+ _Out_bytecap_(cbBuffer) PVOID pvBuffer,
+ _In_opt_ SIZE_T cbBuffer,
+ _Out_opt_ SIZE_T *pcbWrittenOrRequired
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlQueryInformationActiveActivationContext(
+ _In_ ULONG ulInfoClass,
+ _Out_bytecap_(cbBuffer) PVOID pvBuffer,
+ _In_opt_ SIZE_T cbBuffer,
+ _Out_opt_ SIZE_T *pcbWrittenOrRequired
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlZombifyActivationContext(
+ PVOID Context
+);
+
+//
+// WOW64 Functions
+//
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlWow64EnableFsRedirection(
+ _In_ BOOLEAN Wow64FsEnableRedirection
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlWow64EnableFsRedirectionEx(
+ _In_ PVOID Wow64FsEnableRedirection,
+ _Out_ PVOID *OldFsRedirectionLevel
+);
+
+#endif
+
+//
+// Registry Functions
+//
+_IRQL_requires_max_(PASSIVE_LEVEL)
+_Must_inspect_result_
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCheckRegistryKey(
+ _In_ ULONG RelativeTo,
+ _In_ PWSTR Path
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCreateRegistryKey(
+ _In_ ULONG RelativeTo,
+ _In_ PWSTR Path
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlFormatCurrentUserKeyPath(
+ _Out_ _At_(KeyPath->Buffer, __drv_allocatesMem(Mem) _Post_bytecap_(KeyPath->MaximumLength) _Post_bytecount_(KeyPath->Length))
+ PUNICODE_STRING KeyPath
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlOpenCurrentUser(
+ _In_ ACCESS_MASK DesiredAccess,
+ _Out_ PHANDLE KeyHandle
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlQueryRegistryValues(
+ _In_ ULONG RelativeTo,
+ _In_ PCWSTR Path,
+ _Inout_ _At_(*(*QueryTable).EntryContext, _Pre_unknown_)
+ PRTL_QUERY_REGISTRY_TABLE QueryTable,
+ _In_opt_ PVOID Context,
+ _In_opt_ PVOID Environment
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlWriteRegistryValue(
+ _In_ ULONG RelativeTo,
+ _In_ PCWSTR Path,
+ _In_z_ PCWSTR ValueName,
+ _In_ ULONG ValueType,
+ _In_reads_bytes_opt_(ValueLength) PVOID ValueData,
+ _In_ ULONG ValueLength
+);
+
+#ifdef NTOS_MODE_USER
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlpNtCreateKey(
+ _Out_ HANDLE KeyHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ POBJECT_ATTRIBUTES ObjectAttributes,
+ _In_ ULONG TitleIndex,
+ _In_ PUNICODE_STRING Class,
+ _Out_ PULONG Disposition
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlpNtEnumerateSubKey(
+ _In_ HANDLE KeyHandle,
+ _Inout_ PUNICODE_STRING SubKeyName,
+ _In_ ULONG Index,
+ _In_ ULONG Unused
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlpNtMakeTemporaryKey(
+ _In_ HANDLE KeyHandle
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlpNtOpenKey(
+ _Out_ HANDLE KeyHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ POBJECT_ATTRIBUTES ObjectAttributes,
+ _In_ ULONG Unused
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlpNtQueryValueKey(
+ _In_ HANDLE KeyHandle,
+ _Out_opt_ PULONG Type,
+ _Out_opt_ PVOID Data,
+ _Inout_opt_ PULONG DataLength,
+ _In_ ULONG Unused
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlpNtSetValueKey(
+ _In_ HANDLE KeyHandle,
+ _In_ ULONG Type,
+ _In_ PVOID Data,
+ _In_ ULONG DataLength
+);
+#endif
+
+//
+// NLS Functions
+//
+NTSYSAPI
+VOID
+NTAPI
+RtlGetDefaultCodePage(
+ _Out_ PUSHORT AnsiCodePage,
+ _Out_ PUSHORT OemCodePage
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlInitNlsTables(
+ _In_ PUSHORT AnsiTableBase,
+ _In_ PUSHORT OemTableBase,
+ _In_ PUSHORT CaseTableBase,
+ _Out_ PNLSTABLEINFO NlsTable
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSYSAPI
+VOID
+NTAPI
+RtlInitCodePageTable(
+ _In_ PUSHORT TableBase,
+ _Out_ PCPTABLEINFO CodePageTable
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlResetRtlTranslations(
+ _In_ PNLSTABLEINFO NlsTable);
+
+#if defined(NTOS_MODE_USER) && !defined(NO_RTL_INLINES)
+
+//
+// Misc conversion functions
+//
+static __inline
+LARGE_INTEGER
+NTAPI_INLINE
+RtlConvertLongToLargeInteger(
+ _In_ LONG SignedInteger
+)
+{
+ LARGE_INTEGER Result;
+
+ Result.QuadPart = SignedInteger;
+ return Result;
+}
+
+static __inline
+LARGE_INTEGER
+NTAPI_INLINE
+RtlEnlargedIntegerMultiply(
+ _In_ LONG Multiplicand,
+ _In_ LONG Multiplier
+)
+{
+ LARGE_INTEGER Product;
+
+ Product.QuadPart = (LONGLONG)Multiplicand * (ULONGLONG)Multiplier;
+ return Product;
+}
+
+static __inline
+ULONG
+NTAPI_INLINE
+RtlEnlargedUnsignedDivide(
+ _In_ ULARGE_INTEGER Dividend,
+ _In_ ULONG Divisor,
+ _In_opt_ PULONG Remainder
+)
+{
+ ULONG Quotient;
+
+ Quotient = (ULONG)(Dividend.QuadPart / Divisor);
+ if (Remainder) {
+ *Remainder = (ULONG)(Dividend.QuadPart % Divisor);
+ }
+
+ return Quotient;
+}
+
+static __inline
+LARGE_INTEGER
+NTAPI_INLINE
+RtlEnlargedUnsignedMultiply(
+ _In_ ULONG Multiplicand,
+ _In_ ULONG Multiplier
+)
+{
+ LARGE_INTEGER Product;
+
+ Product.QuadPart = (ULONGLONG)Multiplicand * (ULONGLONG)Multiplier;
+ return Product;
+}
+
+#if defined(_AMD64_) || defined(_IA64_)
+static __inline
+LARGE_INTEGER
+NTAPI_INLINE
+RtlExtendedLargeIntegerDivide(
+ _In_ LARGE_INTEGER Dividend,
+ _In_ ULONG Divisor,
+ _Out_opt_ PULONG Remainder)
+{
+ LARGE_INTEGER ret;
+ ret.QuadPart = (ULONG64)Dividend.QuadPart / Divisor;
+ if (Remainder)
+ *Remainder = (ULONG)(Dividend.QuadPart % Divisor);
+ return ret;
+}
+
+#else
+NTSYSAPI
+LARGE_INTEGER
+NTAPI
+RtlExtendedLargeIntegerDivide(
+ _In_ LARGE_INTEGER Dividend,
+ _In_ ULONG Divisor,
+ _Out_opt_ PULONG Remainder
+);
+
+#endif /* defined(_AMD64_) || defined(_IA64_) */
+
+#endif
+
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlUniform(
+ _In_ PULONG Seed
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlRandom(
+ _Inout_ PULONG Seed
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlComputeCrc32(
+ _In_ ULONG InitialCrc,
+ _In_ PUCHAR Buffer,
+ _In_ ULONG Length
+);
+
+//
+// Network Functions
+//
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlIpv4StringToAddressA(
+ _In_ PCSTR String,
+ _In_ BOOLEAN Strict,
+ _Out_ PCSTR *Terminator,
+ _Out_ struct in_addr *Addr
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlIpv4StringToAddressW(
+ _In_ PCWSTR String,
+ _In_ BOOLEAN Strict,
+ _Out_ PCWSTR *Terminator,
+ _Out_ struct in_addr *Addr
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlIpv4StringToAddressExA(
+ _In_ PCSTR AddressString,
+ _In_ BOOLEAN Strict,
+ _Out_ struct in_addr *Address,
+ _Out_ PUSHORT Port
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlIpv4StringToAddressExW(
+ _In_ PCWSTR AddressString,
+ _In_ BOOLEAN Strict,
+ _Out_ struct in_addr *Address,
+ _Out_ PUSHORT Port
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlIpv6StringToAddressA(
+ _In_ PCHAR Name,
+ _Out_ PCHAR *Terminator,
+ _Out_ struct in6_addr *Addr
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlIpv6StringToAddressW(
+ _In_ PWCHAR Name,
+ _Out_ PCHAR *Terminator,
+ _Out_ struct in6_addr *Addr
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlIpv6StringToAddressExA(
+ _In_ PCHAR AddressString,
+ _In_ struct in6_addr *Address,
+ _In_ PULONG ScopeId,
+ _In_ PUSHORT Port
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlIpv6StringToAddressExW(
+ _In_ PWCHAR AddressName,
+ _In_ struct in6_addr *Address,
+ _In_ PULONG ScopeId,
+ _In_ PUSHORT Port
+);
+
+
+//
+// Time Functions
+//
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlQueryTimeZoneInformation(
+ _Out_ PRTL_TIME_ZONE_INFORMATION TimeZoneInformation);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlSecondsSince1970ToTime(
+ _In_ ULONG SecondsSince1970,
+ _Out_ PLARGE_INTEGER Time
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlSetTimeZoneInformation(
+ _In_ PRTL_TIME_ZONE_INFORMATION TimeZoneInformation);
+
+_Success_(return!=FALSE)
+_Must_inspect_result_
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlTimeFieldsToTime(
+ _In_ PTIME_FIELDS TimeFields,
+ _Out_ PLARGE_INTEGER Time
+);
+
+_Success_(return != 0)
+_Must_inspect_result_
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlTimeToSecondsSince1970(
+ _In_ PLARGE_INTEGER Time,
+ _Out_ PULONG ElapsedSeconds
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlTimeToTimeFields(
+ PLARGE_INTEGER Time,
+ PTIME_FIELDS TimeFields
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlSystemTimeToLocalTime(
+ _In_ PLARGE_INTEGER SystemTime,
+ _Out_ PLARGE_INTEGER LocalTime
+);
+
+//
+// Version Functions
+//
+_IRQL_requires_max_(PASSIVE_LEVEL)
+_Must_inspect_result_
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlVerifyVersionInfo(
+ _In_ PRTL_OSVERSIONINFOEXW VersionInfo,
+ _In_ ULONG TypeMask,
+ _In_ ULONGLONG ConditionMask
+);
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlGetVersion(
+ _Out_
+ _At_(lpVersionInformation->dwOSVersionInfoSize, _Pre_ _Valid_)
+ _When_(lpVersionInformation->dwOSVersionInfoSize == sizeof(RTL_OSVERSIONINFOEXW),
+ _At_((PRTL_OSVERSIONINFOEXW)lpVersionInformation, _Out_))
+ PRTL_OSVERSIONINFOW lpVersionInformation
+);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlGetNtProductType(OUT PNT_PRODUCT_TYPE ProductType);
+
+//
+// Secure Memory Functions
+//
+#ifdef NTOS_MODE_USER
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlRegisterSecureMemoryCacheCallback(
+ _In_ PRTL_SECURE_MEMORY_CACHE_CALLBACK Callback);
+
+NTSYSAPI
+BOOLEAN
+NTAPI
+RtlFlushSecureMemoryCache(
+ _In_ PVOID MemoryCache,
+ _In_opt_ SIZE_T MemoryLength
+);
+#endif
+
+//
+// Boot Status Data Functions
+//
+#ifdef NTOS_MODE_USER
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCreateBootStatusDataFile(
+ VOID
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlGetSetBootStatusData(
+ _In_ HANDLE FileHandle,
+ _In_ BOOLEAN WriteMode,
+ _In_ RTL_BSD_ITEM_TYPE DataClass,
+ _In_ PVOID Buffer,
+ _In_ ULONG BufferSize,
+ _Out_opt_ PULONG ReturnLength
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlLockBootStatusData(
+ _Out_ PHANDLE FileHandle
+);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlUnlockBootStatusData(
+ _In_ HANDLE FileHandle
+);
+#endif
+
+#ifdef NTOS_MODE_USER
+_Must_inspect_result_
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlGUIDFromString(
+ _In_ PUNICODE_STRING GuidString,
+ _Out_ GUID *Guid);
+
+_Must_inspect_result_
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlStringFromGUID(
+ _In_ REFGUID Guid,
+ _Out_ _At_(GuidString->Buffer, __drv_allocatesMem(Mem))
+ PUNICODE_STRING GuidString);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlComputeImportTableHash(
+ _In_ HANDLE hFile,
+ _Out_ PCHAR Hash,
+ _In_ ULONG ImportTableHashRevision
+);
+#endif
+
+//
+// MemoryStream functions
+//
+#ifdef NTOS_MODE_USER
+
+NTSYSAPI
+VOID
+NTAPI
+RtlInitMemoryStream(
+ _Out_ PRTL_MEMORY_STREAM Stream
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlInitOutOfProcessMemoryStream(
+ _Out_ PRTL_MEMORY_STREAM Stream
+);
+
+NTSYSAPI
+VOID
+NTAPI
+RtlFinalReleaseOutOfProcessMemoryStream(
+ _In_ PRTL_MEMORY_STREAM Stream
+);
+
+NTSYSAPI
+HRESULT
+NTAPI
+RtlQueryInterfaceMemoryStream(
+ _In_ struct IStream *This,
+ _In_ REFIID RequestedIid,
+ _Outptr_ PVOID *ResultObject
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlAddRefMemoryStream(
+ _In_ struct IStream *This
+);
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlReleaseMemoryStream(
+ _In_ struct IStream *This
+);
+
+NTSYSAPI
+HRESULT
+NTAPI
+RtlReadMemoryStream(
+ _In_ struct IStream *This,
+ _Out_writes_bytes_(Length) PVOID Buffer,
+ _In_ ULONG Length,
+ _Out_opt_ PULONG BytesRead
+);
+
+NTSYSAPI
+HRESULT
+NTAPI
+RtlReadOutOfProcessMemoryStream(
+ _In_ struct IStream *This,
+ _Out_writes_bytes_(Length) PVOID Buffer,
+ _In_ ULONG Length,
+ _Out_opt_ PULONG BytesRead
+);
+
+NTSYSAPI
+HRESULT
+NTAPI
+RtlSeekMemoryStream(
+ _In_ struct IStream *This,
+ _In_ LARGE_INTEGER RelativeOffset,
+ _In_ ULONG Origin,
+ _Out_opt_ PULARGE_INTEGER ResultOffset
+);
+
+NTSYSAPI
+HRESULT
+NTAPI
+RtlCopyMemoryStreamTo(
+ _In_ struct IStream *This,
+ _In_ struct IStream *Target,
+ _In_ ULARGE_INTEGER Length,
+ _Out_opt_ PULARGE_INTEGER BytesRead,
+ _Out_opt_ PULARGE_INTEGER BytesWritten
+);
+
+NTSYSAPI
+HRESULT
+NTAPI
+RtlCopyOutOfProcessMemoryStreamTo(
+ _In_ struct IStream *This,
+ _In_ struct IStream *Target,
+ _In_ ULARGE_INTEGER Length,
+ _Out_opt_ PULARGE_INTEGER BytesRead,
+ _Out_opt_ PULARGE_INTEGER BytesWritten
+);
+
+NTSYSAPI
+HRESULT
+NTAPI
+RtlStatMemoryStream(
+ _In_ struct IStream *This,
+ _Out_ struct tagSTATSTG *Stats,
+ _In_ ULONG Flags
+);
+
+// Dummy functions
+NTSYSAPI
+HRESULT
+NTAPI
+RtlWriteMemoryStream(
+ _In_ struct IStream *This,
+ _In_reads_bytes_(Length) CONST VOID *Buffer,
+ _In_ ULONG Length,
+ _Out_opt_ PULONG BytesWritten
+);
+
+NTSYSAPI
+HRESULT
+NTAPI
+RtlSetMemoryStreamSize(
+ _In_ struct IStream *This,
+ _In_ ULARGE_INTEGER NewSize
+);
+
+NTSYSAPI
+HRESULT
+NTAPI
+RtlCommitMemoryStream(
+ _In_ struct IStream *This,
+ _In_ ULONG CommitFlags
+);
+
+NTSYSAPI
+HRESULT
+NTAPI
+RtlRevertMemoryStream(
+ _In_ struct IStream *This
+);
+
+NTSYSAPI
+HRESULT
+NTAPI
+RtlLockMemoryStreamRegion(
+ _In_ struct IStream *This,
+ _In_ ULARGE_INTEGER Offset,
+ _In_ ULARGE_INTEGER Length,
+ _In_ ULONG LockType
+);
+
+NTSYSAPI
+HRESULT
+NTAPI
+RtlUnlockMemoryStreamRegion(
+ _In_ struct IStream *This,
+ _In_ ULARGE_INTEGER Offset,
+ _In_ ULARGE_INTEGER Length,
+ _In_ ULONG LockType
+);
+
+NTSYSAPI
+HRESULT
+NTAPI
+RtlCloneMemoryStream(
+ _In_ struct IStream *This,
+ _Outptr_ struct IStream **ResultStream
+);
+
+#endif // NTOS_MODE_USER
+
++NTSYSAPI
++NTSTATUS
++NTAPI
++RtlFindActivationContextSectionGuid(
++ ULONG flags,
++ const GUID *extguid,
++ ULONG section_kind,
++ const GUID *guid,
++ void *ptr
++);
++
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
- HANDLE OutputHandle;
-
- BOOL Unicode;
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Console Server DLL
+ * FILE: include/reactos/subsys/win/conmsg.h
+ * PURPOSE: Public definitions for communication
+ * between Console API Clients and Servers
+ * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
+ */
+
+#ifndef _CONMSG_H
+#define _CONMSG_H
+
+#pragma once
+
+#define CONSRV_SERVERDLL_INDEX 2
+#define CONSRV_FIRST_API_NUMBER 512
+
+// Windows Server 2003 table from http://j00ru.vexillium.org/csrss_list/api_list.html#Windows_2k3
+typedef enum _CONSRV_API_NUMBER
+{
+ ConsolepOpenConsole = CONSRV_FIRST_API_NUMBER,
+ ConsolepGetConsoleInput,
+ ConsolepWriteConsoleInput,
+ ConsolepReadConsoleOutput,
+ ConsolepWriteConsoleOutput,
+ ConsolepReadConsoleOutputString,
+ ConsolepWriteConsoleOutputString,
+ ConsolepFillConsoleOutput,
+ ConsolepGetMode,
+ ConsolepGetNumberOfFonts,
+ ConsolepGetNumberOfInputEvents,
+ ConsolepGetScreenBufferInfo,
+ ConsolepGetCursorInfo,
+ ConsolepGetMouseInfo,
+ ConsolepGetFontInfo,
+ ConsolepGetFontSize,
+ ConsolepGetCurrentFont,
+ ConsolepSetMode,
+ ConsolepSetActiveScreenBuffer,
+ ConsolepFlushInputBuffer,
+ ConsolepGetLargestWindowSize,
+ ConsolepSetScreenBufferSize,
+ ConsolepSetCursorPosition,
+ ConsolepSetCursorInfo,
+ ConsolepSetWindowInfo,
+ ConsolepScrollScreenBuffer,
+ ConsolepSetTextAttribute,
+ ConsolepSetFont,
+ ConsolepSetIcon,
+ ConsolepReadConsole,
+ ConsolepWriteConsole,
+ ConsolepDuplicateHandle,
+ ConsolepGetHandleInformation,
+ ConsolepSetHandleInformation,
+ ConsolepCloseHandle,
+ ConsolepVerifyIoHandle,
+ ConsolepAlloc, // Not present in Win7
+ ConsolepFree, // Not present in Win7
+ ConsolepGetTitle,
+ ConsolepSetTitle,
+ ConsolepCreateScreenBuffer,
+ ConsolepInvalidateBitMapRect,
+ ConsolepVDMOperation,
+ ConsolepSetCursor,
+ ConsolepShowCursor,
+ ConsolepMenuControl,
+ ConsolepSetPalette,
+ ConsolepSetDisplayMode,
+ ConsolepRegisterVDM,
+ ConsolepGetHardwareState,
+ ConsolepSetHardwareState,
+ ConsolepGetDisplayMode,
+ ConsolepAddAlias,
+ ConsolepGetAlias,
+ ConsolepGetAliasesLength,
+ ConsolepGetAliasExesLength,
+ ConsolepGetAliases,
+ ConsolepGetAliasExes,
+ ConsolepExpungeCommandHistory,
+ ConsolepSetNumberOfCommands,
+ ConsolepGetCommandHistoryLength,
+ ConsolepGetCommandHistory,
+ ConsolepSetCommandHistoryMode, // Not present in Vista+
+ ConsolepGetCP,
+ ConsolepSetCP,
+ ConsolepSetKeyShortcuts,
+ ConsolepSetMenuClose,
+ ConsolepNotifyLastClose,
+ ConsolepGenerateCtrlEvent,
+ ConsolepGetKeyboardLayoutName,
+ ConsolepGetConsoleWindow,
+ ConsolepCharType,
+ ConsolepSetLocalEUDC,
+ ConsolepSetCursorMode,
+ ConsolepGetCursorMode,
+ ConsolepRegisterOS2,
+ ConsolepSetOS2OemFormat,
+ ConsolepGetNlsMode,
+ ConsolepSetNlsMode,
+ ConsolepRegisterConsoleIME, // Not present in Win7
+ ConsolepUnregisterConsoleIME, // Not present in Win7
+ // ConsolepQueryConsoleIME, // Added only in Vista and Win2k8, not present in Win7
+ ConsolepGetLangId,
+ ConsolepAttach, // Not present in Win7
+ ConsolepGetSelectionInfo,
+ ConsolepGetProcessList,
+
+ ConsolepGetHistory, // Added in Vista+
+ ConsolepSetHistory, // Added in Vista+
+ // ConsolepSetCurrentFont, // Added in Vista+
+ // ConsolepSetScreenBufferInfo, // Added in Vista+
+ // ConsolepClientConnect, // Added in Win7
+
+ ConsolepMaxApiNumber
+} CONSRV_API_NUMBER, *PCONSRV_API_NUMBER;
+
+//
+// See http://msdn.microsoft.com/en-us/library/windows/desktop/bb773359(v=vs.85).aspx
+//
+typedef struct _CONSOLE_PROPERTIES
+{
+ WORD wFillAttribute;
+ WORD wPopupFillAttribute;
+
+ //
+ // Not on MSDN, but show up in binary
+ //
+ WORD wShowWindow;
+ WORD wUnknown;
+
+ COORD dwScreenBufferSize;
+ COORD dwWindowSize;
+ COORD dwWindowOrigin;
+ DWORD nFont;
+ DWORD nInputBufferSize;
+ COORD dwFontSize;
+ UINT uFontFamily;
+ UINT uFontWeight;
+ WCHAR FaceName[LF_FACESIZE];
+ UINT uCursorSize;
+ BOOL bFullScreen;
+ BOOL bQuickEdit;
+ BOOL bInsertMode;
+ BOOL bAutoPosition;
+ UINT uHistoryBufferSize;
+ UINT uNumberOfHistoryBuffers;
+ BOOL bHistoryNoDup;
+ COLORREF ColorTable[16];
+
+ //NT_FE_CONSOLE_PROPS
+ UINT uCodePage;
+} CONSOLE_PROPERTIES;
+
+//
+// To minimize code changes, some fields were put here even though they really only belong in
+// CONSRV_API_CONNECTINFO. Do not change the ordering however, as it's required for Windows
+// compatibility.
+//
+typedef struct _CONSOLE_START_INFO
+{
+ INT IconIndex;
+ HICON IconHandle1;
+ HICON IconHandle2;
+ DWORD dwHotKey;
+ DWORD dwStartupFlags;
+ CONSOLE_PROPERTIES;
+ BOOLEAN ConsoleNeeded; // Used for GUI apps only.
+ LPTHREAD_START_ROUTINE CtrlDispatcher;
+ LPTHREAD_START_ROUTINE ImeDispatcher;
+ LPTHREAD_START_ROUTINE PropDispatcher;
+ ULONG TitleLength;
+ WCHAR ConsoleTitle[MAX_PATH + 1]; // Console title or full path to the startup shortcut
+ ULONG DesktopLength;
+ PWCHAR DesktopPath;
+ ULONG AppNameLength;
+ WCHAR AppPath[128]; // Full path of the launched app
+ ULONG IconPathLength;
+ WCHAR IconPath[MAX_PATH + 1]; // Path to the file containing the icon
+} CONSOLE_START_INFO, *PCONSOLE_START_INFO;
+
+typedef struct _CONSRV_API_CONNECTINFO
+{
+ HANDLE ConsoleHandle;
+ HANDLE InputWaitHandle;
+ HANDLE InputHandle;
+ HANDLE OutputHandle;
+ HANDLE ErrorHandle;
+ HANDLE Event1;
+ HANDLE Event2;
+ /* Adapted from CONSOLE_ALLOCCONSOLE */
+ CONSOLE_START_INFO ConsoleStartInfo;
+} CONSRV_API_CONNECTINFO, *PCONSRV_API_CONNECTINFO;
+
+#if defined(_M_IX86)
+C_ASSERT(sizeof(CONSRV_API_CONNECTINFO) == 0x638);
+#endif
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ ULONG ProcessCount;
+ PDWORD ProcessIdsList;
+} CONSOLE_GETPROCESSLIST, *PCONSOLE_GETPROCESSLIST;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ DWORD CtrlEvent;
+ DWORD ProcessGroupId;
+} CONSOLE_GENERATECTRLEVENT, *PCONSOLE_GENERATECTRLEVENT;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+} CONSOLE_NOTIFYLASTCLOSE, *PCONSOLE_NOTIFYLASTCLOSE;
+
+
+
+typedef struct
+{
+ HANDLE OutputHandle;
+
+ BOOL Unicode;
+ ULONG NrCharactersToWrite;
+ ULONG NrCharactersWritten;
+
+ ULONG BufferSize;
+ PVOID Buffer;
+} CONSOLE_WRITECONSOLE, *PCONSOLE_WRITECONSOLE;
+
+typedef struct
+{
+ HANDLE InputHandle;
+
+ BOOL Unicode;
+ ULONG NrCharactersToRead;
+ ULONG NrCharactersRead;
+
+ UNICODE_STRING ExeName;
+ DWORD CtrlWakeupMask;
+ DWORD ControlKeyState;
+
+ ULONG BufferSize;
+ PVOID Buffer;
+} CONSOLE_READCONSOLE, *PCONSOLE_READCONSOLE;
+
+typedef struct
+{
+ PCONSOLE_START_INFO ConsoleStartInfo;
+
+ HANDLE ConsoleHandle;
+ HANDLE InputHandle;
+ HANDLE OutputHandle;
+ HANDLE ErrorHandle;
+ HANDLE InputWaitHandle;
+ LPTHREAD_START_ROUTINE CtrlDispatcher;
+ LPTHREAD_START_ROUTINE PropDispatcher;
+} CONSOLE_ALLOCCONSOLE, *PCONSOLE_ALLOCCONSOLE;
+
+typedef struct
+{
+ DWORD ProcessId; // If ProcessId == ATTACH_PARENT_PROCESS == -1, then attach the current process to its parent process console.
+ HANDLE ConsoleHandle;
+ HANDLE InputHandle;
+ HANDLE OutputHandle;
+ HANDLE ErrorHandle;
+ HANDLE InputWaitHandle;
+ LPTHREAD_START_ROUTINE CtrlDispatcher;
+ LPTHREAD_START_ROUTINE PropDispatcher;
+} CONSOLE_ATTACHCONSOLE, *PCONSOLE_ATTACHCONSOLE;
+
+typedef struct
+{
+ ULONG Dummy;
+} CONSOLE_FREECONSOLE, *PCONSOLE_FREECONSOLE;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE OutputHandle;
+ COORD ScreenBufferSize;
+ COORD CursorPosition;
+ COORD ViewOrigin;
+ WORD Attributes;
+ COORD ViewSize;
+ COORD MaximumViewSize;
+} CONSOLE_GETSCREENBUFFERINFO, *PCONSOLE_GETSCREENBUFFERINFO;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE OutputHandle;
+ COORD Position;
+} CONSOLE_SETCURSORPOSITION, *PCONSOLE_SETCURSORPOSITION;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE OutputHandle;
+ BOOL Show;
+ INT RefCount;
+} CONSOLE_SHOWCURSOR, *PCONSOLE_SHOWCURSOR;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE OutputHandle;
+ HCURSOR CursorHandle;
+} CONSOLE_SETCURSOR, *PCONSOLE_SETCURSOR;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE OutputHandle;
+ CONSOLE_CURSOR_INFO Info;
+/*
+ DWORD Size;
+ BOOLEAN Visible;
+*/
+} CONSOLE_GETSETCURSORINFO, *PCONSOLE_GETSETCURSORINFO;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE OutputHandle;
+ WORD Attributes;
+} CONSOLE_SETTEXTATTRIB, *PCONSOLE_SETTEXTATTRIB;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE Handle;
+ DWORD Mode;
+} CONSOLE_GETSETCONSOLEMODE, *PCONSOLE_GETSETCONSOLEMODE;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ DWORD DisplayMode; // ModeFlags
+} CONSOLE_GETDISPLAYMODE, *PCONSOLE_GETDISPLAYMODE;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE OutputHandle;
+ DWORD DisplayMode; // ModeFlags
+ COORD NewSBDim;
+ HANDLE EventHandle;
+} CONSOLE_SETDISPLAYMODE, *PCONSOLE_SETDISPLAYMODE;
+
+/*
+ * Console hardware states.
+ */
+#define CONSOLE_HARDWARE_STATE_GDI_MANAGED 0
+#define CONSOLE_HARDWARE_STATE_DIRECT 1
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE OutputHandle;
+ DWORD Flags;
+ DWORD State;
+} CONSOLE_GETSETHWSTATE, *PCONSOLE_GETSETHWSTATE;
+
+
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ DWORD DesiredAccess;
+ BOOL InheritHandle;
+ DWORD ShareMode;
+ DWORD ScreenBufferType; /* Type of the screen buffer: CONSOLE_TEXTMODE_BUFFER or CONSOLE_GRAPHICS_BUFFER */
+ /*
+ * This structure holds the initialization information
+ * for graphics screen buffers.
+ */
+ CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo;
+ HANDLE hMutex;
+ PVOID lpBitMap;
+ HANDLE OutputHandle; /* Handle to newly created screen buffer */
+} CONSOLE_CREATESCREENBUFFER, *PCONSOLE_CREATESCREENBUFFER;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE OutputHandle; /* Handle to screen buffer to switch to */
+} CONSOLE_SETACTIVESCREENBUFFER, *PCONSOLE_SETACTIVESCREENBUFFER;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE OutputHandle;
+ SMALL_RECT Region;
+} CONSOLE_INVALIDATEDIBITS, *PCONSOLE_INVALIDATEDIBITS;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE OutputHandle;
+ HPALETTE PaletteHandle;
+ UINT Usage;
+} CONSOLE_SETPALETTE, *PCONSOLE_SETPALETTE;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ DWORD Length;
+ PVOID Title;
+ BOOLEAN Unicode;
+} CONSOLE_GETSETCONSOLETITLE, *PCONSOLE_GETSETCONSOLETITLE;
+
+typedef struct
+{
+ HANDLE OutputHandle;
+
+ BOOL Unicode;
+ COORD BufferSize;
+ COORD BufferCoord;
+ SMALL_RECT WriteRegion;
+ PCHAR_INFO CharInfo;
+} CONSOLE_WRITEOUTPUT, *PCONSOLE_WRITEOUTPUT;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE InputHandle;
+} CONSOLE_FLUSHINPUTBUFFER, *PCONSOLE_FLUSHINPUTBUFFER;
+
+typedef struct
+{
- BOOL UseClipRectangle;
++ HANDLE ConsoleHandle;
++ HANDLE OutputHandle;
+ SMALL_RECT ScrollRectangle;
- COORD DestinationOrigin;
- CHAR_INFO Fill;
+ SMALL_RECT ClipRectangle;
- DWORD Length;
- DWORD ExeLength;
- LPWSTR ExeName;
++ BOOL UseClipRectangle;
++ COORD DestinationOrigin;
++ CHAR_INFO Fill;
++ BOOLEAN Unicode;
+} CONSOLE_SCROLLSCREENBUFFER, *PCONSOLE_SCROLLSCREENBUFFER;
+
+
+/*
+ * An attribute or a character are instances of the same entity, namely
+ * a "code" (what would be called an (ANSI) escape sequence). Therefore
+ * encode them inside the same structure.
+ */
+typedef enum _CODE_TYPE
+{
+ CODE_ASCII = 0x01,
+ CODE_UNICODE = 0x02,
+ CODE_ATTRIBUTE = 0x03
+} CODE_TYPE;
+
+typedef struct
+{
+ HANDLE OutputHandle;
+
+ DWORD NumCodesToRead;
+ COORD ReadCoord;
+ COORD EndCoord;
+
+ DWORD CodesRead;
+
+ CODE_TYPE CodeType;
+ union
+ {
+ PVOID pCode;
+ PCHAR AsciiChar;
+ PWCHAR UnicodeChar;
+ PWORD Attribute;
+ } pCode; // Either a pointer to a character or to an attribute.
+} CONSOLE_READOUTPUTCODE, *PCONSOLE_READOUTPUTCODE;
+
+typedef struct
+{
+ HANDLE OutputHandle;
+
+ ULONG BufferSize; // Seems unusued
+ WORD Length;
+ COORD Coord;
+ COORD EndCoord;
+
+ ULONG NrCharactersWritten; // Seems unusued
+
+ CODE_TYPE CodeType;
+ union
+ {
+ PVOID pCode;
+ PCHAR AsciiChar;
+ PWCHAR UnicodeChar;
+ PWORD Attribute;
+ } pCode; // Either a pointer to a character or to an attribute.
+} CONSOLE_WRITEOUTPUTCODE, *PCONSOLE_WRITEOUTPUTCODE;
+
+typedef struct
+{
+ HANDLE OutputHandle;
+
+ CODE_TYPE CodeType;
+ union
+ {
+ CHAR AsciiChar;
+ WCHAR UnicodeChar;
+ WORD Attribute;
+ } Code; // Either a character or an attribute.
+
+ COORD Coord;
+ ULONG Length;
+
+ ULONG NrCharactersWritten; // FIXME: Only for chars, is it removable ?
+} CONSOLE_FILLOUTPUTCODE, *PCONSOLE_FILLOUTPUTCODE;
+
+typedef struct
+{
+ HANDLE InputHandle;
+ ULONG InputsRead;
+ PINPUT_RECORD InputRecord;
+ ULONG Length;
+ WORD wFlags;
+ BOOLEAN Unicode;
+} CONSOLE_GETINPUT, *PCONSOLE_GETINPUT;
+
+typedef struct
+{
+ HANDLE OutputHandle;
+
+ BOOL Unicode;
+ COORD BufferSize;
+ COORD BufferCoord;
+ SMALL_RECT ReadRegion;
+ PCHAR_INFO CharInfo;
+} CONSOLE_READOUTPUT, *PCONSOLE_READOUTPUT;
+
+typedef struct
+{
+ HANDLE InputHandle;
+ DWORD Length;
+ INPUT_RECORD* InputRecord;
+ BOOL Unicode;
+ BOOL AppendToEnd;
+} CONSOLE_WRITEINPUT, *PCONSOLE_WRITEINPUT;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE InputHandle;
+ DWORD NumberOfEvents;
+} CONSOLE_GETNUMINPUTEVENTS, *PCONSOLE_GETNUMINPUTEVENTS;
+
+
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE Handle;
+} CONSOLE_CLOSEHANDLE, *PCONSOLE_CLOSEHANDLE;
+
+typedef struct
+{
+ BOOL IsValid;
+ HANDLE ConsoleHandle;
+ HANDLE Handle;
+} CONSOLE_VERIFYHANDLE, *PCONSOLE_VERIFYHANDLE;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE SourceHandle;
+ DWORD DesiredAccess;
+ BOOLEAN InheritHandle;
+ DWORD Options;
+ HANDLE TargetHandle;
+} CONSOLE_DUPLICATEHANDLE, *PCONSOLE_DUPLICATEHANDLE;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE Handle;
+ DWORD Flags;
+} CONSOLE_GETHANDLEINFO, *PCONSOLE_GETHANDLEINFO;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE Handle;
+ DWORD Mask;
+ DWORD Flags;
+} CONSOLE_SETHANDLEINFO, *PCONSOLE_SETHANDLEINFO;
+
+/*
+ * Type of handles.
+ */
+typedef enum _CONSOLE_HANDLE_TYPE
+{
+ HANDLE_INPUT = 0x01,
+ HANDLE_OUTPUT = 0x02
+} CONSOLE_HANDLE_TYPE;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ CONSOLE_HANDLE_TYPE HandleType;
+ DWORD DesiredAccess;
+ BOOL InheritHandle;
+ DWORD ShareMode;
+ HANDLE Handle;
+} CONSOLE_OPENCONSOLE, *PCONSOLE_OPENCONSOLE;
+
+
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE OutputHandle;
+ COORD Size;
+} CONSOLE_GETLARGESTWINDOWSIZE, *PCONSOLE_GETLARGESTWINDOWSIZE;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE OutputHandle;
+ DWORD CmdIdLow;
+ DWORD CmdIdHigh;
+ HMENU MenuHandle;
+} CONSOLE_MENUCONTROL, *PCONSOLE_MENUCONTROL;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ BOOL Enable;
+} CONSOLE_SETMENUCLOSE, *PCONSOLE_SETMENUCLOSE;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE OutputHandle;
+ BOOL Absolute;
+ SMALL_RECT WindowRect; // New console window position in the screen-buffer frame (Absolute == TRUE)
+ // or in the old window position frame (Absolute == FALSE).
+} CONSOLE_SETWINDOWINFO, *PCONSOLE_SETWINDOWINFO;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HWND WindowHandle;
+} CONSOLE_GETWINDOW, *PCONSOLE_GETWINDOW;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HICON IconHandle;
+} CONSOLE_SETICON, *PCONSOLE_SETICON;
+
+
+
+typedef struct
+{
+ ULONG SourceLength;
+ ULONG TargetLength; // Also used for storing the number of bytes written.
+ ULONG ExeLength;
+ LPWSTR Source;
+ LPWSTR Target;
+ LPWSTR Exe;
+} CONSOLE_ADDGETALIAS, *PCONSOLE_ADDGETALIAS;
+
+typedef struct
+{
+ DWORD ExeLength;
+ DWORD AliasesBufferLength;
+ LPWSTR ExeName;
+ LPWSTR AliasesBuffer;
+} CONSOLE_GETALLALIASES, *PCONSOLE_GETALLALIASES;
+
+typedef struct
+{
- DWORD Length;
- LPWSTR ExeNames;
++ HANDLE ConsoleHandle;
++ USHORT ExeLength;
++ PVOID ExeName;
++ ULONG Length;
++ BOOLEAN Unicode;
++ BOOLEAN Unicode2;
+} CONSOLE_GETALLALIASESLENGTH, *PCONSOLE_GETALLALIASESLENGTH;
+
+typedef struct
+{
- DWORD Length;
++ HANDLE ConsoleHandle;
++ ULONG Length ; // ExeLength; // ExesLength
++ PVOID ExeNames;
++ BOOLEAN Unicode;
+} CONSOLE_GETALIASESEXES, *PCONSOLE_GETALIASESEXES;
+
+typedef struct
+{
- UINT HistoryBufferSize;
- UINT NumberOfHistoryBuffers;
- DWORD dwFlags;
- } CONSOLE_GETSETHISTORYINFO, *PCONSOLE_GETSETHISTORYINFO;
++ HANDLE ConsoleHandle;
++ ULONG Length;
++ BOOLEAN Unicode;
+} CONSOLE_GETALIASESEXESLENGTH, *PCONSOLE_GETALIASESEXESLENGTH;
+
+
+
+typedef struct
+{
+ UNICODE_STRING ExeName;
+ PWCHAR History;
+ DWORD Length;
+} CONSOLE_GETCOMMANDHISTORY, *PCONSOLE_GETCOMMANDHISTORY;
+
+typedef struct
+{
+ UNICODE_STRING ExeName;
+ DWORD Length;
+} CONSOLE_GETCOMMANDHISTORYLENGTH, *PCONSOLE_GETCOMMANDHISTORYLENGTH;
+
+typedef struct
+{
+ UNICODE_STRING ExeName;
+} CONSOLE_EXPUNGECOMMANDHISTORY, *PCONSOLE_EXPUNGECOMMANDHISTORY;
+
++typedef struct
++{
++ UINT HistoryBufferSize;
++ UINT NumberOfHistoryBuffers;
++ DWORD dwFlags;
++} CONSOLE_GETSETHISTORYINFO, *PCONSOLE_GETSETHISTORYINFO;
++
+typedef struct
+{
+ UNICODE_STRING ExeName;
+ DWORD NumCommands;
+} CONSOLE_SETHISTORYNUMBERCOMMANDS, *PCONSOLE_SETHISTORYNUMBERCOMMANDS;
+
+typedef struct
+{
- CONSOLE_SETHISTORYNUMBERCOMMANDS SetHistoryNumberCommandsRequest;
++ HANDLE ConsoleHandle;
++ ULONG Mode;
++} CONSOLE_SETHISTORYMODE, *PCONSOLE_SETHISTORYMODE;
+
+
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ HANDLE OutputHandle;
+ COORD Size;
+} CONSOLE_SETSCREENBUFFERSIZE, *PCONSOLE_SETSCREENBUFFERSIZE;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ CONSOLE_SELECTION_INFO Info;
+} CONSOLE_GETSELECTIONINFO, *PCONSOLE_GETSELECTIONINFO;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ UINT CodePage;
+ BOOL OutputCP; // TRUE : Output Code Page ; FALSE : Input Code Page
+} CONSOLE_GETINPUTOUTPUTCP, *PCONSOLE_GETINPUTOUTPUTCP;
+
+typedef struct
+{
+ HANDLE ConsoleHandle;
+ UINT CodePage;
+ BOOL OutputCP; // TRUE : Output Code Page ; FALSE : Input Code Page
+ HANDLE EventHandle;
+} CONSOLE_SETINPUTOUTPUTCP, *PCONSOLE_SETINPUTOUTPUTCP;
+
+typedef struct _CONSOLE_API_MESSAGE
+{
+ PORT_MESSAGE Header;
+
+ PCSR_CAPTURE_BUFFER CsrCaptureData;
+ CSR_API_NUMBER ApiNumber;
+ NTSTATUS Status;
+ ULONG Reserved;
+ union
+ {
+ /* Console initialization and uninitialization */
+ CONSOLE_ALLOCCONSOLE AllocConsoleRequest;
+ CONSOLE_ATTACHCONSOLE AttachConsoleRequest;
+ CONSOLE_FREECONSOLE FreeConsoleRequest;
+
+ /* Processes */
+ CONSOLE_GETPROCESSLIST GetProcessListRequest;
+ CONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest;
+ CONSOLE_NOTIFYLASTCLOSE NotifyLastCloseRequest;
+
+ /* Handles */
+ CONSOLE_OPENCONSOLE OpenConsoleRequest;
+ CONSOLE_CLOSEHANDLE CloseHandleRequest;
+ CONSOLE_VERIFYHANDLE VerifyHandleRequest;
+ CONSOLE_DUPLICATEHANDLE DuplicateHandleRequest;
+ CONSOLE_GETHANDLEINFO GetHandleInfoRequest;
+ CONSOLE_SETHANDLEINFO SetHandleInfoRequest;
+
+ /* Cursor */
+ CONSOLE_SHOWCURSOR ShowCursorRequest;
+ CONSOLE_SETCURSOR SetCursorRequest;
+ CONSOLE_GETSETCURSORINFO CursorInfoRequest;
+ CONSOLE_SETCURSORPOSITION SetCursorPositionRequest;
+
+ /* Screen-buffer */
+ CONSOLE_CREATESCREENBUFFER CreateScreenBufferRequest;
+ CONSOLE_SETACTIVESCREENBUFFER SetScreenBufferRequest;
+ CONSOLE_GETSCREENBUFFERINFO ScreenBufferInfoRequest;
+ CONSOLE_SETSCREENBUFFERSIZE SetScreenBufferSizeRequest;
+ CONSOLE_SCROLLSCREENBUFFER ScrollScreenBufferRequest;
+
+ CONSOLE_GETSELECTIONINFO GetSelectionInfoRequest;
+ CONSOLE_FLUSHINPUTBUFFER FlushInputBufferRequest;
+
+ /* Console mode */
+ CONSOLE_GETSETCONSOLEMODE ConsoleModeRequest;
+ CONSOLE_GETDISPLAYMODE GetDisplayModeRequest;
+ CONSOLE_SETDISPLAYMODE SetDisplayModeRequest;
+ CONSOLE_GETSETHWSTATE HardwareStateRequest;
+
+ /* Console window */
+ CONSOLE_INVALIDATEDIBITS InvalidateDIBitsRequest;
+ CONSOLE_SETPALETTE SetPaletteRequest;
+ CONSOLE_GETSETCONSOLETITLE TitleRequest;
+ CONSOLE_GETLARGESTWINDOWSIZE GetLargestWindowSizeRequest;
+ CONSOLE_MENUCONTROL MenuControlRequest;
+ CONSOLE_SETMENUCLOSE SetMenuCloseRequest;
+ CONSOLE_SETWINDOWINFO SetWindowInfoRequest;
+ CONSOLE_GETWINDOW GetWindowRequest;
+ CONSOLE_SETICON SetIconRequest;
+
+ /* Read */
+ CONSOLE_READCONSOLE ReadConsoleRequest; // SrvReadConsole / ReadConsole
+ CONSOLE_GETINPUT GetInputRequest; // SrvGetConsoleInput / PeekConsoleInput & ReadConsoleInput
+ CONSOLE_READOUTPUT ReadOutputRequest; // SrvReadConsoleOutput / ReadConsoleOutput
+ CONSOLE_READOUTPUTCODE ReadOutputCodeRequest; // SrvReadConsoleOutputString / ReadConsoleOutputAttribute & ReadConsoleOutputCharacter
+ CONSOLE_GETNUMINPUTEVENTS GetNumInputEventsRequest;
+
+ /* Write */
+ CONSOLE_WRITECONSOLE WriteConsoleRequest; // SrvWriteConsole / WriteConsole
+ CONSOLE_WRITEINPUT WriteInputRequest;
+ CONSOLE_WRITEOUTPUT WriteOutputRequest;
+ CONSOLE_WRITEOUTPUTCODE WriteOutputCodeRequest;
+
+ CONSOLE_FILLOUTPUTCODE FillOutputRequest;
+ CONSOLE_SETTEXTATTRIB SetTextAttribRequest;
+
+ /* Aliases */
+ CONSOLE_ADDGETALIAS ConsoleAliasRequest;
+ CONSOLE_GETALLALIASES GetAllAliasesRequest;
+ CONSOLE_GETALLALIASESLENGTH GetAllAliasesLengthRequest;
+ CONSOLE_GETALIASESEXES GetAliasesExesRequest;
+ CONSOLE_GETALIASESEXESLENGTH GetAliasesExesLengthRequest;
+
+ /* History */
+ CONSOLE_GETCOMMANDHISTORY GetCommandHistoryRequest;
+ CONSOLE_GETCOMMANDHISTORYLENGTH GetCommandHistoryLengthRequest;
+ CONSOLE_EXPUNGECOMMANDHISTORY ExpungeCommandHistoryRequest;
+ CONSOLE_GETSETHISTORYINFO HistoryInfoRequest;
++ CONSOLE_SETHISTORYNUMBERCOMMANDS SetHistoryNumberCommandsRequest;
++ CONSOLE_SETHISTORYMODE SetHistoryModeRequest;
+
+ /* Input and Output Code Pages */
+ CONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest;
+ CONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest;
+ } Data;
+} CONSOLE_API_MESSAGE, *PCONSOLE_API_MESSAGE;
+
+// Check that a CONSOLE_API_MESSAGE can hold in a CSR_API_MESSAGE.
+CHECK_API_MSG_SIZE(CONSOLE_API_MESSAGE);
+
+#endif // _CONMSG_H
+
+/* EOF */
--- /dev/null
- #define interlocked_cmpxchg_ptr InterlockedCompareExchangePtr
+/*
+ * Wine porting definitions
+ *
+ * Copyright 1996 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_WINE_PORT_H
+#define __WINE_WINE_PORT_H
+
+#ifndef __WINE_CONFIG_H
+# error You must include config.h to use this header
+#endif
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE /* for pread/pwrite, isfinite */
+#endif
+#include <fcntl.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_DIRECT_H
+# include <direct.h>
+#endif
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+#ifdef HAVE_PROCESS_H
+# include <process.h>
+#endif
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+
+/****************************************************************
+ * Type definitions
+ */
+
+#if !defined(_MSC_VER) && !defined(__int64)
+# if defined(__x86_64__) || defined(_WIN64)
+# define __int64 long
+# else
+# define __int64 long long
+# endif
+#endif
+
+#if !defined(HAVE_MODE_T) && !defined(_MODE_T)
+typedef int mode_t;
+#endif
+#if !defined(HAVE_OFF_T) && !defined(_OFF_T)
+typedef long off_t;
+#endif
+#if !defined(HAVE_PID_T) && !defined(_PID_T)
+typedef int pid_t;
+#endif
+#if !defined(HAVE_SIZE_T) && !defined(_SIZE_T)
+typedef unsigned int size_t;
+#endif
+#if !defined(HAVE_SSIZE_T) && !defined(_SSIZE_T)
+typedef int ssize_t;
+#endif
+//#ifndef HAVE_SOCKLEN_T
+//typedef unsigned int socklen_t;
+//#endif
+
+#ifndef HAVE_STATFS
+# ifdef __BEOS__
+# define HAVE_STRUCT_STATFS_F_BFREE
+struct statfs {
+ long f_bsize; /* block_size */
+ long f_blocks; /* total_blocks */
+ long f_bfree; /* free_blocks */
+};
+# else /* defined(__BEOS__) */
+struct statfs;
+# endif /* defined(__BEOS__) */
+#endif /* !defined(HAVE_STATFS) */
+
+
+/****************************************************************
+ * Macro definitions
+ */
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#else
+#define RTLD_LAZY 0x001
+#define RTLD_NOW 0x002
+#define RTLD_GLOBAL 0x100
+#endif
+
+#if !defined(HAVE_FTRUNCATE) && defined(HAVE_CHSIZE)
+#define ftruncate chsize
+#endif
+
+#if !defined(HAVE_POPEN) && defined(HAVE__POPEN)
+#define popen _popen
+#endif
+
+#if !defined(HAVE_PCLOSE) && defined(HAVE__PCLOSE)
+#define pclose _pclose
+#endif
+
+#if !defined(HAVE_SNPRINTF) && defined(HAVE__SNPRINTF)
+#define snprintf _snprintf
+#endif
+
+#if !defined(HAVE_VSNPRINTF) && defined(HAVE__VSNPRINTF)
+#define vsnprintf _vsnprintf
+#endif
+
+#ifndef S_ISLNK
+# define S_ISLNK(mod) (0)
+#endif /* S_ISLNK */
+
+/* So we open files in 64 bit access mode on Linux */
+#ifndef O_LARGEFILE
+# define O_LARGEFILE 0
+#endif
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+/****************************************************************
+ * Constants
+ */
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#ifndef M_PI_2
+#define M_PI_2 1.570796326794896619
+#endif
+
+#ifndef M_PI_4
+#define M_PI_4 0.785398163397448309616
+#endif
+
+#ifndef INFINITY
+static inline float __port_infinity(void)
+{
+ static const unsigned __inf_bytes = 0x7f800000;
+ return *(const float *)&__inf_bytes;
+}
+#define INFINITY __port_infinity()
+#endif
+
+#ifndef NAN
+static inline float __port_nan(void)
+{
+ static const unsigned __nan_bytes = 0x7fc00000;
+ return *(const float *)&__nan_bytes;
+}
+#define NAN __port_nan()
+#endif
+
+/* Constructor functions */
+
+#ifdef _MSC_VER
+# define DECL_GLOBAL_CONSTRUCTOR(func) /* nothing */
+#elif defined(__GNUC__)
+# define DECL_GLOBAL_CONSTRUCTOR(func) \
+ static void func(void) __attribute__((constructor)); \
+ static void func(void)
+#elif defined(__i386__)
+# define DECL_GLOBAL_CONSTRUCTOR(func) \
+ static void __dummy_init_##func(void) { \
+ asm(".section .init,\"ax\"\n\t" \
+ "call " #func "\n\t" \
+ ".previous"); } \
+ static void func(void)
+#elif defined(__sparc__)
+# define DECL_GLOBAL_CONSTRUCTOR(func) \
+ static void __dummy_init_##func(void) { \
+ asm("\t.section \".init\",#alloc,#execinstr\n" \
+ "\tcall " #func "\n" \
+ "\tnop\n" \
+ "\t.section \".text\",#alloc,#execinstr\n" ); } \
+ static void func(void)
+#elif defined(_M_AMD64)
+#pragma message("You must define the DECL_GLOBAL_CONSTRUCTOR macro for amd64")
+#else
+# error You must define the DECL_GLOBAL_CONSTRUCTOR macro for your platform
+#endif
+
+
+/* Register functions */
+
+#ifdef __i386__
+#define DEFINE_REGS_ENTRYPOINT( name, fn, args, pop_args ) \
+ __ASM_GLOBAL_FUNC( name, \
+ "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t" \
+ ".long " __ASM_NAME(#fn) "\n\t" \
+ ".byte " #args "," #pop_args )
+/* FIXME: add support for other CPUs */
+#endif /* __i386__ */
+
+
+/****************************************************************
+ * Function definitions (only when using libwine_port)
+ */
+
+#ifndef NO_LIBWINE_PORT
+
+#ifndef HAVE_GETOPT_LONG
+extern char *optarg;
+extern int optind;
+extern int opterr;
+extern int optopt;
+struct option;
+
+#ifndef HAVE_STRUCT_OPTION_NAME
+struct option
+{
+ const char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+#endif
+
+extern int getopt_long (int ___argc, char *const *___argv,
+ const char *__shortopts,
+ const struct option *__longopts, int *__longind);
+extern int getopt_long_only (int ___argc, char *const *___argv,
+ const char *__shortopts,
+ const struct option *__longopts, int *__longind);
+#endif /* HAVE_GETOPT_LONG */
+
+#ifndef HAVE_GETPAGESIZE
+size_t getpagesize(void);
+#endif /* HAVE_GETPAGESIZE */
+
+#if !defined(HAVE_ISFINITE) && !defined(isfinite)
+int isfinite(double x);
+#endif
+
+#if !defined(HAVE_ISINF) && !defined(isinf)
+int isinf(double x);
+#endif
+
+#if !defined(HAVE_ISNAN) && !defined(isnan)
+int isnan(double x);
+#endif
+
+#ifndef HAVE_LSTAT
+int lstat(const char *file_name, struct stat *buf);
+#endif /* HAVE_LSTAT */
+
+#ifndef HAVE_MEMMOVE
+void *memmove(void *dest, const void *src, size_t len);
+#endif /* !defined(HAVE_MEMMOVE) */
+
+#ifndef __REACTOS__
+#ifndef HAVE_PREAD
+ssize_t pread( int fd, void *buf, size_t count, off_t offset );
+#endif /* HAVE_PREAD */
+
+#ifndef HAVE_PWRITE
+ssize_t pwrite( int fd, const void *buf, size_t count, off_t offset );
+#endif /* HAVE_PWRITE */
+#endif /* __REACTOS__ */
+
+#ifdef WIN32
+#ifndef HAVE_SIGSETJMP
+# include <setjmp.h>
+typedef jmp_buf sigjmp_buf;
+int sigsetjmp( sigjmp_buf buf, int savesigs );
+void siglongjmp( sigjmp_buf buf, int val );
+#endif /* HAVE_SIGSETJMP */
+#endif
+
+#ifndef HAVE_STATFS
+int statfs(const char *name, struct statfs *info);
+#endif /* !defined(HAVE_STATFS) */
+
+#ifndef HAVE_STRNCASECMP
+# ifndef HAVE__STRNICMP
+int strncasecmp(const char *str1, const char *str2, size_t n);
+# else
+# define strncasecmp _strnicmp
+# endif
+#endif /* !defined(HAVE_STRNCASECMP) */
+
+#ifndef HAVE_STRERROR
+const char *strerror(int err);
+#endif /* !defined(HAVE_STRERROR) */
+
+#ifndef HAVE_STRCASECMP
+# ifndef HAVE__STRICMP
+int strcasecmp(const char *str1, const char *str2);
+# else
+# define strcasecmp _stricmp
+# endif
+#endif /* !defined(HAVE_STRCASECMP) */
+
+#if !defined(HAVE_USLEEP) && !defined(__CYGWIN__)
+int usleep (unsigned int useconds);
+#endif /* !defined(HAVE_USLEEP) */
+
+#ifdef __i386__
+static inline void *memcpy_unaligned( void *dst, const void *src, size_t size )
+{
+ return memcpy( dst, src, size );
+}
+#else
+extern void *memcpy_unaligned( void *dst, const void *src, size_t size );
+#endif /* __i386__ */
+
+extern int mkstemps(char *template, int suffix_len);
+
+/* Process creation flags */
+#ifndef _P_WAIT
+# define _P_WAIT 0
+# define _P_NOWAIT 1
+# define _P_OVERLAY 2
+# define _P_NOWAITO 3
+# define _P_DETACH 4
+#endif
+#ifndef HAVE_SPAWNVP
+extern int spawnvp(int mode, const char *cmdname, const char * const argv[]);
+#endif
+
+/* Interlocked functions */
+
+#if defined(_MSC_VER) || (defined(__i386__) && defined(__GNUC__) && !defined(WINE_PORT_NO_INTERLOCKED))
+
+#define interlocked_cmpxchg InterlockedCompareExchange
- #define interlocked_xchg_ptr InterlockedExchangePtr
++#define interlocked_cmpxchg_ptr InterlockedCompareExchangePointer
+#define interlocked_xchg InterlockedExchange
++#define interlocked_xchg_ptr InterlockedExchangePointer
+#define interlocked_xchg_add InterlockedExchangeAdd
+
+
+#endif /* __i386___ && __GNUC__ */
+
+#if defined(_MSC_VER)
+__forceinline
+int
+ffs(int mask)
+{
+ long index;
+ if (_BitScanForward(&index, mask) == 0) return 0;
+ return index;
+}
+#else
+#define ffs __builtin_ffs
+#endif
+
+#else /* NO_LIBWINE_PORT */
+
+#define __WINE_NOT_PORTABLE(func) func##_is_not_portable func##_is_not_portable
+
+#define getopt_long __WINE_NOT_PORTABLE(getopt_long)
+#define getopt_long_only __WINE_NOT_PORTABLE(getopt_long_only)
+#define getpagesize __WINE_NOT_PORTABLE(getpagesize)
+#define lstat __WINE_NOT_PORTABLE(lstat)
+#define memcpy_unaligned __WINE_NOT_PORTABLE(memcpy_unaligned)
+#define memmove __WINE_NOT_PORTABLE(memmove)
+#define pread __WINE_NOT_PORTABLE(pread)
+#define pwrite __WINE_NOT_PORTABLE(pwrite)
+#define spawnvp __WINE_NOT_PORTABLE(spawnvp)
+#define statfs __WINE_NOT_PORTABLE(statfs)
+#define strcasecmp __WINE_NOT_PORTABLE(strcasecmp)
+#define strerror __WINE_NOT_PORTABLE(strerror)
+#define strncasecmp __WINE_NOT_PORTABLE(strncasecmp)
+#define usleep __WINE_NOT_PORTABLE(usleep)
+
+#endif /* NO_LIBWINE_PORT */
+
+#endif /* !defined(__WINE_WINE_PORT_H) */
--- /dev/null
- /* Based on Wine 1.1.26 */
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Runtime Library
+ * PURPOSE: Activation Context Support
+ * FILE: lib/rtl/actctx.c
+ * PROGRAMERS:
+ * Jon Griffiths
+ * Eric Pouech
+ * Jacek Caban for CodeWeavers
+ * Alexandre Julliard
+ * Stefan Ginsberg (stefan__100__@hotmail.com)
+ * Samuel Serapión
+ */
+
- ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID |\
- ACTCTX_FLAG_LANGID_VALID |\
- ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID |\
- ACTCTX_FLAG_RESOURCE_NAME_VALID |\
- ACTCTX_FLAG_SET_PROCESS_DEFAULT |\
- ACTCTX_FLAG_APPLICATION_NAME_VALID |\
- ACTCTX_FLAG_SOURCE_IS_ASSEMBLYREF |\
- ACTCTX_FLAG_HMODULE_VALID )
++/* Based on Wine 1.7.17 */
+
+#include <rtl.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include <wine/unicode.h>
+
+BOOLEAN RtlpNotAllowingMultipleActivation;
+
+#define ACTCTX_FLAGS_ALL (\
- WCHAR *version;
++ ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID |\
++ ACTCTX_FLAG_LANGID_VALID |\
++ ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID |\
++ ACTCTX_FLAG_RESOURCE_NAME_VALID |\
++ ACTCTX_FLAG_SET_PROCESS_DEFAULT |\
++ ACTCTX_FLAG_APPLICATION_NAME_VALID |\
++ ACTCTX_FLAG_SOURCE_IS_ASSEMBLYREF |\
++ ACTCTX_FLAG_HMODULE_VALID )
++
++#define STRSECTION_MAGIC 0x64487353 /* dHsS */
++#define GUIDSECTION_MAGIC 0x64487347 /* dHsG */
+
+#define ACTCTX_MAGIC_MARKER (PVOID)'gMcA'
+
+#define ACTCTX_FAKE_HANDLE ((HANDLE) 0xf00baa)
+#define ACTCTX_FAKE_COOKIE ((ULONG_PTR) 0xf00bad)
+
+
+
+typedef struct
+{
+ const WCHAR *ptr;
+ unsigned int len;
+} xmlstr_t;
+
+typedef struct
+{
+ const WCHAR *ptr;
+ const WCHAR *end;
+} xmlbuf_t;
+
+struct file_info
+{
+ ULONG type;
+ WCHAR *info;
+};
+
+struct assembly_version
+{
+ USHORT major;
+ USHORT minor;
+ USHORT build;
+ USHORT revision;
+};
+
+struct assembly_identity
+{
+ WCHAR *name;
+ WCHAR *arch;
+ WCHAR *public_key;
+ WCHAR *language;
+ WCHAR *type;
+ struct assembly_version version;
+ BOOL optional;
+};
+
++struct strsection_header
++{
++ DWORD magic;
++ ULONG size;
++ DWORD unk1[3];
++ ULONG count;
++ ULONG index_offset;
++ DWORD unk2[2];
++ ULONG global_offset;
++ ULONG global_len;
++};
++
++struct string_index
++{
++ ULONG hash; /* key string hash */
++ ULONG name_offset;
++ ULONG name_len;
++ ULONG data_offset; /* redirect data offset */
++ ULONG data_len;
++ ULONG rosterindex;
++};
++
++struct guidsection_header
++{
++ DWORD magic;
++ ULONG size;
++ DWORD unk[3];
++ ULONG count;
++ ULONG index_offset;
++ DWORD unk2;
++ ULONG names_offset;
++ ULONG names_len;
++};
++
++struct guid_index
++{
++ GUID guid;
++ ULONG data_offset;
++ ULONG data_len;
++ ULONG rosterindex;
++};
++
++struct wndclass_redirect_data
++{
++ ULONG size;
++ DWORD res;
++ ULONG name_len;
++ ULONG name_offset; /* versioned name offset */
++ ULONG module_len;
++ ULONG module_offset;/* container name offset */
++};
++
++struct dllredirect_data
++{
++ ULONG size;
++ ULONG unk;
++ DWORD res[3];
++};
++
++struct tlibredirect_data
++{
++ ULONG size;
++ DWORD res;
++ ULONG name_len;
++ ULONG name_offset;
++ LANGID langid;
++ WORD flags;
++ ULONG help_len;
++ ULONG help_offset;
++ WORD major_version;
++ WORD minor_version;
++};
++
++enum comclass_threadingmodel
++{
++ ThreadingModel_Apartment = 1,
++ ThreadingModel_Free = 2,
++ ThreadingModel_No = 3,
++ ThreadingModel_Both = 4,
++ ThreadingModel_Neutral = 5
++};
++
++enum comclass_miscfields
++{
++ MiscStatus = 1,
++ MiscStatusIcon = 2,
++ MiscStatusContent = 4,
++ MiscStatusThumbnail = 8,
++ MiscStatusDocPrint = 16
++};
++
++struct comclassredirect_data
++{
++ ULONG size;
++ BYTE res;
++ BYTE miscmask;
++ BYTE res1[2];
++ DWORD model;
++ GUID clsid;
++ GUID alias;
++ GUID clsid2;
++ GUID tlbid;
++ ULONG name_len;
++ ULONG name_offset;
++ ULONG progid_len;
++ ULONG progid_offset;
++ ULONG clrdata_len;
++ ULONG clrdata_offset;
++ DWORD miscstatus;
++ DWORD miscstatuscontent;
++ DWORD miscstatusthumbnail;
++ DWORD miscstatusicon;
++ DWORD miscstatusdocprint;
++};
++
++enum ifaceps_mask
++{
++ NumMethods = 1,
++ BaseIface = 2
++};
++
++struct ifacepsredirect_data
++{
++ ULONG size;
++ DWORD mask;
++ GUID iid;
++ ULONG nummethods;
++ GUID tlbid;
++ GUID base;
++ ULONG name_len;
++ ULONG name_offset;
++};
++
++struct clrsurrogate_data
++{
++ ULONG size;
++ DWORD res;
++ GUID clsid;
++ ULONG version_offset;
++ ULONG version_len;
++ ULONG name_offset;
++ ULONG name_len;
++};
++
++struct clrclass_data
++{
++ ULONG size;
++ DWORD res[2];
++ ULONG module_len;
++ ULONG module_offset;
++ ULONG name_len;
++ ULONG name_offset;
++ ULONG version_len;
++ ULONG version_offset;
++ DWORD res2[2];
++};
++
++struct progidredirect_data
++{
++ ULONG size;
++ DWORD reserved;
++ ULONG clsid_offset;
++};
++
++/*
++
++ Sections structure.
++
++ Sections are accessible by string or guid key, that defines two types of sections.
++ All sections of each type have same magic value and header structure, index
++ data could be of two possible types too. So every string based section uses
++ the same index format, same applies to guid sections - they share same guid index
++ format.
++
++ - window class redirection section is a plain buffer with following format:
++
++ <section header>
++ <index[]>
++ <data[]> --- <original name>
++ <redirect data>
++ <versioned name>
++ <module name>
++
++ Header is fixed length structure - struct strsection_header,
++ contains redirected classes count;
++
++ Index is an array of fixed length index records, each record is
++ struct string_index.
++
++ All strings in data itself are WCHAR, null terminated, 4-bytes aligned.
++
++ Versioned name offset is relative to redirect data structure (struct wndclass_redirect_data),
++ others are relative to section itself.
++
++ - dll redirect section format:
++
++ <section header>
++ <index[]>
++ <data[]> --- <dll name>
++ <data>
++
++ This section doesn't seem to carry any payload data except dll names.
++
++ - typelib section format:
++
++ <section header>
++ <module names[]>
++ <index[]>
++ <data[]> --- <data>
++ <helpstring>
++
++ Header is fixed length, index is an array of fixed length 'struct guid_index'.
++ All strings are WCHAR, null terminated, 4-bytes aligned. Module names part is
++ 4-bytes aligned as a whole.
++
++ Module name offsets are relative to section, helpstring offset is relative to data
++ structure itself.
++
++ - comclass section format:
++
++ <section header>
++ <module names[]>
++ <index[]>
++ <data[]> --- <data> --- <data>
++ <progid> <clrdata>
++ <name>
++ <version>
++ <progid>
++
++ This section uses two index records per comclass, one entry contains original guid
++ as specified by context, another one has a generated guid. Index and strings handling
++ is similar to typelib sections.
++
++ For CLR classes additional data is stored after main COM class data, it contains
++ class name and runtime version string, see 'struct clrclass_data'.
++
++ Module name offsets are relative to section, progid offset is relative to data
++ structure itself.
++
++ - COM interface section format:
++
++ <section header>
++ <index[]>
++ <data[]> --- <data>
++ <name>
++
++ Interface section contains data for proxy/stubs and external proxy/stubs. External
++ ones are defined at assembly level, so this section has no module information.
++ All records are indexed with 'iid' value from manifest. There an exception for
++ external variants - if 'proxyStubClsid32' is specified, it's stored as iid in
++ redirect data, but index is still 'iid' from manifest.
++
++ Interface name offset is relative to data structure itself.
++
++ - CLR surrogates section format:
++
++ <section header>
++ <index[]>
++ <data[]> --- <data>
++ <name>
++ <version>
++
++ There's nothing special about this section, same way to store strings is used,
++ no modules part as it belongs to assembly level, not a file.
++
++ - ProgID section format:
++
++ <section header>
++ <guids[]>
++ <index[]>
++ <data[]> --- <progid>
++ <data>
++
++ This sections uses generated alias guids from COM server section. This way
++ ProgID -> CLSID mapping returns generated guid, not the real one. ProgID string
++ is stored too, aligned.
++*/
++
++struct progids
++{
++ WCHAR **progids;
++ unsigned int num;
++ unsigned int allocated;
++};
++
+struct entity
+{
+ DWORD kind;
+ union
+ {
+ struct
+ {
+ WCHAR *tlbid;
- } typelib;
+ WCHAR *helpdir;
- } comclass;
- struct {
++ WORD flags;
++ WORD major;
++ WORD minor;
++ } typelib;
+ struct
+ {
+ WCHAR *clsid;
- } proxy;
++ WCHAR *tlbid;
++ WCHAR *progid;
++ WCHAR *name; /* clrClass: class name */
++ WCHAR *version; /* clrClass: CLR runtime version */
++ DWORD model;
++ DWORD miscstatus;
++ DWORD miscstatuscontent;
++ DWORD miscstatusthumbnail;
++ DWORD miscstatusicon;
++ DWORD miscstatusdocprint;
++ struct progids progids;
++ } comclass;
++ struct {
+ WCHAR *iid;
++ WCHAR *base;
++ WCHAR *tlib;
+ WCHAR *name;
- } clrclass;
- struct
- {
- WCHAR *name;
- WCHAR *clsid;
++ WCHAR *ps32; /* only stored for 'comInterfaceExternalProxyStub' */
++ DWORD mask;
++ ULONG nummethods;
++ } ifaceps;
+ struct
+ {
+ WCHAR *name;
++ BOOL versioned;
+ } class;
+ struct
+ {
+ WCHAR *name;
+ WCHAR *clsid;
- unsigned int i;
++ WCHAR *version;
+ } clrsurrogate;
+ } u;
+};
+
+struct entity_array
+{
+ struct entity *base;
+ unsigned int num;
+ unsigned int allocated;
+};
+
+struct dll_redirect
+{
+ WCHAR *name;
+ WCHAR *hash;
+ struct entity_array entities;
+};
+
+enum assembly_type
+{
+ APPLICATION_MANIFEST,
+ ASSEMBLY_MANIFEST,
+ ASSEMBLY_SHARED_MANIFEST,
+};
+
+struct assembly
+{
+ enum assembly_type type;
+ struct assembly_identity id;
+ struct file_info manifest;
+ WCHAR *directory;
+ BOOL no_inherit;
+ struct dll_redirect *dlls;
+ unsigned int num_dlls;
+ unsigned int allocated_dlls;
+ struct entity_array entities;
+};
+
++enum context_sections
++{
++ WINDOWCLASS_SECTION = 1,
++ DLLREDIRECT_SECTION = 2,
++ TLIBREDIRECT_SECTION = 4,
++ SERVERREDIRECT_SECTION = 8,
++ IFACEREDIRECT_SECTION = 16,
++ CLRSURROGATES_SECTION = 32,
++ PROGIDREDIRECT_SECTION = 64
++};
++
+typedef struct _ASSEMBLY_STORAGE_MAP_ENTRY
+{
+ ULONG Flags;
+ UNICODE_STRING DosPath;
+ HANDLE Handle;
+} ASSEMBLY_STORAGE_MAP_ENTRY, *PASSEMBLY_STORAGE_MAP_ENTRY;
+
+typedef struct _ASSEMBLY_STORAGE_MAP
+{
+ ULONG Flags;
+ ULONG AssemblyCount;
+ PASSEMBLY_STORAGE_MAP_ENTRY *AssemblyArray;
+} ASSEMBLY_STORAGE_MAP, *PASSEMBLY_STORAGE_MAP;
+
+typedef struct _ACTIVATION_CONTEXT
+{
+ LONG RefCount;
+ ULONG Flags;
+ LIST_ENTRY Links;
+ PACTIVATION_CONTEXT_DATA ActivationContextData;
+ PVOID NotificationRoutine;
+ PVOID NotificationContext;
+ ULONG SentNotifications[8];
+ ULONG DisabledNotifications[8];
+ ASSEMBLY_STORAGE_MAP StorageMap;
+ PASSEMBLY_STORAGE_MAP_ENTRY InlineStorageMapEntries;
+ ULONG StackTraceIndex;
+ PVOID StackTraces[4][4];
+ struct file_info config;
+ struct file_info appdir;
+ struct assembly *assemblies;
+ unsigned int num_assemblies;
+ unsigned int allocated_assemblies;
++ /* section data */
++ DWORD sections;
++ struct strsection_header *wndclass_section;
++ struct strsection_header *dllredirect_section;
++ struct strsection_header *progid_section;
++ struct guidsection_header *tlib_section;
++ struct guidsection_header *comserver_section;
++ struct guidsection_header *ifaceps_section;
++ struct guidsection_header *clrsurrogate_section;
+} ACTIVATION_CONTEXT, *PIACTIVATION_CONTEXT;
+
+struct actctx_loader
+{
+ ACTIVATION_CONTEXT *actctx;
+ struct assembly_identity *dependencies;
+ unsigned int num_dependencies;
+ unsigned int allocated_dependencies;
+};
+
+static const WCHAR asmv1W[] = {'a','s','m','v','1',':',0};
+static const WCHAR asmv2W[] = {'a','s','m','v','2',':',0};
+
+typedef struct _ACTIVATION_CONTEXT_WRAPPED
+{
+ PVOID MagicMarker;
+ ACTIVATION_CONTEXT ActivationContext;
+} ACTIVATION_CONTEXT_WRAPPED, *PACTIVATION_CONTEXT_WRAPPED;
+
+VOID
+NTAPI
+RtlpSxsBreakOnInvalidMarker(IN PACTIVATION_CONTEXT ActCtx,
+ IN ULONG FailureCode)
+{
+ EXCEPTION_RECORD ExceptionRecord;
+
+ /* Fatal SxS exception header */
+ ExceptionRecord.ExceptionRecord = NULL;
+ ExceptionRecord.ExceptionCode = STATUS_SXS_CORRUPTION;
+ ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
+
+ /* With SxS-specific information plus the context itself */
+ ExceptionRecord.ExceptionInformation[0] = 1;
+ ExceptionRecord.ExceptionInformation[1] = FailureCode;
+ ExceptionRecord.ExceptionInformation[2] = (ULONG_PTR)ActCtx;
+ ExceptionRecord.NumberParameters = 3;
+
+ /* Raise it */
+ RtlRaiseException(&ExceptionRecord);
+}
+
+FORCEINLINE
+VOID
+RtlpValidateActCtx(IN PACTIVATION_CONTEXT ActCtx)
+{
+ PACTIVATION_CONTEXT_WRAPPED pActual;
+
+ /* Get the caller-opaque header */
+ pActual = CONTAINING_RECORD(ActCtx,
+ ACTIVATION_CONTEXT_WRAPPED,
+ ActivationContext);
+
+ /* Check if the header matches as expected */
+ if (pActual->MagicMarker != ACTCTX_MAGIC_MARKER)
+ {
+ /* Nope, print out a warning, assert, and then throw an exception */
+ DbgPrint("%s : Invalid activation context marker %p found in activation context %p\n"
+ " This means someone stepped on the allocation, or someone is using a\n"
+ " deallocated activation context\n",
+ __FUNCTION__,
+ pActual->MagicMarker,
+ ActCtx);
+ ASSERT(pActual->MagicMarker == ACTCTX_MAGIC_MARKER);
+ RtlpSxsBreakOnInvalidMarker(ActCtx, 1);
+ }
+}
+
+static const WCHAR assemblyW[] = {'a','s','s','e','m','b','l','y',0};
+static const WCHAR assemblyIdentityW[] = {'a','s','s','e','m','b','l','y','I','d','e','n','t','i','t','y',0};
+static const WCHAR bindingRedirectW[] = {'b','i','n','d','i','n','g','R','e','d','i','r','e','c','t',0};
+static const WCHAR clrClassW[] = {'c','l','r','C','l','a','s','s',0};
+static const WCHAR clrSurrogateW[] = {'c','l','r','S','u','r','r','o','g','a','t','e',0};
+static const WCHAR comClassW[] = {'c','o','m','C','l','a','s','s',0};
+static const WCHAR comInterfaceExternalProxyStubW[] = {'c','o','m','I','n','t','e','r','f','a','c','e','E','x','t','e','r','n','a','l','P','r','o','x','y','S','t','u','b',0};
+static const WCHAR comInterfaceProxyStubW[] = {'c','o','m','I','n','t','e','r','f','a','c','e','P','r','o','x','y','S','t','u','b',0};
+static const WCHAR dependencyW[] = {'d','e','p','e','n','d','e','n','c','y',0};
+static const WCHAR dependentAssemblyW[] = {'d','e','p','e','n','d','e','n','t','A','s','s','e','m','b','l','y',0};
+static const WCHAR descriptionW[] = {'d','e','s','c','r','i','p','t','i','o','n',0};
+static const WCHAR fileW[] = {'f','i','l','e',0};
+static const WCHAR asmv2hashW[] = {'a','s','m','v','2',':','h','a','s','h',0};
+static const WCHAR noInheritW[] = {'n','o','I','n','h','e','r','i','t',0};
+static const WCHAR noInheritableW[] = {'n','o','I','n','h','e','r','i','t','a','b','l','e',0};
+static const WCHAR typelibW[] = {'t','y','p','e','l','i','b',0};
+static const WCHAR windowClassW[] = {'w','i','n','d','o','w','C','l','a','s','s',0};
+
+static const WCHAR clsidW[] = {'c','l','s','i','d',0};
+static const WCHAR hashW[] = {'h','a','s','h',0};
+static const WCHAR hashalgW[] = {'h','a','s','h','a','l','g',0};
+static const WCHAR helpdirW[] = {'h','e','l','p','d','i','r',0};
+static const WCHAR iidW[] = {'i','i','d',0};
+static const WCHAR languageW[] = {'l','a','n','g','u','a','g','e',0};
+static const WCHAR manifestVersionW[] = {'m','a','n','i','f','e','s','t','V','e','r','s','i','o','n',0};
+static const WCHAR g_nameW[] = {'n','a','m','e',0};
++static const WCHAR neutralW[] = {'n','e','u','t','r','a','l',0};
+static const WCHAR newVersionW[] = {'n','e','w','V','e','r','s','i','o','n',0};
+static const WCHAR oldVersionW[] = {'o','l','d','V','e','r','s','i','o','n',0};
+static const WCHAR optionalW[] = {'o','p','t','i','o','n','a','l',0};
+static const WCHAR processorArchitectureW[] = {'p','r','o','c','e','s','s','o','r','A','r','c','h','i','t','e','c','t','u','r','e',0};
++static const WCHAR progidW[] = {'p','r','o','g','i','d',0};
+static const WCHAR publicKeyTokenW[] = {'p','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
++static const WCHAR threadingmodelW[] = {'t','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
+static const WCHAR tlbidW[] = {'t','l','b','i','d',0};
+static const WCHAR typeW[] = {'t','y','p','e',0};
+static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
+static const WCHAR xmlnsW[] = {'x','m','l','n','s',0};
++static const WCHAR versionedW[] = {'v','e','r','s','i','o','n','e','d',0};
++static const WCHAR yesW[] = {'y','e','s',0};
++static const WCHAR noW[] = {'n','o',0};
++static const WCHAR restrictedW[] = {'R','E','S','T','R','I','C','T','E','D',0};
++static const WCHAR controlW[] = {'C','O','N','T','R','O','L',0};
++static const WCHAR hiddenW[] = {'H','I','D','D','E','N',0};
++static const WCHAR hasdiskimageW[] = {'H','A','S','D','I','S','K','I','M','A','G','E',0};
++static const WCHAR flagsW[] = {'f','l','a','g','s',0};
++static const WCHAR miscstatusW[] = {'m','i','s','c','S','t','a','t','u','s',0};
++static const WCHAR miscstatusiconW[] = {'m','i','s','c','S','t','a','t','u','s','I','c','o','n',0};
++static const WCHAR miscstatuscontentW[] = {'m','i','s','c','S','t','a','t','u','s','C','o','n','t','e','n','t',0};
++static const WCHAR miscstatusthumbnailW[] = {'m','i','s','c','S','t','a','t','u','s','T','h','u','m','b','n','a','i','l',0};
++static const WCHAR miscstatusdocprintW[] = {'m','i','s','c','S','t','a','t','u','s','D','o','c','P','r','i','n','t',0};
++static const WCHAR baseInterfaceW[] = {'b','a','s','e','I','n','t','e','r','f','a','c','e',0};
++static const WCHAR nummethodsW[] = {'n','u','m','M','e','t','h','o','d','s',0};
++static const WCHAR proxyStubClsid32W[] = {'p','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
++static const WCHAR runtimeVersionW[] = {'r','u','n','t','i','m','e','V','e','r','s','i','o','n',0};
++static const WCHAR mscoreeW[] = {'M','S','C','O','R','E','E','.','D','L','L',0};
++static const WCHAR mscoree2W[] = {'m','s','c','o','r','e','e','.','d','l','l',0};
++
++static const WCHAR activatewhenvisibleW[] = {'a','c','t','i','v','a','t','e','w','h','e','n','v','i','s','i','b','l','e',0};
++static const WCHAR actslikebuttonW[] = {'a','c','t','s','l','i','k','e','b','u','t','t','o','n',0};
++static const WCHAR actslikelabelW[] = {'a','c','t','s','l','i','k','e','l','a','b','e','l',0};
++static const WCHAR alignableW[] = {'a','l','i','g','n','a','b','l','e',0};
++static const WCHAR alwaysrunW[] = {'a','l','w','a','y','s','r','u','n',0};
++static const WCHAR canlinkbyole1W[] = {'c','a','n','l','i','n','k','b','y','o','l','e','1',0};
++static const WCHAR cantlinkinsideW[] = {'c','a','n','t','l','i','n','k','i','n','s','i','d','e',0};
++static const WCHAR ignoreactivatewhenvisibleW[] = {'i','g','n','o','r','e','a','c','t','i','v','a','t','e','w','h','e','n','v','i','s','i','b','l','e',0};
++static const WCHAR imemodeW[] = {'i','m','e','m','o','d','e',0};
++static const WCHAR insertnotreplaceW[] = {'i','n','s','e','r','t','n','o','t','r','e','p','l','a','c','e',0};
++static const WCHAR insideoutW[] = {'i','n','s','i','d','e','o','u','t',0};
++static const WCHAR invisibleatruntimeW[] = {'i','n','v','i','s','i','b','l','e','a','t','r','u','n','t','i','m','e',0};
++static const WCHAR islinkobjectW[] = {'i','s','l','i','n','k','o','b','j','e','c','t',0};
++static const WCHAR nouiactivateW[] = {'n','o','u','i','a','c','t','i','v','a','t','e',0};
++static const WCHAR onlyiconicW[] = {'o','n','l','y','i','c','o','n','i','c',0};
++static const WCHAR recomposeonresizeW[] = {'r','e','c','o','m','p','o','s','e','o','n','r','e','s','i','z','e',0};
++static const WCHAR renderingisdeviceindependentW[] = {'r','e','n','d','e','r','i','n','g','i','s','d','e','v','i','c','e','i','n','d','e','p','e','n','d','e','n','t',0};
++static const WCHAR setclientsitefirstW[] = {'s','e','t','c','l','i','e','n','t','s','i','t','e','f','i','r','s','t',0};
++static const WCHAR simpleframeW[] = {'s','i','m','p','l','e','f','r','a','m','e',0};
++static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
++static const WCHAR supportsmultilevelundoW[] = {'s','u','p','p','o','r','t','s','m','u','l','t','i','l','e','v','e','l','u','n','d','o',0};
++static const WCHAR wantstomenumergeW[] = {'w','a','n','t','s','t','o','m','e','n','u','m','e','r','g','e',0};
++
++struct olemisc_entry
++{
++ const WCHAR *name;
++ OLEMISC value;
++};
++
++static const struct olemisc_entry olemisc_values[] =
++{
++ { activatewhenvisibleW, OLEMISC_ACTIVATEWHENVISIBLE },
++ { actslikebuttonW, OLEMISC_ACTSLIKEBUTTON },
++ { actslikelabelW, OLEMISC_ACTSLIKELABEL },
++ { alignableW, OLEMISC_ALIGNABLE },
++ { alwaysrunW, OLEMISC_ALWAYSRUN },
++ { canlinkbyole1W, OLEMISC_CANLINKBYOLE1 },
++ { cantlinkinsideW, OLEMISC_CANTLINKINSIDE },
++ { ignoreactivatewhenvisibleW, OLEMISC_IGNOREACTIVATEWHENVISIBLE },
++ { imemodeW, OLEMISC_IMEMODE },
++ { insertnotreplaceW, OLEMISC_INSERTNOTREPLACE },
++ { insideoutW, OLEMISC_INSIDEOUT },
++ { invisibleatruntimeW, OLEMISC_INVISIBLEATRUNTIME },
++ { islinkobjectW, OLEMISC_ISLINKOBJECT },
++ { nouiactivateW, OLEMISC_NOUIACTIVATE },
++ { onlyiconicW, OLEMISC_ONLYICONIC },
++ { recomposeonresizeW, OLEMISC_RECOMPOSEONRESIZE },
++ { renderingisdeviceindependentW, OLEMISC_RENDERINGISDEVICEINDEPENDENT },
++ { setclientsitefirstW, OLEMISC_SETCLIENTSITEFIRST },
++ { simpleframeW, OLEMISC_SIMPLEFRAME },
++ { staticW, OLEMISC_STATIC },
++ { supportsmultilevelundoW, OLEMISC_SUPPORTSMULTILEVELUNDO },
++ { wantstomenumergeW, OLEMISC_WANTSTOMENUMERGE }
++};
+
+static const WCHAR g_xmlW[] = {'?','x','m','l',0};
+static const WCHAR manifestv1W[] = {'u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','a','s','m','.','v','1',0};
+static const WCHAR manifestv3W[] = {'u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','a','s','m','.','v','3',0};
+
+static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0};
+static const WCHAR version_formatW[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
+static const WCHAR wildcardW[] = {'*',0};
+
+static ACTIVATION_CONTEXT_WRAPPED system_actctx = { ACTCTX_MAGIC_MARKER, { 1 } };
+static ACTIVATION_CONTEXT *process_actctx = &system_actctx.ActivationContext;
+
+static WCHAR *strdupW(const WCHAR* str)
+{
+ WCHAR* ptr;
+
+ if (!(ptr = RtlAllocateHeap(RtlGetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR))))
+ return NULL;
+ return strcpyW(ptr, str);
+}
+
+static WCHAR *xmlstrdupW(const xmlstr_t* str)
+{
+ WCHAR *strW;
+
+ if ((strW = RtlAllocateHeap(RtlGetProcessHeap(), 0, (str->len + 1) * sizeof(WCHAR))))
+ {
+ memcpy( strW, str->ptr, str->len * sizeof(WCHAR) );
+ strW[str->len] = 0;
+ }
+ return strW;
+}
+
+static inline BOOL xmlstr_cmp(const xmlstr_t* xmlstr, const WCHAR *str)
+{
+ return !strncmpW(xmlstr->ptr, str, xmlstr->len) && !str[xmlstr->len];
+}
+
+static inline BOOL xmlstr_cmpi(const xmlstr_t* xmlstr, const WCHAR *str)
+{
+ return !strncmpiW(xmlstr->ptr, str, xmlstr->len) && !str[xmlstr->len];
+}
+
+static inline BOOL xmlstr_cmp_end(const xmlstr_t* xmlstr, const WCHAR *str)
+{
+ return (xmlstr->len && xmlstr->ptr[0] == '/' &&
+ !strncmpW(xmlstr->ptr + 1, str, xmlstr->len - 1) && !str[xmlstr->len - 1]);
+}
+
+static inline BOOL xml_elem_cmp(const xmlstr_t *elem, const WCHAR *str, const WCHAR *namespace)
+{
+ UINT len = strlenW( namespace );
+
+ if (!strncmpW(elem->ptr, str, elem->len) && !str[elem->len]) return TRUE;
+ return (elem->len > len && !strncmpW(elem->ptr, namespace, len) &&
+ !strncmpW(elem->ptr + len, str, elem->len - len) && !str[elem->len - len]);
+}
+
+static inline BOOL xml_elem_cmp_end(const xmlstr_t *elem, const WCHAR *str, const WCHAR *namespace)
+{
+ if (elem->len && elem->ptr[0] == '/')
+ {
+ xmlstr_t elem_end;
+ elem_end.ptr = elem->ptr + 1;
+ elem_end.len = elem->len - 1;
+ return xml_elem_cmp( &elem_end, str, namespace );
+ }
+ return FALSE;
+}
+
+static inline BOOL isxmlspace( WCHAR ch )
+{
+ return (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t');
+}
+
+static UNICODE_STRING xmlstr2unicode(const xmlstr_t *xmlstr)
+{
+ UNICODE_STRING res;
+
+ res.Buffer = (PWSTR)xmlstr->ptr;
+ res.Length = res.MaximumLength = (USHORT)xmlstr->len * sizeof(WCHAR);
+
+ return res;
+}
+
+static struct assembly *add_assembly(ACTIVATION_CONTEXT *actctx, enum assembly_type at)
+{
+ struct assembly *assembly;
+
+ if (actctx->num_assemblies == actctx->allocated_assemblies)
+ {
+ void *ptr;
+ unsigned int new_count;
+ if (actctx->assemblies)
+ {
+ new_count = actctx->allocated_assemblies * 2;
+ ptr = RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
+ actctx->assemblies, new_count * sizeof(*assembly) );
+ }
+ else
+ {
+ new_count = 4;
+ ptr = RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*assembly) );
+ }
+ if (!ptr) return NULL;
+ actctx->assemblies = ptr;
+ actctx->allocated_assemblies = new_count;
+ }
+
+ assembly = &actctx->assemblies[actctx->num_assemblies++];
+ assembly->type = at;
+ return assembly;
+}
+
+static struct dll_redirect* add_dll_redirect(struct assembly* assembly)
+{
+ if (assembly->num_dlls == assembly->allocated_dlls)
+ {
+ void *ptr;
+ unsigned int new_count;
+ if (assembly->dlls)
+ {
+ new_count = assembly->allocated_dlls * 2;
+ ptr = RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
+ assembly->dlls, new_count * sizeof(*assembly->dlls) );
+ }
+ else
+ {
+ new_count = 4;
+ ptr = RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*assembly->dlls) );
+ }
+ if (!ptr) return NULL;
+ assembly->dlls = ptr;
+ assembly->allocated_dlls = new_count;
+ }
+ return &assembly->dlls[assembly->num_dlls++];
+}
+
+static void free_assembly_identity(struct assembly_identity *ai)
+{
+ RtlFreeHeap( RtlGetProcessHeap(), 0, ai->name );
+ RtlFreeHeap( RtlGetProcessHeap(), 0, ai->arch );
+ RtlFreeHeap( RtlGetProcessHeap(), 0, ai->public_key );
+ RtlFreeHeap( RtlGetProcessHeap(), 0, ai->language );
+ RtlFreeHeap( RtlGetProcessHeap(), 0, ai->type );
+}
+
+static struct entity* add_entity(struct entity_array *array, DWORD kind)
+{
+ struct entity* entity;
+
+ if (array->num == array->allocated)
+ {
+ void *ptr;
+ unsigned int new_count;
+ if (array->base)
+ {
+ new_count = array->allocated * 2;
+ ptr = RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
+ array->base, new_count * sizeof(*array->base) );
+ }
+ else
+ {
+ new_count = 4;
+ ptr = RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*array->base) );
+ }
+ if (!ptr) return NULL;
+ array->base = ptr;
+ array->allocated = new_count;
+ }
+ entity = &array->base[array->num++];
+ entity->kind = kind;
+ return entity;
+}
+
+static void free_entity_array(struct entity_array *array)
+{
- RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.proxy.iid);
- RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.proxy.name);
++ unsigned int i, j;
+ for (i = 0; i < array->num; i++)
+ {
+ struct entity *entity = &array->base[i];
+ switch (entity->kind)
+ {
+ case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION:
+ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.comclass.clsid);
++ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.comclass.tlbid);
++ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.comclass.progid);
++ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.comclass.name);
++ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.comclass.version);
++ for (j = 0; j < entity->u.comclass.progids.num; j++)
++ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.comclass.progids.progids[j]);
++ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.comclass.progids.progids);
+ break;
+ case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION:
- RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.typelib.version);
++ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.ifaceps.iid);
++ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.ifaceps.base);
++ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.ifaceps.ps32);
++ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.ifaceps.name);
+ break;
+ case ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION:
+ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.typelib.tlbid);
- case ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION:
- RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.clrclass.name);
- RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.clrclass.clsid);
- break;
+ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.typelib.helpdir);
+ break;
+ case ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION:
+ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.class.name);
+ break;
- static BOOL parse_com_class_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll)
+ case ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES:
+ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.clrsurrogate.name);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.clrsurrogate.clsid);
++ RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.clrsurrogate.version);
+ break;
+ default:
+ DPRINT1("Unknown entity kind %u\n", entity->kind);
+ }
+ }
+ RtlFreeHeap( RtlGetProcessHeap(), 0, array->base );
+}
+
+static BOOL is_matching_string( const WCHAR *str1, const WCHAR *str2 )
+{
+ if (!str1) return !str2;
+ return str2 && !strcmpiW( str1, str2 );
+}
+
+static BOOL is_matching_identity( const struct assembly_identity *id1,
+ const struct assembly_identity *id2 )
+{
+ if (!is_matching_string( id1->name, id2->name )) return FALSE;
+ if (!is_matching_string( id1->arch, id2->arch )) return FALSE;
+ if (!is_matching_string( id1->public_key, id2->public_key )) return FALSE;
+
+ if (id1->language && id2->language && strcmpiW( id1->language, id2->language ))
+ {
+ if (strcmpW( wildcardW, id1->language ) && strcmpW( wildcardW, id2->language ))
+ return FALSE;
+ }
+ if (id1->version.major != id2->version.major) return FALSE;
+ if (id1->version.minor != id2->version.minor) return FALSE;
+ if (id1->version.build > id2->version.build) return FALSE;
+ if (id1->version.build == id2->version.build &&
+ id1->version.revision > id2->version.revision) return FALSE;
+ return TRUE;
+}
+
+static BOOL add_dependent_assembly_id(struct actctx_loader* acl,
+ struct assembly_identity* ai)
+{
+ unsigned int i;
+
+ /* check if we already have that assembly */
+
+ for (i = 0; i < acl->actctx->num_assemblies; i++)
+ if (is_matching_identity( ai, &acl->actctx->assemblies[i].id ))
+ {
+ DPRINT( "reusing existing assembly for %S arch %S version %u.%u.%u.%u\n",
+ ai->name, ai->arch, ai->version.major, ai->version.minor,
+ ai->version.build, ai->version.revision );
+ return TRUE;
+ }
+
+ for (i = 0; i < acl->num_dependencies; i++)
+ if (is_matching_identity( ai, &acl->dependencies[i] ))
+ {
+ DPRINT( "reusing existing dependency for %S arch %S version %u.%u.%u.%u\n",
+ ai->name, ai->arch, ai->version.major, ai->version.minor,
+ ai->version.build, ai->version.revision );
+ return TRUE;
+ }
+
+ if (acl->num_dependencies == acl->allocated_dependencies)
+ {
+ void *ptr;
+ unsigned int new_count;
+ if (acl->dependencies)
+ {
+ new_count = acl->allocated_dependencies * 2;
+ ptr = RtlReAllocateHeap(RtlGetProcessHeap(), 0, acl->dependencies,
+ new_count * sizeof(acl->dependencies[0]));
+ }
+ else
+ {
+ new_count = 4;
+ ptr = RtlAllocateHeap(RtlGetProcessHeap(), 0, new_count * sizeof(acl->dependencies[0]));
+ }
+ if (!ptr) return FALSE;
+ acl->dependencies = ptr;
+ acl->allocated_dependencies = new_count;
+ }
+ acl->dependencies[acl->num_dependencies++] = *ai;
+
+ return TRUE;
+}
+
+static void free_depend_manifests(struct actctx_loader* acl)
+{
+ unsigned int i;
+ for (i = 0; i < acl->num_dependencies; i++)
+ free_assembly_identity(&acl->dependencies[i]);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, acl->dependencies);
+}
+
+static WCHAR *build_assembly_dir(struct assembly_identity* ai)
+{
+ static const WCHAR undW[] = {'_',0};
+ static const WCHAR noneW[] = {'n','o','n','e',0};
+ static const WCHAR mskeyW[] = {'d','e','a','d','b','e','e','f',0};
+
+ const WCHAR *arch = ai->arch ? ai->arch : noneW;
+ const WCHAR *key = ai->public_key ? ai->public_key : noneW;
+ const WCHAR *lang = ai->language ? ai->language : noneW;
+ const WCHAR *name = ai->name ? ai->name : noneW;
+ SIZE_T size = (strlenW(arch) + 1 + strlenW(name) + 1 + strlenW(key) + 24 + 1 +
+ strlenW(lang) + 1) * sizeof(WCHAR) + sizeof(mskeyW);
+ WCHAR *ret;
+
+ if (!(ret = RtlAllocateHeap( RtlGetProcessHeap(), 0, size ))) return NULL;
+
+ strcpyW( ret, arch );
+ strcatW( ret, undW );
+ strcatW( ret, name );
+ strcatW( ret, undW );
+ strcatW( ret, key );
+ strcatW( ret, undW );
+ sprintfW( ret + strlenW(ret), version_formatW,
+ ai->version.major, ai->version.minor, ai->version.build, ai->version.revision );
+ strcatW( ret, undW );
+ strcatW( ret, lang );
+ strcatW( ret, undW );
+ strcatW( ret, mskeyW );
+ return ret;
+}
+
+static inline void append_string( WCHAR *buffer, const WCHAR *prefix, const WCHAR *str )
+{
+ WCHAR *p = buffer;
+
+ if (!str) return;
+ strcatW( buffer, prefix );
+ p += strlenW(p);
+ *p++ = '"';
+ strcpyW( p, str );
+ p += strlenW(p);
+ *p++ = '"';
+ *p = 0;
+}
+
+static WCHAR *build_assembly_id( const struct assembly_identity *ai )
+{
+ static const WCHAR archW[] =
+ {',','p','r','o','c','e','s','s','o','r','A','r','c','h','i','t','e','c','t','u','r','e','=',0};
+ static const WCHAR public_keyW[] =
+ {',','p','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
+ static const WCHAR typeW2[] =
+ {',','t','y','p','e','=',0};
+ static const WCHAR versionW2[] =
+ {',','v','e','r','s','i','o','n','=',0};
+
+ WCHAR version[64], *ret;
+ SIZE_T size = 0;
+
+ sprintfW( version, version_formatW,
+ ai->version.major, ai->version.minor, ai->version.build, ai->version.revision );
+ if (ai->name) size += strlenW(ai->name) * sizeof(WCHAR);
+ if (ai->arch) size += strlenW(archW) + strlenW(ai->arch) + 2;
+ if (ai->public_key) size += strlenW(public_keyW) + strlenW(ai->public_key) + 2;
+ if (ai->type) size += strlenW(typeW2) + strlenW(ai->type) + 2;
+ size += strlenW(versionW2) + strlenW(version) + 2;
+
+ if (!(ret = RtlAllocateHeap( RtlGetProcessHeap(), 0, (size + 1) * sizeof(WCHAR) )))
+ return NULL;
+
+ if (ai->name) strcpyW( ret, ai->name );
+ else *ret = 0;
+ append_string( ret, archW, ai->arch );
+ append_string( ret, public_keyW, ai->public_key );
+ append_string( ret, typeW2, ai->type );
+ append_string( ret, versionW2, version );
+ return ret;
+}
+static ACTIVATION_CONTEXT *check_actctx( HANDLE h )
+{
+ ACTIVATION_CONTEXT *ret = NULL, *actctx = h;
+ PACTIVATION_CONTEXT_WRAPPED pActual;
+
+ if (!h || h == INVALID_HANDLE_VALUE) return NULL;
+ _SEH2_TRY
+ {
+ if (actctx)
+ {
+ pActual = CONTAINING_RECORD(actctx, ACTIVATION_CONTEXT_WRAPPED, ActivationContext);
+ if (pActual->MagicMarker == ACTCTX_MAGIC_MARKER) ret = &pActual->ActivationContext;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DPRINT1("Invalid activation context handle!\n");
+ }
+ _SEH2_END;
+ return ret;
+}
+
+static inline void actctx_addref( ACTIVATION_CONTEXT *actctx )
+{
+ InterlockedExchangeAdd( &actctx->RefCount, 1 );
+}
+
+static void actctx_release( ACTIVATION_CONTEXT *actctx )
+{
+ PACTIVATION_CONTEXT_WRAPPED pActual;
+
+ if (InterlockedExchangeAdd(&actctx->RefCount, -1) == 1)
+ {
+ unsigned int i, j;
+
+ for (i = 0; i < actctx->num_assemblies; i++)
+ {
+ struct assembly *assembly = &actctx->assemblies[i];
+ for (j = 0; j < assembly->num_dlls; j++)
+ {
+ struct dll_redirect *dll = &assembly->dlls[j];
+ free_entity_array( &dll->entities );
+ RtlFreeHeap( RtlGetProcessHeap(), 0, dll->name );
+ RtlFreeHeap( RtlGetProcessHeap(), 0, dll->hash );
+ }
+ RtlFreeHeap( RtlGetProcessHeap(), 0, assembly->dlls );
+ RtlFreeHeap( RtlGetProcessHeap(), 0, assembly->manifest.info );
+ RtlFreeHeap( RtlGetProcessHeap(), 0, assembly->directory );
+ free_entity_array( &assembly->entities );
+ free_assembly_identity(&assembly->id);
+ }
+ RtlFreeHeap( RtlGetProcessHeap(), 0, actctx->config.info );
+ RtlFreeHeap( RtlGetProcessHeap(), 0, actctx->appdir.info );
+ RtlFreeHeap( RtlGetProcessHeap(), 0, actctx->assemblies );
+ pActual = CONTAINING_RECORD(actctx, ACTIVATION_CONTEXT_WRAPPED, ActivationContext);
+ pActual->MagicMarker = 0;
+ RtlFreeHeap(RtlGetProcessHeap(), 0, pActual);
+ }
+}
+
+static BOOL next_xml_attr(xmlbuf_t* xmlbuf, xmlstr_t* name, xmlstr_t* value,
+ BOOL* error, BOOL* end)
+{
+ const WCHAR* ptr;
+
+ *error = TRUE;
+
+ while (xmlbuf->ptr < xmlbuf->end && isxmlspace(*xmlbuf->ptr))
+ xmlbuf->ptr++;
+
+ if (xmlbuf->ptr == xmlbuf->end) return FALSE;
+
+ if (*xmlbuf->ptr == '/')
+ {
+ xmlbuf->ptr++;
+ if (xmlbuf->ptr == xmlbuf->end || *xmlbuf->ptr != '>')
+ return FALSE;
+
+ xmlbuf->ptr++;
+ *end = TRUE;
+ *error = FALSE;
+ return FALSE;
+ }
+
+ if (*xmlbuf->ptr == '>')
+ {
+ xmlbuf->ptr++;
+ *error = FALSE;
+ return FALSE;
+ }
+
+ ptr = xmlbuf->ptr;
+ while (ptr < xmlbuf->end && *ptr != '=' && *ptr != '>' && !isxmlspace(*ptr)) ptr++;
+
+ if (ptr == xmlbuf->end) return FALSE;
+
+ name->ptr = xmlbuf->ptr;
+ name->len = ptr-xmlbuf->ptr;
+ xmlbuf->ptr = ptr;
+
+ /* skip spaces before '=' */
+ while (ptr < xmlbuf->end && *ptr != '=' && isxmlspace(*ptr)) ptr++;
+ if (ptr == xmlbuf->end || *ptr != '=') return FALSE;
+
+ /* skip '=' itself */
+ ptr++;
+ if (ptr == xmlbuf->end) return FALSE;
+
+ /* skip spaces after '=' */
+ while (ptr < xmlbuf->end && *ptr != '"' && *ptr != '\'' && isxmlspace(*ptr)) ptr++;
+
+ if (ptr == xmlbuf->end || (*ptr != '"' && *ptr != '\'')) return FALSE;
+
+ value->ptr = ++ptr;
+ if (ptr == xmlbuf->end) return FALSE;
+
+ ptr = memchrW(ptr, ptr[-1], xmlbuf->end - ptr);
+ if (!ptr)
+ {
+ xmlbuf->ptr = xmlbuf->end;
+ return FALSE;
+ }
+
+ value->len = ptr - value->ptr;
+ xmlbuf->ptr = ptr + 1;
+
+ if (xmlbuf->ptr == xmlbuf->end) return FALSE;
+
+ *error = FALSE;
+ return TRUE;
+}
+
+static BOOL next_xml_elem(xmlbuf_t* xmlbuf, xmlstr_t* elem)
+{
+ const WCHAR* ptr;
+
+ for (;;)
+ {
+ ptr = memchrW(xmlbuf->ptr, '<', xmlbuf->end - xmlbuf->ptr);
+ if (!ptr)
+ {
+ xmlbuf->ptr = xmlbuf->end;
+ return FALSE;
+ }
+ ptr++;
+ if (ptr + 3 < xmlbuf->end && ptr[0] == '!' && ptr[1] == '-' && ptr[2] == '-') /* skip comment */
+ {
+ for (ptr += 3; ptr + 3 <= xmlbuf->end; ptr++)
+ if (ptr[0] == '-' && ptr[1] == '-' && ptr[2] == '>') break;
+
+ if (ptr + 3 > xmlbuf->end)
+ {
+ xmlbuf->ptr = xmlbuf->end;
+ return FALSE;
+ }
+ xmlbuf->ptr = ptr + 3;
+ }
+ else break;
+ }
+
+ xmlbuf->ptr = ptr;
+ while (ptr < xmlbuf->end && !isxmlspace(*ptr) && *ptr != '>' && (*ptr != '/' || ptr == xmlbuf->ptr))
+ ptr++;
+
+ elem->ptr = xmlbuf->ptr;
+ elem->len = ptr - xmlbuf->ptr;
+ xmlbuf->ptr = ptr;
+ return xmlbuf->ptr != xmlbuf->end;
+}
+
+static BOOL parse_xml_header(xmlbuf_t* xmlbuf)
+{
+ /* FIXME: parse attributes */
+ const WCHAR *ptr;
+
+ for (ptr = xmlbuf->ptr; ptr < xmlbuf->end - 1; ptr++)
+ {
+ if (ptr[0] == '?' && ptr[1] == '>')
+ {
+ xmlbuf->ptr = ptr + 2;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static BOOL parse_text_content(xmlbuf_t* xmlbuf, xmlstr_t* content)
+{
+ const WCHAR *ptr = memchrW(xmlbuf->ptr, '<', xmlbuf->end - xmlbuf->ptr);
+
+ if (!ptr) return FALSE;
+
+ content->ptr = xmlbuf->ptr;
+ content->len = ptr - xmlbuf->ptr;
+ xmlbuf->ptr = ptr;
+
+ return TRUE;
+}
+
+static BOOL parse_version(const xmlstr_t *str, struct assembly_version *version)
+{
+ unsigned int ver[4];
+ unsigned int pos;
+ const WCHAR *curr;
+ UNICODE_STRING strU;
+
+ /* major.minor.build.revision */
+ ver[0] = ver[1] = ver[2] = ver[3] = pos = 0;
+ for (curr = str->ptr; curr < str->ptr + str->len; curr++)
+ {
+ if (*curr >= '0' && *curr <= '9')
+ {
+ ver[pos] = ver[pos] * 10 + *curr - '0';
+ if (ver[pos] >= 0x10000) goto error;
+ }
+ else if (*curr == '.')
+ {
+ if (++pos >= 4) goto error;
+ }
+ else goto error;
+ }
+ version->major = ver[0];
+ version->minor = ver[1];
+ version->build = ver[2];
+ version->revision = ver[3];
+ return TRUE;
+
+error:
+ strU = xmlstr2unicode(str);
+ DPRINT1( "Wrong version definition in manifest file (%wZ)\n", &strU );
+ return FALSE;
+}
+
+static BOOL parse_expect_elem(xmlbuf_t* xmlbuf, const WCHAR* name, const WCHAR *namespace)
+{
+ xmlstr_t elem;
+ UNICODE_STRING elemU;
+ if (!next_xml_elem(xmlbuf, &elem)) return FALSE;
+ if (xml_elem_cmp(&elem, name, namespace)) return TRUE;
+ elemU = xmlstr2unicode(&elem);
+ DPRINT1( "unexpected element %wZ\n", &elemU );
+ return FALSE;
+}
+
+static BOOL parse_expect_no_attr(xmlbuf_t* xmlbuf, BOOL* end)
+{
+ xmlstr_t attr_name, attr_value;
+ UNICODE_STRING attr_nameU, attr_valueU;
+ BOOL error;
+
+ while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, end))
+ {
+ attr_nameU = xmlstr2unicode(&attr_name);
+ attr_valueU = xmlstr2unicode(&attr_value);
+ DPRINT1( "unexpected attr %wZ=%wZ\n", &attr_nameU,
+ &attr_valueU);
+ }
+ return !error;
+}
+
+static BOOL parse_end_element(xmlbuf_t *xmlbuf)
+{
+ BOOL end = FALSE;
+ return parse_expect_no_attr(xmlbuf, &end) && !end;
+}
+
+static BOOL parse_expect_end_elem(xmlbuf_t *xmlbuf, const WCHAR *name, const WCHAR *namespace)
+{
+ xmlstr_t elem;
+ UNICODE_STRING elemU;
+ if (!next_xml_elem(xmlbuf, &elem)) return FALSE;
+ if (!xml_elem_cmp_end(&elem, name, namespace))
+ {
+ elemU = xmlstr2unicode(&elem);
+ DPRINT1( "unexpected element %wZ\n", &elemU );
+ return FALSE;
+ }
+ return parse_end_element(xmlbuf);
+}
+
+static BOOL parse_unknown_elem(xmlbuf_t *xmlbuf, const xmlstr_t *unknown_elem)
+{
+ xmlstr_t attr_name, attr_value, elem;
+ BOOL end = FALSE, error, ret = TRUE;
+
+ while(next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end));
+ if(error || end) return end;
+
+ while(ret && (ret = next_xml_elem(xmlbuf, &elem)))
+ {
+ if(*elem.ptr == '/' && elem.len - 1 == unknown_elem->len &&
+ !strncmpW(elem.ptr+1, unknown_elem->ptr, unknown_elem->len))
+ break;
+ else
+ ret = parse_unknown_elem(xmlbuf, &elem);
+ }
+
+ return ret && parse_end_element(xmlbuf);
+}
+
+static BOOL parse_assembly_identity_elem(xmlbuf_t* xmlbuf, ACTIVATION_CONTEXT* actctx,
+ struct assembly_identity* ai)
+{
+ xmlstr_t attr_name, attr_value;
+ BOOL end = FALSE, error;
+ UNICODE_STRING attr_valueU, attr_nameU;
+
+ while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+ {
+ if (xmlstr_cmp(&attr_name, g_nameW))
+ {
+ if (!(ai->name = xmlstrdupW(&attr_value))) return FALSE;
+ }
+ else if (xmlstr_cmp(&attr_name, typeW))
+ {
+ if (!(ai->type = xmlstrdupW(&attr_value))) return FALSE;
+ }
+ else if (xmlstr_cmp(&attr_name, versionW))
+ {
+ if (!parse_version(&attr_value, &ai->version)) return FALSE;
+ }
+ else if (xmlstr_cmp(&attr_name, processorArchitectureW))
+ {
+ if (!(ai->arch = xmlstrdupW(&attr_value))) return FALSE;
+ }
+ else if (xmlstr_cmp(&attr_name, publicKeyTokenW))
+ {
+ if (!(ai->public_key = xmlstrdupW(&attr_value))) return FALSE;
+ }
+ else if (xmlstr_cmp(&attr_name, languageW))
+ {
+ DPRINT1("Unsupported yet language attribute (%S)\n",
+ ai->language);
+ if (!(ai->language = xmlstrdupW(&attr_value))) return FALSE;
+ }
+ else
+ {
+ attr_nameU = xmlstr2unicode(&attr_name);
+ attr_valueU = xmlstr2unicode(&attr_value);
+ DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
+ }
+ }
+
+ if (error || end) return end;
+ return parse_expect_end_elem(xmlbuf, assemblyIdentityW, asmv1W);
+}
+
- if (error || end) return end;
++static enum comclass_threadingmodel parse_com_class_threadingmodel(xmlstr_t *value)
++{
++ static const WCHAR apartW[] = {'A','p','a','r','t','m','e','n','t',0};
++ static const WCHAR neutralW[] = {'N','e','u','t','r','a','l',0};
++ static const WCHAR freeW[] = {'F','r','e','e',0};
++ static const WCHAR bothW[] = {'B','o','t','h',0};
++
++ if (value->len == 0) return ThreadingModel_No;
++ if (xmlstr_cmp(value, apartW))
++ return ThreadingModel_Apartment;
++ else if (xmlstr_cmp(value, freeW))
++ return ThreadingModel_Free;
++ else if (xmlstr_cmp(value, bothW))
++ return ThreadingModel_Both;
++ else if (xmlstr_cmp(value, neutralW))
++ return ThreadingModel_Neutral;
++ else
++ return ThreadingModel_No;
++};
++
++static OLEMISC get_olemisc_value(const WCHAR *str, int len)
++{
++ int min, max;
++
++ min = 0;
++ max = sizeof(olemisc_values)/sizeof(struct olemisc_entry) - 1;
++
++ while (min <= max)
++ {
++ int n, c;
++
++ n = (min+max)/2;
++
++ c = strncmpW(olemisc_values[n].name, str, len);
++ if (!c && !olemisc_values[n].name[len])
++ return olemisc_values[n].value;
++
++ if (c >= 0)
++ max = n-1;
++ else
++ min = n+1;
++ }
++
++ DPRINT1("unknown flag %S\n", str);
++ return 0;
++}
++
++static DWORD parse_com_class_misc(const xmlstr_t *value)
++{
++ const WCHAR *str = value->ptr, *start;
++ DWORD flags = 0;
++ int i = 0;
++
++ /* it's comma separated list of flags */
++ while (i < value->len)
++ {
++ start = str;
++ while (*str != ',' && (i++ < value->len)) str++;
++
++ flags |= get_olemisc_value(start, str-start);
++
++ /* skip separator */
++ str++;
++ i++;
++ }
++
++ return flags;
++}
++
++static BOOL com_class_add_progid(const xmlstr_t *progid, struct entity *entity)
++{
++ struct progids *progids = &entity->u.comclass.progids;
++
++ if (progids->allocated == 0)
++ {
++ progids->allocated = 4;
++ if (!(progids->progids = RtlAllocateHeap(RtlGetProcessHeap(), 0, progids->allocated * sizeof(WCHAR*)))) return FALSE;
++ }
++
++ if (progids->allocated == progids->num)
++ {
++ progids->allocated *= 2;
++ progids->progids = RtlReAllocateHeap(RtlGetProcessHeap(), 0, progids->progids, progids->allocated * sizeof(WCHAR*));
++ }
++
++ if (!(progids->progids[progids->num] = xmlstrdupW(progid))) return FALSE;
++ progids->num++;
++
++ return TRUE;
++}
++
++static BOOL parse_com_class_progid(xmlbuf_t* xmlbuf, struct entity *entity)
++{
++ xmlstr_t content;
++ BOOL end = FALSE;
++
++ if (!parse_expect_no_attr(xmlbuf, &end) || end || !parse_text_content(xmlbuf, &content))
++ return FALSE;
++
++ if (!com_class_add_progid(&content, entity)) return FALSE;
++ return parse_expect_end_elem(xmlbuf, progidW, asmv1W);
++}
++
++static BOOL parse_com_class_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll, struct actctx_loader *acl)
+{
+ xmlstr_t elem, attr_name, attr_value;
+ BOOL ret = TRUE, end = FALSE, error;
+ struct entity* entity;
+ UNICODE_STRING attr_valueU, attr_nameU;
+
+ if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)))
+ return FALSE;
+
+ while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+ {
+ if (xmlstr_cmp(&attr_name, clsidW))
+ {
+ if (!(entity->u.comclass.clsid = xmlstrdupW(&attr_value))) return FALSE;
+ }
++ else if (xmlstr_cmp(&attr_name, progidW))
++ {
++ if (!(entity->u.comclass.progid = xmlstrdupW(&attr_value))) return FALSE;
++ }
++ else if (xmlstr_cmp(&attr_name, tlbidW))
++ {
++ if (!(entity->u.comclass.tlbid = xmlstrdupW(&attr_value))) return FALSE;
++ }
++ else if (xmlstr_cmp(&attr_name, threadingmodelW))
++ {
++ entity->u.comclass.model = parse_com_class_threadingmodel(&attr_value);
++ }
++ else if (xmlstr_cmp(&attr_name, miscstatusW))
++ {
++ entity->u.comclass.miscstatus = parse_com_class_misc(&attr_value);
++ }
++ else if (xmlstr_cmp(&attr_name, miscstatuscontentW))
++ {
++ entity->u.comclass.miscstatuscontent = parse_com_class_misc(&attr_value);
++ }
++ else if (xmlstr_cmp(&attr_name, miscstatusthumbnailW))
++ {
++ entity->u.comclass.miscstatusthumbnail = parse_com_class_misc(&attr_value);
++ }
++ else if (xmlstr_cmp(&attr_name, miscstatusiconW))
++ {
++ entity->u.comclass.miscstatusicon = parse_com_class_misc(&attr_value);
++ }
++ else if (xmlstr_cmp(&attr_name, miscstatusdocprintW))
++ {
++ entity->u.comclass.miscstatusdocprint = parse_com_class_misc(&attr_value);
++ }
++ else if (xmlstr_cmp(&attr_name, descriptionW))
++ {
++ /* not stored */
++ }
+ else
+ {
+ attr_nameU = xmlstr2unicode(&attr_name);
+ attr_valueU = xmlstr2unicode(&attr_value);
+ DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
+ }
+ }
+
- while ((ret = next_xml_elem(xmlbuf, &elem)))
++ if (error) return FALSE;
+
- static BOOL parse_cominterface_proxy_stub_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll)
++ acl->actctx->sections |= SERVERREDIRECT_SECTION;
++ if (entity->u.comclass.progid)
++ acl->actctx->sections |= PROGIDREDIRECT_SECTION;
++
++ if (end) return TRUE;
++
++ while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
+ {
+ if (xmlstr_cmp_end(&elem, comClassW))
+ {
+ ret = parse_end_element(xmlbuf);
+ break;
+ }
++ else if (xmlstr_cmp(&elem, progidW))
++ {
++ ret = parse_com_class_progid(xmlbuf, entity);
++ }
+ else
+ {
+ attr_nameU = xmlstr2unicode(&elem);
+ DPRINT1("unknown elem %wZ\n", &attr_nameU);
+ ret = parse_unknown_elem(xmlbuf, &elem);
+ }
+ }
++
++ if (entity->u.comclass.progids.num)
++ acl->actctx->sections |= PROGIDREDIRECT_SECTION;
++
+ return ret;
+}
+
- if (!(entity->u.proxy.iid = xmlstrdupW(&attr_value))) return FALSE;
++static BOOL parse_nummethods(const xmlstr_t *str, struct entity *entity)
++{
++ const WCHAR *curr;
++ ULONG num = 0;
++
++ for (curr = str->ptr; curr < str->ptr + str->len; curr++)
++ {
++ if (*curr >= '0' && *curr <= '9')
++ num = num * 10 + *curr - '0';
++ else
++ {
++ UNICODE_STRING strU = xmlstr2unicode(str);
++ DPRINT1("wrong numeric value %wZ\n", &strU);
++ return FALSE;
++ }
++ }
++ entity->u.ifaceps.nummethods = num;
++
++ return TRUE;
++}
++
++static BOOL parse_cominterface_proxy_stub_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll, struct actctx_loader* acl)
+{
+ xmlstr_t attr_name, attr_value;
+ BOOL end = FALSE, error;
+ struct entity* entity;
+ UNICODE_STRING attr_valueU, attr_nameU;
+
+ if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION)))
+ return FALSE;
+
+ while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+ {
+ if (xmlstr_cmp(&attr_name, iidW))
+ {
- if (xmlstr_cmp(&attr_name, g_nameW))
++ if (!(entity->u.ifaceps.iid = xmlstrdupW(&attr_value))) return FALSE;
+ }
- if (!(entity->u.proxy.name = xmlstrdupW(&attr_value))) return FALSE;
++ else if (xmlstr_cmp(&attr_name, g_nameW))
++ {
++ if (!(entity->u.ifaceps.name = xmlstrdupW(&attr_value))) return FALSE;
++ }
++ else if (xmlstr_cmp(&attr_name, baseInterfaceW))
++ {
++ if (!(entity->u.ifaceps.base = xmlstrdupW(&attr_value))) return FALSE;
++ entity->u.ifaceps.mask |= BaseIface;
++ }
++ else if (xmlstr_cmp(&attr_name, nummethodsW))
++ {
++ if (!(parse_nummethods(&attr_value, entity))) return FALSE;
++ entity->u.ifaceps.mask |= NumMethods;
++ }
++ else if (xmlstr_cmp(&attr_name, tlbidW))
++ {
++ if (!(entity->u.ifaceps.tlib = xmlstrdupW(&attr_value))) return FALSE;
++ }
++ /* not used */
++ else if (xmlstr_cmp(&attr_name, proxyStubClsid32W) || xmlstr_cmp(&attr_name, threadingmodelW))
+ {
- if (error || end) return end;
+ }
+ else
+ {
+ attr_nameU = xmlstr2unicode(&attr_name);
+ attr_valueU = xmlstr2unicode(&attr_value);
+ DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
+ }
+ }
+
- static BOOL parse_typelib_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll)
++ if (error) return FALSE;
++ acl->actctx->sections |= IFACEREDIRECT_SECTION;
++ if (end) return TRUE;
++
+ return parse_expect_end_elem(xmlbuf, comInterfaceProxyStubW, asmv1W);
+}
+
- if (xmlstr_cmp(&attr_name, versionW))
++static BOOL parse_typelib_flags(const xmlstr_t *value, struct entity *entity)
++{
++ WORD *flags = &entity->u.typelib.flags;
++ const WCHAR *str = value->ptr, *start;
++ int i = 0;
++
++ *flags = 0;
++
++ /* it's comma separated list of flags */
++ while (i < value->len)
++ {
++ start = str;
++ while (*str != ',' && (i++ < value->len)) str++;
++
++ if (!strncmpiW(start, restrictedW, str-start))
++ *flags |= LIBFLAG_FRESTRICTED;
++ else if (!strncmpiW(start, controlW, str-start))
++ *flags |= LIBFLAG_FCONTROL;
++ else if (!strncmpiW(start, hiddenW, str-start))
++ *flags |= LIBFLAG_FHIDDEN;
++ else if (!strncmpiW(start, hasdiskimageW, str-start))
++ *flags |= LIBFLAG_FHASDISKIMAGE;
++ else
++ {
++ UNICODE_STRING valueU = xmlstr2unicode(value);
++ DPRINT1("unknown flags value %wZ\n", &valueU);
++ return FALSE;
++ }
++
++ /* skip separator */
++ str++;
++ i++;
++ }
++
++ return TRUE;
++}
++
++static BOOL parse_typelib_version(const xmlstr_t *str, struct entity *entity)
++{
++ unsigned int ver[2];
++ unsigned int pos;
++ const WCHAR *curr;
++ UNICODE_STRING strW;
++
++ /* major.minor */
++ ver[0] = ver[1] = pos = 0;
++ for (curr = str->ptr; curr < str->ptr + str->len; curr++)
++ {
++ if (*curr >= '0' && *curr <= '9')
++ {
++ ver[pos] = ver[pos] * 10 + *curr - '0';
++ if (ver[pos] >= 0x10000) goto error;
++ }
++ else if (*curr == '.')
++ {
++ if (++pos >= 2) goto error;
++ }
++ else goto error;
++ }
++ entity->u.typelib.major = ver[0];
++ entity->u.typelib.minor = ver[1];
++ return TRUE;
++
++error:
++ strW = xmlstr2unicode(str);
++ DPRINT1("FIXME: wrong typelib version value (%wZ)\n", &strW);
++ return FALSE;
++}
++
++static BOOL parse_typelib_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll, struct actctx_loader* acl)
+{
+ xmlstr_t attr_name, attr_value;
+ BOOL end = FALSE, error;
+ struct entity* entity;
+ UNICODE_STRING attr_valueU, attr_nameU;
+
+ if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION)))
+ return FALSE;
+
+ while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+ {
+ if (xmlstr_cmp(&attr_name, tlbidW))
+ {
+ if (!(entity->u.typelib.tlbid = xmlstrdupW(&attr_value))) return FALSE;
+ }
- if (!(entity->u.typelib.version = xmlstrdupW(&attr_value))) return FALSE;
++ else if (xmlstr_cmp(&attr_name, versionW))
+ {
- if (xmlstr_cmp(&attr_name, helpdirW))
++ if (!parse_typelib_version(&attr_value, entity)) return FALSE;
+ }
- if (error || end) return end;
++ else if (xmlstr_cmp(&attr_name, helpdirW))
+ {
+ if (!(entity->u.typelib.helpdir = xmlstrdupW(&attr_value))) return FALSE;
+ }
++ else if (xmlstr_cmp(&attr_name, flagsW))
++ {
++ if (!parse_typelib_flags(&attr_value, entity)) return FALSE;
++ }
+ else
+ {
+ attr_nameU = xmlstr2unicode(&attr_name);
+ attr_valueU = xmlstr2unicode(&attr_value);
+ DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
+ }
+ }
+
- static BOOL parse_window_class_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll)
++ if (error) return FALSE;
++
++ acl->actctx->sections |= TLIBREDIRECT_SECTION;
++
++ if (end) return TRUE;
++
+ return parse_expect_end_elem(xmlbuf, typelibW, asmv1W);
+}
+
- xmlstr_t elem, content;
- BOOL end = FALSE, ret = TRUE;
- struct entity* entity;
- UNICODE_STRING elemU;
++static inline int aligned_string_len(int len)
+{
- if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION)))
- return FALSE;
++ return (len + 3) & ~3;
++}
+
- if (!parse_expect_no_attr(xmlbuf, &end)) return FALSE;
- if (end) return FALSE;
++static int get_assembly_version(struct assembly *assembly, WCHAR *ret)
++{
++ static const WCHAR fmtW[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
++ struct assembly_version *ver = &assembly->id.version;
++ WCHAR buff[25];
+
- if (!parse_text_content(xmlbuf, &content)) return FALSE;
++ if (!ret) ret = buff;
++ return sprintfW(ret, fmtW, ver->major, ver->minor, ver->build, ver->revision);
++}
+
- if (!(entity->u.class.name = xmlstrdupW(&content))) return FALSE;
++static BOOL parse_window_class_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll, struct actctx_loader* acl)
++{
++ xmlstr_t elem, content, attr_name, attr_value;
++ BOOL end = FALSE, ret = TRUE, error;
++ struct entity* entity;
++ UNICODE_STRING elemU, attr_nameU, attr_valueU;
+
- while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
++ if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION)))
++ return FALSE;
+
- if (xmlstr_cmp_end(&elem, windowClassW))
++ entity->u.class.versioned = TRUE;
++ while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+ {
- struct assembly* assembly)
++ if (xmlstr_cmp(&attr_name, versionedW))
++ {
++ if (xmlstr_cmpi(&attr_value, noW))
++ entity->u.class.versioned = FALSE;
++ else if (!xmlstr_cmpi(&attr_value, yesW))
++ return FALSE;
++ }
++ else
++ {
++ attr_nameU = xmlstr2unicode(&attr_name);
++ attr_valueU = xmlstr2unicode(&attr_value);
++ DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
++ }
++ }
++
++ if (error || end) return end;
++
++ if (!parse_text_content(xmlbuf, &content)) return FALSE;
++
++ if (!(entity->u.class.name = xmlstrdupW(&content))) return FALSE;
++
++ acl->actctx->sections |= WINDOWCLASS_SECTION;
++
++ while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
++ {
++ if (xmlstr_cmp_end(&elem, windowClassW))
+ {
+ ret = parse_end_element(xmlbuf);
+ break;
+ }
+ else
+ {
+ elemU = xmlstr2unicode(&elem);
+ DPRINT1("unknown elem %wZ\n", &elemU);
+ ret = parse_unknown_elem(xmlbuf, &elem);
+ }
+ }
+
+ return ret;
+}
+
+static BOOL parse_binding_redirect_elem(xmlbuf_t* xmlbuf)
+{
+ xmlstr_t attr_name, attr_value;
+ UNICODE_STRING attr_valueU, attr_nameU;
+ BOOL end = FALSE, error;
+
+ while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+ {
+ attr_nameU = xmlstr2unicode(&attr_name);
+ attr_valueU = xmlstr2unicode(&attr_value);
+
+ if (xmlstr_cmp(&attr_name, oldVersionW))
+ {
+ DPRINT1("Not stored yet oldVersion=%wZ\n", &attr_valueU);
+ }
+ else if (xmlstr_cmp(&attr_name, newVersionW))
+ {
+ DPRINT1("Not stored yet newVersion=%wZ\n", &attr_valueU);
+ }
+ else
+ {
+ DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
+ }
+ }
+
+ if (error || end) return end;
+ return parse_expect_end_elem(xmlbuf, bindingRedirectW, asmv1W);
+}
+
+static BOOL parse_description_elem(xmlbuf_t* xmlbuf)
+{
+ xmlstr_t elem, content;
+ UNICODE_STRING elemU;
+ BOOL end = FALSE, ret = TRUE;
+
+ if (!parse_expect_no_attr(xmlbuf, &end) || end ||
+ !parse_text_content(xmlbuf, &content))
+ return FALSE;
+
+ elemU = xmlstr2unicode(&content);
+ DPRINT("Got description %wZ\n", &elemU);
+
+ while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
+ {
+ if (xmlstr_cmp_end(&elem, descriptionW))
+ {
+ ret = parse_end_element(xmlbuf);
+ break;
+ }
+ else
+ {
+ elemU = xmlstr2unicode(&elem);
+ DPRINT1("unknown elem %wZ\n", &elemU);
+ ret = parse_unknown_elem(xmlbuf, &elem);
+ }
+ }
+
+ return ret;
+}
+
+static BOOL parse_com_interface_external_proxy_stub_elem(xmlbuf_t* xmlbuf,
- if (!(entity->u.proxy.iid = xmlstrdupW(&attr_value))) return FALSE;
++ struct assembly* assembly,
++ struct actctx_loader* acl)
+{
+ xmlstr_t attr_name, attr_value;
+ UNICODE_STRING attr_nameU, attr_valueU;
+ BOOL end = FALSE, error;
+ struct entity* entity;
+
+ entity = add_entity(&assembly->entities, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION);
+ if (!entity) return FALSE;
+
+ while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+ {
+ if (xmlstr_cmp(&attr_name, iidW))
+ {
- if (xmlstr_cmp(&attr_name, g_nameW))
++ if (!(entity->u.ifaceps.iid = xmlstrdupW(&attr_value))) return FALSE;
+ }
- if (!(entity->u.proxy.name = xmlstrdupW(&attr_value))) return FALSE;
++ else if (xmlstr_cmp(&attr_name, g_nameW))
++ {
++ if (!(entity->u.ifaceps.name = xmlstrdupW(&attr_value))) return FALSE;
++ }
++ else if (xmlstr_cmp(&attr_name, baseInterfaceW))
++ {
++ if (!(entity->u.ifaceps.base = xmlstrdupW(&attr_value))) return FALSE;
++ entity->u.ifaceps.mask |= BaseIface;
++ }
++ else if (xmlstr_cmp(&attr_name, nummethodsW))
++ {
++ if (!(parse_nummethods(&attr_value, entity))) return FALSE;
++ entity->u.ifaceps.mask |= NumMethods;
++ }
++ else if (xmlstr_cmp(&attr_name, proxyStubClsid32W))
++ {
++ if (!(entity->u.ifaceps.ps32 = xmlstrdupW(&attr_value))) return FALSE;
++ }
++ else if (xmlstr_cmp(&attr_name, tlbidW))
+ {
- if (error || end) return end;
++ if (!(entity->u.ifaceps.tlib = xmlstrdupW(&attr_value))) return FALSE;
+ }
+ else
+ {
+ attr_nameU = xmlstr2unicode(&attr_name);
+ attr_valueU = xmlstr2unicode(&attr_value);
+ DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
+ }
+ }
+
- static BOOL parse_clr_class_elem(xmlbuf_t* xmlbuf, struct assembly* assembly)
++ if (error) return FALSE;
++ acl->actctx->sections |= IFACEREDIRECT_SECTION;
++ if (end) return TRUE;
++
+ return parse_expect_end_elem(xmlbuf, comInterfaceExternalProxyStubW, asmv1W);
+}
+
- xmlstr_t attr_name, attr_value;
- UNICODE_STRING attr_nameU, attr_valueU;
- BOOL end = FALSE, error;
++static BOOL parse_clr_class_elem(xmlbuf_t* xmlbuf, struct assembly* assembly, struct actctx_loader *acl)
+{
- entity = add_entity(&assembly->entities, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION);
++ xmlstr_t attr_name, attr_value, elem;
++ BOOL end = FALSE, error, ret = TRUE;
+ struct entity* entity;
+
- if (!(entity->u.clrclass.name = xmlstrdupW(&attr_value))) return FALSE;
++ entity = add_entity(&assembly->entities, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION);
+ if (!entity) return FALSE;
+
+ while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+ {
+ if (xmlstr_cmp(&attr_name, g_nameW))
+ {
- if (!(entity->u.clrclass.clsid = xmlstrdupW(&attr_value))) return FALSE;
++ if (!(entity->u.comclass.name = xmlstrdupW(&attr_value))) return FALSE;
+ }
+ else if (xmlstr_cmp(&attr_name, clsidW))
+ {
- if (error || end) return end;
- return parse_expect_end_elem(xmlbuf, clrClassW, asmv1W);
++ if (!(entity->u.comclass.clsid = xmlstrdupW(&attr_value))) return FALSE;
++ }
++ else if (xmlstr_cmp(&attr_name, progidW))
++ {
++ if (!(entity->u.comclass.progid = xmlstrdupW(&attr_value))) return FALSE;
++ }
++ else if (xmlstr_cmp(&attr_name, tlbidW))
++ {
++ if (!(entity->u.comclass.tlbid = xmlstrdupW(&attr_value))) return FALSE;
++ }
++ else if (xmlstr_cmp(&attr_name, threadingmodelW))
++ {
++ entity->u.comclass.model = parse_com_class_threadingmodel(&attr_value);
++ }
++ else if (xmlstr_cmp(&attr_name, runtimeVersionW))
++ {
++ if (!(entity->u.comclass.version = xmlstrdupW(&attr_value))) return FALSE;
+ }
+ else
+ {
++ UNICODE_STRING attr_nameU, attr_valueU;
+ attr_nameU = xmlstr2unicode(&attr_name);
+ attr_valueU = xmlstr2unicode(&attr_value);
+ DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
+ }
+ }
+
- static BOOL parse_clr_surrogate_elem(xmlbuf_t* xmlbuf, struct assembly* assembly)
++ if (error) return FALSE;
++ acl->actctx->sections |= SERVERREDIRECT_SECTION;
++ if (entity->u.comclass.progid)
++ acl->actctx->sections |= PROGIDREDIRECT_SECTION;
++ if (end) return TRUE;
++
++ while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
++ {
++ if (xmlstr_cmp_end(&elem, clrClassW))
++ {
++ ret = parse_end_element(xmlbuf);
++ break;
++ }
++ else if (xmlstr_cmp(&elem, progidW))
++ {
++ ret = parse_com_class_progid(xmlbuf, entity);
++ }
++ else
++ {
++ UNICODE_STRING elemU = xmlstr2unicode(&elem);
++ DPRINT1("unknown elem %wZ\n", &elemU);
++ ret = parse_unknown_elem(xmlbuf, &elem);
++ }
++ }
++
++ if (entity->u.comclass.progids.num)
++ acl->actctx->sections |= PROGIDREDIRECT_SECTION;
++
++ return ret;
+}
+
- if (error || end) return end;
++static BOOL parse_clr_surrogate_elem(xmlbuf_t* xmlbuf, struct assembly* assembly, struct actctx_loader *acl)
+{
+ xmlstr_t attr_name, attr_value;
+ UNICODE_STRING attr_nameU, attr_valueU;
+ BOOL end = FALSE, error;
+ struct entity* entity;
+
+ entity = add_entity(&assembly->entities, ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES);
+ if (!entity) return FALSE;
+
+ while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+ {
+ if (xmlstr_cmp(&attr_name, g_nameW))
+ {
+ if (!(entity->u.clrsurrogate.name = xmlstrdupW(&attr_value))) return FALSE;
+ }
+ else if (xmlstr_cmp(&attr_name, clsidW))
+ {
+ if (!(entity->u.clrsurrogate.clsid = xmlstrdupW(&attr_value))) return FALSE;
+ }
++ else if (xmlstr_cmp(&attr_name, runtimeVersionW))
++ {
++ if (!(entity->u.clrsurrogate.version = xmlstrdupW(&attr_value))) return FALSE;
++ }
+ else
+ {
+ attr_nameU = xmlstr2unicode(&attr_name);
+ attr_valueU = xmlstr2unicode(&attr_value);
+ DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
+ }
+ }
+
- static const WCHAR yesW[] = {'y','e','s',0};
++ if (error) return FALSE;
++ acl->actctx->sections |= CLRSURROGATES_SECTION;
++ if (end) return TRUE;
++
+ return parse_expect_end_elem(xmlbuf, clrSurrogateW, asmv1W);
+}
+
+static BOOL parse_dependent_assembly_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl, BOOL optional)
+{
+ struct assembly_identity ai;
+ xmlstr_t elem;
+ BOOL end = FALSE, ret = TRUE;
+
+ if (!parse_expect_no_attr(xmlbuf, &end) || end) return end;
+
+ memset(&ai, 0, sizeof(ai));
+ ai.optional = optional;
+
+ if (!parse_expect_elem(xmlbuf, assemblyIdentityW, asmv1W) ||
+ !parse_assembly_identity_elem(xmlbuf, acl->actctx, &ai))
+ return FALSE;
+
++ //TRACE( "adding name=%s version=%s arch=%s\n", debugstr_w(ai.name), debugstr_version(&ai.version), debugstr_w(ai.arch) );
++
+ /* store the newly found identity for later loading */
+ if (!add_dependent_assembly_id(acl, &ai)) return FALSE;
+
+ while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
+ {
+ if (xmlstr_cmp_end(&elem, dependentAssemblyW))
+ {
+ ret = parse_end_element(xmlbuf);
+ break;
+ }
+ else if (xmlstr_cmp(&elem, bindingRedirectW))
+ {
+ ret = parse_binding_redirect_elem(xmlbuf);
+ }
+ else
+ {
+ DPRINT1("unknown elem %S\n", elem.ptr);
+ ret = parse_unknown_elem(xmlbuf, &elem);
+ }
+ }
+
+ return ret;
+}
+
+static BOOL parse_dependency_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl)
+{
+ xmlstr_t attr_name, attr_value, elem;
+ UNICODE_STRING attr_nameU, attr_valueU;
+ BOOL end = FALSE, ret = TRUE, error, optional = FALSE;
+
+ while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+ {
+ attr_nameU = xmlstr2unicode(&attr_name);
+ attr_valueU = xmlstr2unicode(&attr_value);
+
+ if (xmlstr_cmp(&attr_name, optionalW))
+ {
- static BOOL parse_file_elem(xmlbuf_t* xmlbuf, struct assembly* assembly)
+ optional = xmlstr_cmpi( &attr_value, yesW );
+ DPRINT1("optional=%wZ\n", &attr_valueU);
+ }
+ else
+ {
+ DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
+ }
+ }
+
+ while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
+ {
+ if (xmlstr_cmp_end(&elem, dependencyW))
+ {
+ ret = parse_end_element(xmlbuf);
+ break;
+ }
+ else if (xmlstr_cmp(&elem, dependentAssemblyW))
+ {
+ ret = parse_dependent_assembly_elem(xmlbuf, acl, optional);
+ }
+ else
+ {
+ attr_nameU = xmlstr2unicode(&elem);
+ DPRINT1("unknown element %wZ\n", &attr_nameU);
+ ret = parse_unknown_elem(xmlbuf, &elem);
+ }
+ }
+
+ return ret;
+}
+
+static BOOL parse_noinherit_elem(xmlbuf_t* xmlbuf)
+{
+ BOOL end = FALSE;
+
+ if (!parse_expect_no_attr(xmlbuf, &end)) return FALSE;
+ return end || parse_expect_end_elem(xmlbuf, noInheritW, asmv1W);
+}
+
+static BOOL parse_noinheritable_elem(xmlbuf_t* xmlbuf)
+{
+ BOOL end = FALSE;
+
+ if (!parse_expect_no_attr(xmlbuf, &end)) return FALSE;
+ return end || parse_expect_end_elem(xmlbuf, noInheritableW, asmv1W);
+}
+
- ret = parse_com_class_elem(xmlbuf, dll);
++static BOOL parse_file_elem(xmlbuf_t* xmlbuf, struct assembly* assembly, struct actctx_loader* acl)
+{
+ xmlstr_t attr_name, attr_value, elem;
+ UNICODE_STRING attr_nameU, attr_valueU;
+ BOOL end = FALSE, error, ret = TRUE;
+ struct dll_redirect* dll;
+
+ if (!(dll = add_dll_redirect(assembly))) return FALSE;
+
+ while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+ {
+ attr_nameU = xmlstr2unicode(&attr_name);
+ attr_valueU = xmlstr2unicode(&attr_value);
+
+ if (xmlstr_cmp(&attr_name, g_nameW))
+ {
+ if (!(dll->name = xmlstrdupW(&attr_value))) return FALSE;
+ DPRINT("name=%wZ\n", &attr_valueU);
+ }
+ else if (xmlstr_cmp(&attr_name, hashW))
+ {
+ if (!(dll->hash = xmlstrdupW(&attr_value))) return FALSE;
+ }
+ else if (xmlstr_cmp(&attr_name, hashalgW))
+ {
+ static const WCHAR sha1W[] = {'S','H','A','1',0};
+ if (!xmlstr_cmpi(&attr_value, sha1W))
+ DPRINT1("hashalg should be SHA1, got %wZ\n", &attr_valueU);
+ }
+ else
+ {
+ DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
+ }
+ }
+
+ if (error || !dll->name) return FALSE;
++
++ acl->actctx->sections |= DLLREDIRECT_SECTION;
++
+ if (end) return TRUE;
+
+ while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
+ {
+ if (xmlstr_cmp_end(&elem, fileW))
+ {
+ ret = parse_end_element(xmlbuf);
+ break;
+ }
+ else if (xmlstr_cmp(&elem, comClassW))
+ {
- ret = parse_cominterface_proxy_stub_elem(xmlbuf, dll);
++ ret = parse_com_class_elem(xmlbuf, dll, acl);
+ }
+ else if (xmlstr_cmp(&elem, comInterfaceProxyStubW))
+ {
- else if (xmlstr_cmp(&elem, asmv2hashW))
++ ret = parse_cominterface_proxy_stub_elem(xmlbuf, dll, acl);
+ }
- ret = parse_typelib_elem(xmlbuf, dll);
++ else if (xml_elem_cmp(&elem, hashW, asmv2W))
+ {
+ DPRINT1("asmv2hash (undocumented) not supported\n");
+ ret = parse_unknown_elem(xmlbuf, &elem);
+ }
+ else if (xmlstr_cmp(&elem, typelibW))
+ {
- ret = parse_window_class_elem(xmlbuf, dll);
++ ret = parse_typelib_elem(xmlbuf, dll, acl);
+ }
+ else if (xmlstr_cmp(&elem, windowClassW))
+ {
- if (xmlstr_cmp(&elem, noInheritableW))
++ ret = parse_window_class_elem(xmlbuf, dll, acl);
+ }
+ else
+ {
+ attr_nameU = xmlstr2unicode(&elem);
+ DPRINT1("unknown elem %wZ\n", &attr_nameU);
+ ret = parse_unknown_elem( xmlbuf, &elem );
+ }
+ }
+
+ return ret;
+}
+
+static BOOL parse_assembly_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl,
+ struct assembly* assembly,
+ struct assembly_identity* expected_ai)
+{
+ xmlstr_t attr_name, attr_value, elem;
+ UNICODE_STRING attr_nameU, attr_valueU;
+ BOOL end = FALSE, error, version = FALSE, xmlns = FALSE, ret = TRUE;
+
++ DPRINT("(%p)\n", xmlbuf);
++
+ while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+ {
+ attr_nameU = xmlstr2unicode(&attr_name);
+ attr_valueU = xmlstr2unicode(&attr_value);
+
+ if (xmlstr_cmp(&attr_name, manifestVersionW))
+ {
+ static const WCHAR v10W[] = {'1','.','0',0};
+ if (!xmlstr_cmp(&attr_value, v10W))
+ {
+ DPRINT1("wrong version %wZ\n", &attr_valueU);
+ return FALSE;
+ }
+ version = TRUE;
+ }
+ else if (xmlstr_cmp(&attr_name, xmlnsW))
+ {
+ if (!xmlstr_cmp(&attr_value, manifestv1W) && !xmlstr_cmp(&attr_value, manifestv3W))
+ {
+ DPRINT1("wrong namespace %wZ\n", &attr_valueU);
+ return FALSE;
+ }
+ xmlns = TRUE;
+ }
+ else
+ {
+ DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
+ }
+ }
+
+ if (error || end || !xmlns || !version) return FALSE;
+ if (!next_xml_elem(xmlbuf, &elem)) return FALSE;
+
+ if (assembly->type == APPLICATION_MANIFEST && xmlstr_cmp(&elem, noInheritW))
+ {
+ if (!parse_noinherit_elem(xmlbuf) || !next_xml_elem(xmlbuf, &elem))
+ return FALSE;
+ assembly->no_inherit = TRUE;
+ }
+
- if (xmlstr_cmp_end(&elem, assemblyW))
++ if (xml_elem_cmp(&elem, noInheritableW, asmv1W))
+ {
+ if (!parse_noinheritable_elem(xmlbuf) || !next_xml_elem(xmlbuf, &elem))
+ return FALSE;
+ }
+ else if ((assembly->type == ASSEMBLY_MANIFEST || assembly->type == ASSEMBLY_SHARED_MANIFEST) &&
+ assembly->no_inherit)
+ return FALSE;
+
+ while (ret)
+ {
- else if (xmlstr_cmp(&elem, descriptionW))
++ if (xml_elem_cmp_end(&elem, assemblyW, asmv1W))
+ {
+ ret = parse_end_element(xmlbuf);
+ break;
+ }
- else if (xmlstr_cmp(&elem, comInterfaceExternalProxyStubW))
++ else if (xml_elem_cmp(&elem, descriptionW, asmv1W))
+ {
+ ret = parse_description_elem(xmlbuf);
+ }
- ret = parse_com_interface_external_proxy_stub_elem(xmlbuf, assembly);
++ else if (xml_elem_cmp(&elem, comInterfaceExternalProxyStubW, asmv1W))
+ {
- else if (xmlstr_cmp(&elem, dependencyW))
++ ret = parse_com_interface_external_proxy_stub_elem(xmlbuf, assembly, acl);
+ }
- else if (xmlstr_cmp(&elem, fileW))
++ else if (xml_elem_cmp(&elem, dependencyW, asmv1W))
+ {
+ ret = parse_dependency_elem(xmlbuf, acl);
+ }
- ret = parse_file_elem(xmlbuf, assembly);
++ else if (xml_elem_cmp(&elem, fileW, asmv1W))
+ {
- else if (xmlstr_cmp(&elem, clrClassW))
++ ret = parse_file_elem(xmlbuf, assembly, acl);
+ }
- ret = parse_clr_class_elem(xmlbuf, assembly);
++ else if (xml_elem_cmp(&elem, clrClassW, asmv1W))
+ {
- else if (xmlstr_cmp(&elem, clrSurrogateW))
++ ret = parse_clr_class_elem(xmlbuf, assembly, acl);
+ }
- ret = parse_clr_surrogate_elem(xmlbuf, assembly);
++ else if (xml_elem_cmp(&elem, clrSurrogateW, asmv1W))
+ {
- else if (xmlstr_cmp(&elem, assemblyIdentityW))
++ ret = parse_clr_surrogate_elem(xmlbuf, assembly, acl);
+ }
- if (!xmlstr_cmp(&elem, assemblyW))
++ else if (xml_elem_cmp(&elem, assemblyIdentityW, asmv1W))
+ {
+ if (!parse_assembly_identity_elem(xmlbuf, acl->actctx, &assembly->id)) return FALSE;
+
+ if (expected_ai)
+ {
+ /* FIXME: more tests */
+ if (assembly->type == ASSEMBLY_MANIFEST &&
+ memcmp(&assembly->id.version, &expected_ai->version, sizeof(assembly->id.version)))
+ {
+ DPRINT1("wrong version for assembly manifest: %u.%u.%u.%u / %u.%u.%u.%u\n",
+ expected_ai->version.major, expected_ai->version.minor,
+ expected_ai->version.build, expected_ai->version.revision,
+ assembly->id.version.major, assembly->id.version.minor,
+ assembly->id.version.build, assembly->id.version.revision);
+ ret = FALSE;
+ }
+ else if (assembly->type == ASSEMBLY_SHARED_MANIFEST &&
+ (assembly->id.version.major != expected_ai->version.major ||
+ assembly->id.version.minor != expected_ai->version.minor ||
+ assembly->id.version.build < expected_ai->version.build ||
+ (assembly->id.version.build == expected_ai->version.build &&
+ assembly->id.version.revision < expected_ai->version.revision)))
+ {
+ DPRINT1("wrong version for shared assembly manifest\n");
+ ret = FALSE;
+ }
+ }
+ }
+ else
+ {
+ attr_nameU = xmlstr2unicode(&elem);
+ DPRINT1("unknown element %wZ\n", &attr_nameU);
+ ret = parse_unknown_elem(xmlbuf, &elem);
+ }
+ if (ret) ret = next_xml_elem(xmlbuf, &elem);
+ }
+
+ return ret;
+}
+
+static NTSTATUS parse_manifest_buffer( struct actctx_loader* acl, struct assembly *assembly,
+ struct assembly_identity* ai, xmlbuf_t *xmlbuf )
+{
+ xmlstr_t elem;
+ UNICODE_STRING elemU;
+
+ if (!next_xml_elem(xmlbuf, &elem)) return STATUS_SXS_CANT_GEN_ACTCTX;
+
+ if (xmlstr_cmp(&elem, g_xmlW) &&
+ (!parse_xml_header(xmlbuf) || !next_xml_elem(xmlbuf, &elem)))
+ return STATUS_SXS_CANT_GEN_ACTCTX;
+
-
++ if (!xml_elem_cmp(&elem, assemblyW, asmv1W))
+ {
+ elemU = xmlstr2unicode(&elem);
+ DPRINT1("root element is %wZ, not <assembly>\n", &elemU);
+ return STATUS_SXS_CANT_GEN_ACTCTX;
+ }
+
+ if (!parse_assembly_elem(xmlbuf, acl, assembly, ai))
+ {
+ DPRINT1("failed to parse manifest %S\n", assembly->manifest.info );
+ return STATUS_SXS_CANT_GEN_ACTCTX;
+ }
+
+ if (next_xml_elem(xmlbuf, &elem))
+ {
+ elemU = xmlstr2unicode(&elem);
+ DPRINT1("unexpected element %wZ\n", &elemU);
+ return STATUS_SXS_CANT_GEN_ACTCTX;
+ }
+
+ if (xmlbuf->ptr != xmlbuf->end)
+ {
+ DPRINT1("parse error\n");
+ return STATUS_SXS_CANT_GEN_ACTCTX;
+ }
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS parse_manifest( struct actctx_loader* acl, struct assembly_identity* ai,
+ LPCWSTR filename, LPCWSTR directory, BOOL shared,
+ const void *buffer, SIZE_T size )
+{
+ xmlbuf_t xmlbuf;
+ NTSTATUS status;
+ struct assembly *assembly;
+ int unicode_tests;
+
+ DPRINT( "parsing manifest loaded from %S base dir %S\n", filename, directory );
+
+ if (!(assembly = add_assembly(acl->actctx, shared ? ASSEMBLY_SHARED_MANIFEST : ASSEMBLY_MANIFEST)))
+ return STATUS_SXS_CANT_GEN_ACTCTX;
+
+ if (directory && !(assembly->directory = strdupW(directory)))
+ return STATUS_NO_MEMORY;
+
+ if (filename) assembly->manifest.info = strdupW( filename + 4 /* skip \??\ prefix */ );
+ assembly->manifest.type = assembly->manifest.info ? ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE
+ : ACTIVATION_CONTEXT_PATH_TYPE_NONE;
+
+ unicode_tests = IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_REVERSE_SIGNATURE;
+ if (RtlIsTextUnicode((PVOID)buffer, (ULONG)size, &unicode_tests ))
+ {
+ xmlbuf.ptr = buffer;
+ xmlbuf.end = xmlbuf.ptr + size / sizeof(WCHAR);
+ status = parse_manifest_buffer( acl, assembly, ai, &xmlbuf );
+ }
+ else if (unicode_tests & IS_TEXT_UNICODE_REVERSE_SIGNATURE)
+ {
+ const WCHAR *buf = buffer;
+ WCHAR *new_buff;
+ unsigned int i;
+
+ if (!(new_buff = RtlAllocateHeap( RtlGetProcessHeap(), 0, size )))
+ return STATUS_NO_MEMORY;
+ for (i = 0; i < size / sizeof(WCHAR); i++)
+ new_buff[i] = RtlUshortByteSwap( buf[i] );
+ xmlbuf.ptr = new_buff;
+ xmlbuf.end = xmlbuf.ptr + size / sizeof(WCHAR);
+ status = parse_manifest_buffer( acl, assembly, ai, &xmlbuf );
+ RtlFreeHeap( RtlGetProcessHeap(), 0, new_buff );
+ }
+ else
+ {
+ /* TODO: this doesn't handle arbitrary encodings */
+ WCHAR *new_buff;
+ ULONG sizeU;
+
+ status = RtlMultiByteToUnicodeSize(&sizeU, buffer, size);
+ if (!NT_SUCCESS(status))
+ {
+ DPRINT1("RtlMultiByteToUnicodeSize failed with %lx\n", status);
+ return STATUS_SXS_CANT_GEN_ACTCTX;
+ }
+
+ new_buff = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeU);
+ if (!new_buff)
+ return STATUS_NO_MEMORY;
+
+ status = RtlMultiByteToUnicodeN(new_buff, sizeU, &sizeU, buffer, size);
+ if (!NT_SUCCESS(status))
+ {
+ DPRINT1("RtlMultiByteToUnicodeN failed with %lx\n", status);
+ return STATUS_SXS_CANT_GEN_ACTCTX;
+ }
+
+ xmlbuf.ptr = new_buff;
+ xmlbuf.end = xmlbuf.ptr + sizeU / sizeof(WCHAR);
+ status = parse_manifest_buffer(acl, assembly, ai, &xmlbuf);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, new_buff);
+ }
+ return status;
+}
+
+static NTSTATUS open_nt_file( HANDLE *handle, UNICODE_STRING *name )
+{
+ OBJECT_ATTRIBUTES attr;
+ IO_STATUS_BLOCK io;
+
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = 0;
+ attr.Attributes = OBJ_CASE_INSENSITIVE;
+ attr.ObjectName = name;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+ return NtOpenFile(handle,
+ GENERIC_READ | SYNCHRONIZE,
+ &attr, &io,
+ FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_ALERT);
+}
+
+static NTSTATUS get_module_filename( HMODULE module, UNICODE_STRING *str, USHORT extra_len )
+{
+ NTSTATUS status;
+ ULONG magic;
+ LDR_DATA_TABLE_ENTRY *pldr;
+
+ LdrLockLoaderLock(0, NULL, &magic);
+ status = LdrFindEntryForAddress( module, &pldr );
+ if (status == STATUS_SUCCESS)
+ {
+ if ((str->Buffer = RtlAllocateHeap( RtlGetProcessHeap(), 0,
+ pldr->FullDllName.Length + extra_len + sizeof(WCHAR) )))
+ {
+ memcpy( str->Buffer, pldr->FullDllName.Buffer, pldr->FullDllName.Length + sizeof(WCHAR) );
+ str->Length = pldr->FullDllName.Length;
+ str->MaximumLength = pldr->FullDllName.Length + extra_len + sizeof(WCHAR);
+ }
+ else status = STATUS_NO_MEMORY;
+ }
+ LdrUnlockLoaderLock(0, magic);
+ return status;
+}
+
+static NTSTATUS get_manifest_in_module( struct actctx_loader* acl, struct assembly_identity* ai,
+ LPCWSTR filename, LPCWSTR directory, BOOL shared,
+ HANDLE hModule, LPCWSTR resname, ULONG lang )
+{
+ NTSTATUS status;
+ UNICODE_STRING nameW;
+ LDR_RESOURCE_INFO info;
+ IMAGE_RESOURCE_DATA_ENTRY* entry = NULL;
+ void *ptr;
+
+ //DPRINT( "looking for res %s in module %p %s\n", resname,
+ // hModule, filename );
+
+#if 0
+ if (TRACE_ON(actctx))
+ {
+ if (!filename && !get_module_filename( hModule, &nameW, 0 ))
+ {
+ DPRINT( "looking for res %s in module %p %s\n", debugstr_w(resname),
+ hModule, debugstr_w(nameW.Buffer) );
+ RtlFreeUnicodeString( &nameW );
+ }
+ else DPRINT( "looking for res %s in module %p %s\n", debugstr_w(resname),
+ hModule, debugstr_w(filename) );
+ }
+#endif
+
+ if (!resname) return STATUS_INVALID_PARAMETER;
+
+ info.Type = (ULONG_PTR)RT_MANIFEST;
+ info.Language = lang;
+ if (!((ULONG_PTR)resname >> 16))
+ {
+ info.Name = (ULONG_PTR)resname;
+ status = LdrFindResource_U(hModule, &info, 3, &entry);
+ }
+ else if (resname[0] == '#')
+ {
+ ULONG value;
+ RtlInitUnicodeString(&nameW, resname + 1);
+ if (RtlUnicodeStringToInteger(&nameW, 10, &value) != STATUS_SUCCESS || HIWORD(value))
+ return STATUS_INVALID_PARAMETER;
+ info.Name = value;
+ status = LdrFindResource_U(hModule, &info, 3, &entry);
+ }
+ else
+ {
+ RtlCreateUnicodeString(&nameW, resname);
+ RtlUpcaseUnicodeString(&nameW, &nameW, FALSE);
+ info.Name = (ULONG_PTR)nameW.Buffer;
+ status = LdrFindResource_U(hModule, &info, 3, &entry);
+ RtlFreeUnicodeString(&nameW);
+ }
+ if (status == STATUS_SUCCESS) status = LdrAccessResource(hModule, entry, &ptr, NULL);
+
+ if (status == STATUS_SUCCESS)
+ status = parse_manifest(acl, ai, filename, directory, shared, ptr, entry->Size);
+
+ return status;
+}
+
+static NTSTATUS get_manifest_in_pe_file( struct actctx_loader* acl, struct assembly_identity* ai,
+ LPCWSTR filename, LPCWSTR directory, BOOL shared,
+ HANDLE file, LPCWSTR resname, ULONG lang )
+{
+ HANDLE mapping;
+ OBJECT_ATTRIBUTES attr;
+ LARGE_INTEGER size;
+ LARGE_INTEGER offset;
+ NTSTATUS status;
+ SIZE_T count;
+ void *base;
+
+ DPRINT( "looking for res %S in %S\n", resname, filename );
+
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = 0;
+ attr.ObjectName = NULL;
+ attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+
+ size.QuadPart = 0;
+ status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
+ &attr, &size, PAGE_READONLY, SEC_COMMIT, file );
+ if (status != STATUS_SUCCESS) return status;
+
+ offset.QuadPart = 0;
+ count = 0;
+ base = NULL;
+ status = NtMapViewOfSection( mapping, NtCurrentProcess(), &base, 0, 0, &offset,
+ &count, ViewShare, 0, PAGE_READONLY );
+ NtClose( mapping );
+ if (status != STATUS_SUCCESS) return status;
+
+ if (RtlImageNtHeader(base)) /* we got a PE file */
+ {
+ HANDLE module = (HMODULE)((ULONG_PTR)base | 1); /* make it a LOAD_LIBRARY_AS_DATAFILE handle */
+ status = get_manifest_in_module( acl, ai, filename, directory, shared, module, resname, lang );
+ }
+ else status = STATUS_INVALID_IMAGE_FORMAT;
+
+ NtUnmapViewOfSection( NtCurrentProcess(), base );
+ return status;
+}
+
+static NTSTATUS get_manifest_in_manifest_file( struct actctx_loader* acl, struct assembly_identity* ai,
+ LPCWSTR filename, LPCWSTR directory, BOOL shared, HANDLE file )
+{
+ FILE_STANDARD_INFORMATION info;
+ IO_STATUS_BLOCK io;
+ HANDLE mapping;
+ OBJECT_ATTRIBUTES attr;
+ LARGE_INTEGER size;
+ LARGE_INTEGER offset;
+ NTSTATUS status;
+ SIZE_T count;
+ void *base;
+
+ DPRINT( "loading manifest file %S\n", filename );
+
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = 0;
+ attr.ObjectName = NULL;
+ attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+
+ size.QuadPart = 0;
+ status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
+ &attr, &size, PAGE_READONLY, SEC_COMMIT, file );
+
+ if (status != STATUS_SUCCESS) return status;
+
+ offset.QuadPart = 0;
+ count = 0;
+ base = NULL;
+ status = NtMapViewOfSection( mapping, NtCurrentProcess(), &base, 0, 0, &offset,
+ &count, ViewShare, 0, PAGE_READONLY );
- NtClose( mapping );
++ NtClose( mapping );
+ if (status != STATUS_SUCCESS) return status;
+
+ /* Fixme: WINE uses FileEndOfFileInformation with NtQueryInformationFile. */
+ status = NtQueryInformationFile( file, &io, &info, sizeof(info), FileStandardInformation);
+
+ if (status == STATUS_SUCCESS)
+ status = parse_manifest(acl, ai, filename, directory, shared, base, (SIZE_T)info.EndOfFile.QuadPart);
+
+ NtUnmapViewOfSection( NtCurrentProcess(), base );
- else status = STATUS_RESOURCE_DATA_NOT_FOUND;
+ return status;
+}
+
+/* try to load the .manifest file associated to the file */
+static NTSTATUS get_manifest_in_associated_manifest( struct actctx_loader* acl, struct assembly_identity* ai,
+ LPCWSTR filename, LPCWSTR directory, HMODULE module, LPCWSTR resname )
+{
+ static const WCHAR fmtW[] = { '.','%','l','u',0 };
+ WCHAR *buffer;
+ NTSTATUS status;
+ UNICODE_STRING nameW;
+ HANDLE file;
+ ULONG_PTR resid = (ULONG_PTR)CREATEPROCESS_MANIFEST_RESOURCE_ID;
+
+ if (!((ULONG_PTR)resname >> 16)) resid = (ULONG_PTR)resname & 0xffff;
+
+ DPRINT( "looking for manifest associated with %S id %lu\n", filename, resid );
+
+ if (module) /* use the module filename */
+ {
+ UNICODE_STRING name;
+
+ if (!(status = get_module_filename( module, &name, sizeof(dotManifestW) + 10*sizeof(WCHAR) )))
+ {
+ if (resid != 1) sprintfW( name.Buffer + strlenW(name.Buffer), fmtW, resid );
+ strcatW( name.Buffer, dotManifestW );
+ if (!RtlDosPathNameToNtPathName_U( name.Buffer, &nameW, NULL, NULL ))
+ status = STATUS_RESOURCE_DATA_NOT_FOUND;
+ RtlFreeUnicodeString( &name );
+ }
+ if (status) return status;
+ }
+ else
+ {
+ if (!(buffer = RtlAllocateHeap( RtlGetProcessHeap(), 0,
+ (strlenW(filename) + 10) * sizeof(WCHAR) + sizeof(dotManifestW) )))
+ return STATUS_NO_MEMORY;
+ strcpyW( buffer, filename );
+ if (resid != 1) sprintfW( buffer + strlenW(buffer), fmtW, resid );
+ strcatW( buffer, dotManifestW );
+ RtlInitUnicodeString( &nameW, buffer );
+ }
+
+ if (!open_nt_file( &file, &nameW ))
+ {
+ status = get_manifest_in_manifest_file( acl, ai, nameW.Buffer, directory, FALSE, file );
+ NtClose( file );
+ }
- sprintfW( lookup, lookup_fmtW, ai->arch, ai->name, ai->public_key, ai->version.major, ai->version.minor);
++ else status = STATUS_RESOURCE_TYPE_NOT_FOUND;
+ RtlFreeUnicodeString( &nameW );
+ return status;
+}
+
+static WCHAR *lookup_manifest_file( HANDLE dir, struct assembly_identity *ai )
+{
+ static const WCHAR lookup_fmtW[] =
+ {'%','s','_','%','s','_','%','s','_','%','u','.','%','u','.','*','.','*','_',
+ '*', /* FIXME */
+ '.','m','a','n','i','f','e','s','t',0};
+
+ WCHAR *lookup, *ret = NULL;
+ UNICODE_STRING lookup_us;
+ IO_STATUS_BLOCK io;
++ const WCHAR *lang = ai->language;
+ unsigned int data_pos = 0, data_len;
+ char buffer[8192];
+
+ if (!(lookup = RtlAllocateHeap( RtlGetProcessHeap(), 0,
+ (strlenW(ai->arch) + strlenW(ai->name)
+ + strlenW(ai->public_key) + 20) * sizeof(WCHAR)
+ + sizeof(lookup_fmtW) )))
+ return NULL;
+
- DPRINT1( "Could not find dependent assembly %S\n", acl->dependencies[i].name );
++ if (!lang || !strcmpiW( lang, neutralW )) lang = wildcardW;
++ sprintfW( lookup, lookup_fmtW, ai->arch, ai->name, ai->public_key,
++ ai->version.major, ai->version.minor, lang );
+ RtlInitUnicodeString( &lookup_us, lookup );
+
+ NtQueryDirectoryFile( dir, 0, NULL, NULL, &io, buffer, sizeof(buffer),
+ FileBothDirectoryInformation, FALSE, &lookup_us, TRUE );
+ if (io.Status == STATUS_SUCCESS)
+ {
+ FILE_BOTH_DIR_INFORMATION *dir_info;
+ WCHAR *tmp;
+ ULONG build, revision;
+
+ data_len = (ULONG)io.Information;
+
+ for (;;)
+ {
+ if (data_pos >= data_len)
+ {
+ NtQueryDirectoryFile( dir, 0, NULL, NULL, &io, buffer, sizeof(buffer),
+ FileBothDirectoryInformation, FALSE, &lookup_us, FALSE );
+ if (io.Status != STATUS_SUCCESS) break;
+ data_len = (ULONG)io.Information;
+ data_pos = 0;
+ }
+ dir_info = (FILE_BOTH_DIR_INFORMATION*)(buffer + data_pos);
+
+ if (dir_info->NextEntryOffset) data_pos += dir_info->NextEntryOffset;
+ else data_pos = data_len;
+
+ tmp = (WCHAR *)dir_info->FileName + (strchrW(lookup, '*') - lookup);
+ build = atoiW(tmp);
+ if (build < ai->version.build) continue;
+ tmp = strchrW(tmp, '.') + 1;
+ revision = atoiW(tmp);
+ if (build == ai->version.build && revision < ai->version.revision)
+ continue;
+ ai->version.build = (USHORT)build;
+ ai->version.revision = (USHORT)revision;
+
+ if ((ret = RtlAllocateHeap( RtlGetProcessHeap(), 0, dir_info->FileNameLength * sizeof(WCHAR) )))
+ {
+ memcpy( ret, dir_info->FileName, dir_info->FileNameLength );
+ ret[dir_info->FileNameLength/sizeof(WCHAR)] = 0;
+ }
+ break;
+ }
+ }
+ else DPRINT1("no matching file for %S\n", lookup);
+ RtlFreeHeap( RtlGetProcessHeap(), 0, lookup );
+ return ret;
+}
+
+static NTSTATUS lookup_winsxs(struct actctx_loader* acl, struct assembly_identity* ai)
+{
+ struct assembly_identity sxs_ai;
+ UNICODE_STRING path_us;
+ OBJECT_ATTRIBUTES attr;
+ IO_STATUS_BLOCK io;
+ WCHAR *path, *file = NULL;
+ HANDLE handle;
+
+ static const WCHAR manifest_dirW[] =
+ {'\\','w','i','n','s','x','s','\\','m','a','n','i','f','e','s','t','s',0};
+
+ if (!ai->arch || !ai->name || !ai->public_key) return STATUS_NO_SUCH_FILE;
+
+ if (!(path = RtlAllocateHeap( RtlGetProcessHeap(), 0,
+ ((strlenW(SharedUserData->NtSystemRoot) + 1) *sizeof(WCHAR)) + sizeof(manifest_dirW) )))
+ return STATUS_NO_MEMORY;
+
+ memcpy( path, SharedUserData->NtSystemRoot, strlenW(SharedUserData->NtSystemRoot) * sizeof(WCHAR) );
+ memcpy( path + strlenW(SharedUserData->NtSystemRoot), manifest_dirW, sizeof(manifest_dirW) );
+
+ if (!RtlDosPathNameToNtPathName_U( path, &path_us, NULL, NULL ))
+ {
+ RtlFreeHeap( RtlGetProcessHeap(), 0, path );
+ return STATUS_NO_SUCH_FILE;
+ }
+ RtlFreeHeap( RtlGetProcessHeap(), 0, path );
+
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = 0;
+ attr.Attributes = OBJ_CASE_INSENSITIVE;
+ attr.ObjectName = &path_us;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+
+ if (!NtOpenFile(&handle,
+ GENERIC_READ | SYNCHRONIZE,
+ &attr, &io,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT))
+ {
+ sxs_ai = *ai;
+ file = lookup_manifest_file( handle, &sxs_ai );
+ NtClose( handle );
+ }
+ if (!file)
+ {
+ RtlFreeUnicodeString( &path_us );
+ return STATUS_NO_SUCH_FILE;
+ }
+
+ /* append file name to directory path */
+ if (!(path = RtlReAllocateHeap( RtlGetProcessHeap(), 0, path_us.Buffer,
+ path_us.Length + (strlenW(file) + 2) * sizeof(WCHAR) )))
+ {
+ RtlFreeHeap( RtlGetProcessHeap(), 0, file );
+ RtlFreeUnicodeString( &path_us );
+ return STATUS_NO_MEMORY;
+ }
+
+ path[path_us.Length/sizeof(WCHAR)] = '\\';
+ strcpyW( path + path_us.Length/sizeof(WCHAR) + 1, file );
+ RtlInitUnicodeString( &path_us, path );
+ *strrchrW(file, '.') = 0; /* remove .manifest extension */
+
+ if (!open_nt_file( &handle, &path_us ))
+ {
+ io.Status = get_manifest_in_manifest_file(acl, &sxs_ai, path_us.Buffer, file, TRUE, handle);
+ NtClose( handle );
+ }
+ else io.Status = STATUS_NO_SUCH_FILE;
+
+ RtlFreeHeap( RtlGetProcessHeap(), 0, file );
+ RtlFreeUnicodeString( &path_us );
+ return io.Status;
+}
+
+static NTSTATUS lookup_assembly(struct actctx_loader* acl,
+ struct assembly_identity* ai)
+{
+ static const WCHAR dotDllW[] = {'.','d','l','l',0};
+ unsigned int i;
+ WCHAR *buffer, *p, *directory;
+ NTSTATUS status;
+ UNICODE_STRING nameW;
+ HANDLE file;
+ DWORD len;
+
+ DPRINT( "looking for name=%S version=%u.%u.%u.%u arch=%S\n",
+ ai->name, ai->version.major, ai->version.minor, ai->version.build, ai->version.revision, ai->arch );
+
+ if ((status = lookup_winsxs(acl, ai)) != STATUS_NO_SUCH_FILE) return status;
+
+ /* FIXME: add support for language specific lookup */
+
+ len = max(RtlGetFullPathName_U(acl->actctx->assemblies->manifest.info, 0, NULL, NULL) / sizeof(WCHAR),
+ strlenW(acl->actctx->appdir.info));
+
+ nameW.Buffer = NULL;
+ if (!(buffer = RtlAllocateHeap( RtlGetProcessHeap(), 0,
+ (len + 2 * strlenW(ai->name) + 2) * sizeof(WCHAR) + sizeof(dotManifestW) )))
+ return STATUS_NO_MEMORY;
+
+ if (!(directory = build_assembly_dir( ai )))
+ {
+ RtlFreeHeap( RtlGetProcessHeap(), 0, buffer );
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Lookup in <dir>\name.dll
+ * <dir>\name.manifest
+ * <dir>\name\name.dll
+ * <dir>\name\name.manifest
+ *
+ * First 'appdir' is used as <dir>, if that failed
+ * it tries application manifest file path.
+ */
+ strcpyW( buffer, acl->actctx->appdir.info );
+ p = buffer + strlenW(buffer);
+ for (i = 0; i < 4; i++)
+ {
+ if (i == 2)
+ {
+ struct assembly *assembly = acl->actctx->assemblies;
+ if (!RtlGetFullPathName_U(assembly->manifest.info, len * sizeof(WCHAR), buffer, &p)) break;
+ }
+ else *p++ = '\\';
+
+ strcpyW( p, ai->name );
+ p += strlenW(p);
+
+ strcpyW( p, dotDllW );
+ if (RtlDosPathNameToNtPathName_U( buffer, &nameW, NULL, NULL ))
+ {
+ status = open_nt_file( &file, &nameW );
+ if (!status)
+ {
+ status = get_manifest_in_pe_file( acl, ai, nameW.Buffer, directory, FALSE, file,
+ (LPCWSTR)CREATEPROCESS_MANIFEST_RESOURCE_ID, 0 );
+ NtClose( file );
+ break;
+ }
+ RtlFreeUnicodeString( &nameW );
+ }
+
+ strcpyW( p, dotManifestW );
+ if (RtlDosPathNameToNtPathName_U( buffer, &nameW, NULL, NULL ))
+ {
+ status = open_nt_file( &file, &nameW );
+ if (!status)
+ {
+ status = get_manifest_in_manifest_file( acl, ai, nameW.Buffer, directory, FALSE, file );
+ NtClose( file );
+ break;
+ }
+ RtlFreeUnicodeString( &nameW );
+ }
+ status = STATUS_SXS_ASSEMBLY_NOT_FOUND;
+ }
+ RtlFreeUnicodeString( &nameW );
+ RtlFreeHeap( RtlGetProcessHeap(), 0, directory );
+ RtlFreeHeap( RtlGetProcessHeap(), 0, buffer );
+ return status;
+}
+
+static NTSTATUS parse_depend_manifests(struct actctx_loader* acl)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ unsigned int i;
+
+ for (i = 0; i < acl->num_dependencies; i++)
+ {
+ if (lookup_assembly(acl, &acl->dependencies[i]) != STATUS_SUCCESS)
+ {
+ if (!acl->dependencies[i].optional)
+ {
- static NTSTATUS fill_keyed_data(PACTCTX_SECTION_KEYED_DATA data, PVOID v1, PVOID v2, unsigned int i)
++ const struct assembly_version *ver = &acl->dependencies[i].version;
++ DPRINT1( "Could not find dependent assembly %S (%u.%u.%u.%u)\n",
++ acl->dependencies[i].name,
++ ver->major, ver->minor, ver->build, ver->revision );
+ status = STATUS_SXS_CANT_GEN_ACTCTX;
+ break;
+ }
+ }
+ }
+ /* FIXME should now iterate through all refs */
+ return status;
+}
+
+/* find the appropriate activation context for RtlQueryInformationActivationContext */
+static NTSTATUS find_query_actctx( HANDLE *handle, DWORD flags, ULONG class )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ if (flags & RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT)
+ {
+ if (*handle) return STATUS_INVALID_PARAMETER;
+
+ if (NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame)
+ *handle = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame->ActivationContext;
+ }
+ else if (flags & (RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_ADDRESS | RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_HMODULE))
+ {
+ ULONG magic;
+ LDR_DATA_TABLE_ENTRY *pldr;
+
+ if (!*handle) return STATUS_INVALID_PARAMETER;
+
+ LdrLockLoaderLock( 0, NULL, &magic );
+ if (!LdrFindEntryForAddress( *handle, &pldr ))
+ {
+ if ((flags & RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_HMODULE) && *handle != pldr->DllBase)
+ status = STATUS_DLL_NOT_FOUND;
+ else
+ *handle = pldr->EntryPointActivationContext;
+ }
+ else status = STATUS_DLL_NOT_FOUND;
+ LdrUnlockLoaderLock( 0, magic );
+ }
+ else if (!*handle && (class != ActivationContextBasicInformation))
+ *handle = process_actctx;
+
+ return status;
+}
+
- data->lpData = v1;
- data->ulLength = 20; /* FIXME */
- data->lpSectionGlobalData = NULL; /* FIXME */
- data->ulSectionGlobalDataLength = 0; /* FIXME */
- data->lpSectionBase = v2;
- data->ulSectionTotalLength = 0; /* FIXME */
++static NTSTATUS build_dllredirect_section(ACTIVATION_CONTEXT* actctx, struct strsection_header **section)
++{
++ unsigned int i, j, total_len = 0, dll_count = 0;
++ struct strsection_header *header;
++ struct dllredirect_data *data;
++ struct string_index *index;
++ ULONG name_offset;
++
++ /* compute section length */
++ for (i = 0; i < actctx->num_assemblies; i++)
++ {
++ struct assembly *assembly = &actctx->assemblies[i];
++ for (j = 0; j < assembly->num_dlls; j++)
++ {
++ struct dll_redirect *dll = &assembly->dlls[j];
++
++ /* each entry needs index, data and string data */
++ total_len += sizeof(*index);
++ total_len += sizeof(*data);
++ total_len += aligned_string_len((strlenW(dll->name)+1)*sizeof(WCHAR));
++ }
++
++ dll_count += assembly->num_dlls;
++ }
++
++ total_len += sizeof(*header);
++
++ header = RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len);
++ if (!header) return STATUS_NO_MEMORY;
++
++ memset(header, 0, sizeof(*header));
++ header->magic = STRSECTION_MAGIC;
++ header->size = sizeof(*header);
++ header->count = dll_count;
++ header->index_offset = sizeof(*header);
++ index = (struct string_index*)((BYTE*)header + header->index_offset);
++ name_offset = header->index_offset + header->count*sizeof(*index);
++
++ for (i = 0; i < actctx->num_assemblies; i++)
++ {
++ struct assembly *assembly = &actctx->assemblies[i];
++ for (j = 0; j < assembly->num_dlls; j++)
++ {
++ struct dll_redirect *dll = &assembly->dlls[j];
++ UNICODE_STRING str;
++ WCHAR *ptrW;
++
++ /* setup new index entry */
++ str.Buffer = dll->name;
++ str.Length = strlenW(dll->name)*sizeof(WCHAR);
++ str.MaximumLength = str.Length + sizeof(WCHAR);
++ /* hash original class name */
++ RtlHashUnicodeString(&str, TRUE, HASH_STRING_ALGORITHM_X65599, &index->hash);
++
++ index->name_offset = name_offset;
++ index->name_len = str.Length;
++ index->data_offset = index->name_offset + aligned_string_len(str.MaximumLength);
++ index->data_len = sizeof(*data);
++ index->rosterindex = i + 1;
++
++ /* setup data */
++ data = (struct dllredirect_data*)((BYTE*)header + index->data_offset);
++ data->size = sizeof(*data);
++ data->unk = 2; /* FIXME: seems to be constant */
++ memset(data->res, 0, sizeof(data->res));
++
++ /* dll name */
++ ptrW = (WCHAR*)((BYTE*)header + index->name_offset);
++ memcpy(ptrW, dll->name, index->name_len);
++ ptrW[index->name_len/sizeof(WCHAR)] = 0;
++
++ name_offset += sizeof(*data) + aligned_string_len(str.MaximumLength);
++
++ index++;
++ }
++ }
++
++ *section = header;
++
++ return STATUS_SUCCESS;
++}
++
++static struct string_index *find_string_index(const struct strsection_header *section, const UNICODE_STRING *name)
++{
++ struct string_index *iter, *index = NULL;
++ ULONG hash = 0, i;
++
++ RtlHashUnicodeString(name, TRUE, HASH_STRING_ALGORITHM_X65599, &hash);
++ iter = (struct string_index*)((BYTE*)section + section->index_offset);
++
++ for (i = 0; i < section->count; i++)
++ {
++ if (iter->hash == hash)
++ {
++ const WCHAR *nameW = (WCHAR*)((BYTE*)section + iter->name_offset);
++
++ if (!strcmpiW(nameW, name->Buffer))
++ {
++ index = iter;
++ break;
++ }
++ else
++ DPRINT1("hash collision 0x%08x, %wZ, %S\n", hash, name, nameW);
++ }
++ iter++;
++ }
++
++ return index;
++}
++
++static struct guid_index *find_guid_index(const struct guidsection_header *section, const GUID *guid)
++{
++ struct guid_index *iter, *index = NULL;
++ ULONG i;
++
++ iter = (struct guid_index*)((BYTE*)section + section->index_offset);
++
++ for (i = 0; i < section->count; i++)
++ {
++ if (!memcmp(guid, &iter->guid, sizeof(*guid)))
++ {
++ index = iter;
++ break;
++ }
++ iter++;
++ }
++
++ return index;
++}
++
++static inline struct dllredirect_data *get_dllredirect_data(ACTIVATION_CONTEXT *ctxt, struct string_index *index)
++{
++ return (struct dllredirect_data*)((BYTE*)ctxt->dllredirect_section + index->data_offset);
++}
++
++static NTSTATUS find_dll_redirection(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *name,
++ PACTCTX_SECTION_KEYED_DATA data)
+{
++ struct dllredirect_data *dll;
++ struct string_index *index;
++
++ if (!(actctx->sections & DLLREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;
++
++ if (!actctx->dllredirect_section)
++ {
++ struct strsection_header *section;
++
++ NTSTATUS status = build_dllredirect_section(actctx, §ion);
++ if (status) return status;
++
++ if (InterlockedCompareExchangePointer((void**)&actctx->dllredirect_section, section, NULL))
++ RtlFreeHeap(RtlGetProcessHeap(), 0, section);
++ }
++
++ index = find_string_index(actctx->dllredirect_section, name);
++ if (!index) return STATUS_SXS_KEY_NOT_FOUND;
++
++ dll = get_dllredirect_data(actctx, index);
++
+ data->ulDataFormatVersion = 1;
- if (data->cbSize >= offsetof(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
- data->ulAssemblyRosterIndex = i + 1;
++ data->lpData = dll;
++ data->ulLength = dll->size;
++ data->lpSectionGlobalData = NULL;
++ data->ulSectionGlobalDataLength = 0;
++ data->lpSectionBase = actctx->dllredirect_section;
++ data->ulSectionTotalLength = RtlSizeHeap( RtlGetProcessHeap(), 0, actctx->dllredirect_section );
+ data->hActCtx = NULL;
- static NTSTATUS find_dll_redirection(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *section_name,
- PACTCTX_SECTION_KEYED_DATA data)
++
++ if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
++ data->ulAssemblyRosterIndex = index->rosterindex;
+
+ return STATUS_SUCCESS;
+}
+
- unsigned int i, j, snlen = section_name->Length / sizeof(WCHAR);
++static inline struct string_index *get_wndclass_first_index(ACTIVATION_CONTEXT *actctx)
++{
++ return (struct string_index*)((BYTE*)actctx->wndclass_section + actctx->wndclass_section->index_offset);
++}
++
++static inline struct wndclass_redirect_data *get_wndclass_data(ACTIVATION_CONTEXT *ctxt, struct string_index *index)
+{
- if (!strncmpiW(section_name->Buffer, dll->name, snlen) && !dll->name[snlen])
- return fill_keyed_data(data, dll, assembly, i);
++ return (struct wndclass_redirect_data*)((BYTE*)ctxt->wndclass_section + index->data_offset);
++}
++
++static NTSTATUS build_wndclass_section(ACTIVATION_CONTEXT* actctx, struct strsection_header **section)
++{
++ unsigned int i, j, k, total_len = 0, class_count = 0;
++ struct wndclass_redirect_data *data;
++ struct strsection_header *header;
++ struct string_index *index;
++ ULONG name_offset;
+
++ /* compute section length */
+ for (i = 0; i < actctx->num_assemblies; i++)
+ {
+ struct assembly *assembly = &actctx->assemblies[i];
+ for (j = 0; j < assembly->num_dlls; j++)
+ {
+ struct dll_redirect *dll = &assembly->dlls[j];
- return STATUS_SXS_KEY_NOT_FOUND;
- }
++ for (k = 0; k < dll->entities.num; k++)
++ {
++ struct entity *entity = &dll->entities.base[k];
++ if (entity->kind == ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION)
++ {
++ int class_len = strlenW(entity->u.class.name) + 1;
++ int len;
++
++ /* each class entry needs index, data and string data */
++ total_len += sizeof(*index);
++ total_len += sizeof(*data);
++ /* original name is stored separately */
++ total_len += aligned_string_len(class_len*sizeof(WCHAR));
++ /* versioned name and module name are stored one after another */
++ if (entity->u.class.versioned)
++ len = get_assembly_version(assembly, NULL) + class_len + 1 /* '!' separator */;
++ else
++ len = class_len;
++ len += strlenW(dll->name) + 1;
++ total_len += aligned_string_len(len*sizeof(WCHAR));
++
++ class_count++;
++ }
++ }
+ }
+ }
- static NTSTATUS find_window_class(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *section_name,
- PACTCTX_SECTION_KEYED_DATA data)
- {
- unsigned int i, j, k, snlen = section_name->Length / sizeof(WCHAR);
+
- if (!strncmpiW(section_name->Buffer, entity->u.class.name, snlen) && !entity->u.class.name[snlen])
- return fill_keyed_data(data, entity, dll, i);
++ total_len += sizeof(*header);
++
++ header = RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len);
++ if (!header) return STATUS_NO_MEMORY;
++
++ memset(header, 0, sizeof(*header));
++ header->magic = STRSECTION_MAGIC;
++ header->size = sizeof(*header);
++ header->count = class_count;
++ header->index_offset = sizeof(*header);
++ index = (struct string_index*)((BYTE*)header + header->index_offset);
++ name_offset = header->index_offset + header->count*sizeof(*index);
+
+ for (i = 0; i < actctx->num_assemblies; i++)
+ {
+ struct assembly *assembly = &actctx->assemblies[i];
+ for (j = 0; j < assembly->num_dlls; j++)
+ {
+ struct dll_redirect *dll = &assembly->dlls[j];
+ for (k = 0; k < dll->entities.num; k++)
+ {
+ struct entity *entity = &dll->entities.base[k];
+ if (entity->kind == ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION)
+ {
- return STATUS_SXS_KEY_NOT_FOUND;
++ static const WCHAR exclW[] = {'!',0};
++ ULONG versioned_len, module_len;
++ UNICODE_STRING str;
++ WCHAR *ptrW;
++
++ /* setup new index entry */
++ str.Buffer = entity->u.class.name;
++ str.Length = strlenW(entity->u.class.name)*sizeof(WCHAR);
++ str.MaximumLength = str.Length + sizeof(WCHAR);
++ /* hash original class name */
++ RtlHashUnicodeString(&str, TRUE, HASH_STRING_ALGORITHM_X65599, &index->hash);
++
++ /* include '!' separator too */
++ if (entity->u.class.versioned)
++ versioned_len = (get_assembly_version(assembly, NULL) + 1)*sizeof(WCHAR) + str.Length;
++ else
++ versioned_len = str.Length;
++ module_len = strlenW(dll->name)*sizeof(WCHAR);
++
++ index->name_offset = name_offset;
++ index->name_len = str.Length;
++ index->data_offset = index->name_offset + aligned_string_len(str.MaximumLength);
++ index->data_len = sizeof(*data) + versioned_len + module_len + 2*sizeof(WCHAR) /* two nulls */;
++ index->rosterindex = i + 1;
++
++ /* setup data */
++ data = (struct wndclass_redirect_data*)((BYTE*)header + index->data_offset);
++ data->size = sizeof(*data);
++ data->res = 0;
++ data->name_len = versioned_len;
++ data->name_offset = sizeof(*data);
++ data->module_len = module_len;
++ data->module_offset = index->data_offset + data->name_offset + data->name_len + sizeof(WCHAR);
++
++ /* original class name */
++ ptrW = (WCHAR*)((BYTE*)header + index->name_offset);
++ memcpy(ptrW, entity->u.class.name, index->name_len);
++ ptrW[index->name_len/sizeof(WCHAR)] = 0;
++
++ /* module name */
++ ptrW = (WCHAR*)((BYTE*)header + data->module_offset);
++ memcpy(ptrW, dll->name, data->module_len);
++ ptrW[data->module_len/sizeof(WCHAR)] = 0;
++
++ /* versioned name */
++ ptrW = (WCHAR*)((BYTE*)data + data->name_offset);
++ if (entity->u.class.versioned)
++ {
++ get_assembly_version(assembly, ptrW);
++ strcatW(ptrW, exclW);
++ strcatW(ptrW, entity->u.class.name);
++ }
++ else
++ {
++ memcpy(ptrW, entity->u.class.name, index->name_len);
++ ptrW[index->name_len/sizeof(WCHAR)] = 0;
++ }
++
++ name_offset += sizeof(*data);
++ name_offset += aligned_string_len(str.MaximumLength) + aligned_string_len(versioned_len + module_len + 2*sizeof(WCHAR));
++
++ index++;
+ }
+ }
+ }
+ }
- static NTSTATUS find_string(ACTIVATION_CONTEXT* actctx, ULONG section_kind,
- const UNICODE_STRING *section_name,
- DWORD flags, PACTCTX_SECTION_KEYED_DATA data)
++
++ *section = header;
++
++ return STATUS_SUCCESS;
+}
+
- NTSTATUS status;
++static NTSTATUS find_window_class(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *name,
++ PACTCTX_SECTION_KEYED_DATA data)
+{
- switch (section_kind)
++ struct string_index *iter, *index = NULL;
++ struct wndclass_redirect_data *class;
++ ULONG hash;
++ int i;
+
- case ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION:
- status = find_dll_redirection(actctx, section_name, data);
- break;
- case ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION:
- status = find_window_class(actctx, section_name, data);
- break;
- case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION:
- case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION:
- case ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION:
- case ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION:
- case ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE:
- case ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES:
- DPRINT1("Unsupported yet section_kind %x\n", section_kind);
- return STATUS_SXS_SECTION_NOT_FOUND;
- default:
- DPRINT1("Unknown section_kind %x\n", section_kind);
- return STATUS_SXS_SECTION_NOT_FOUND;
++ if (!(actctx->sections & WINDOWCLASS_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;
++
++ if (!actctx->wndclass_section)
+ {
- if (status != STATUS_SUCCESS) return status;
++ struct strsection_header *section;
++
++ NTSTATUS status = build_wndclass_section(actctx, §ion);
++ if (status) return status;
++
++ if (InterlockedCompareExchangePointer((void**)&actctx->wndclass_section, section, NULL))
++ RtlFreeHeap(RtlGetProcessHeap(), 0, section);
+ }
+
- if (flags & FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX)
++ hash = 0;
++ RtlHashUnicodeString(name, TRUE, HASH_STRING_ALGORITHM_X65599, &hash);
++ iter = get_wndclass_first_index(actctx);
+
- actctx_addref(actctx);
- data->hActCtx = actctx;
++ for (i = 0; i < actctx->wndclass_section->count; i++)
+ {
- static NTSTATUS find_guid(ACTIVATION_CONTEXT* actctx, ULONG section_kind,
- const GUID *guid, DWORD flags, PACTCTX_SECTION_KEYED_DATA data)
++ if (iter->hash == hash)
++ {
++ const WCHAR *nameW = (WCHAR*)((BYTE*)actctx->wndclass_section + iter->name_offset);
++
++ if (!strcmpW(nameW, name->Buffer))
++ {
++ index = iter;
++ break;
++ }
++ else
++ DPRINT1("hash collision 0x%08x, %wZ, %S\n", hash, name, nameW);
++ }
++ iter++;
+ }
++
++ if (!index) return STATUS_SXS_KEY_NOT_FOUND;
++
++ class = get_wndclass_data(actctx, index);
++
++ data->ulDataFormatVersion = 1;
++ data->lpData = class;
++ /* full length includes string length with nulls */
++ data->ulLength = class->size + class->name_len + class->module_len + 2*sizeof(WCHAR);
++ data->lpSectionGlobalData = NULL;
++ data->ulSectionGlobalDataLength = 0;
++ data->lpSectionBase = actctx->wndclass_section;
++ data->ulSectionTotalLength = RtlSizeHeap( RtlGetProcessHeap(), 0, actctx->wndclass_section );
++ data->hActCtx = NULL;
++
++ if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
++ data->ulAssemblyRosterIndex = index->rosterindex;
++
+ return STATUS_SUCCESS;
+}
+
- NTSTATUS status;
++static NTSTATUS build_tlib_section(ACTIVATION_CONTEXT* actctx, struct guidsection_header **section)
+{
- switch (section_kind)
++ unsigned int i, j, k, total_len = 0, tlib_count = 0, names_len = 0;
++ struct guidsection_header *header;
++ ULONG module_offset, data_offset;
++ struct tlibredirect_data *data;
++ struct guid_index *index;
+
- UNICODE_STRING *section_name, PACTCTX_SECTION_KEYED_DATA data )
++ /* compute section length */
++ for (i = 0; i < actctx->num_assemblies; i++)
++ {
++ struct assembly *assembly = &actctx->assemblies[i];
++ for (j = 0; j < assembly->num_dlls; j++)
++ {
++ struct dll_redirect *dll = &assembly->dlls[j];
++ for (k = 0; k < dll->entities.num; k++)
++ {
++ struct entity *entity = &dll->entities.base[k];
++ if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION)
++ {
++ /* each entry needs index, data and string data for module name and help string */
++ total_len += sizeof(*index);
++ total_len += sizeof(*data);
++ /* help string is stored separately */
++ if (*entity->u.typelib.helpdir)
++ total_len += aligned_string_len((strlenW(entity->u.typelib.helpdir)+1)*sizeof(WCHAR));
++
++ /* module names are packed one after another */
++ names_len += (strlenW(dll->name)+1)*sizeof(WCHAR);
++
++ tlib_count++;
++ }
++ }
++ }
++ }
++
++ total_len += aligned_string_len(names_len);
++ total_len += sizeof(*header);
++
++ header = RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len);
++ if (!header) return STATUS_NO_MEMORY;
++
++ memset(header, 0, sizeof(*header));
++ header->magic = GUIDSECTION_MAGIC;
++ header->size = sizeof(*header);
++ header->count = tlib_count;
++ header->index_offset = sizeof(*header) + aligned_string_len(names_len);
++ index = (struct guid_index*)((BYTE*)header + header->index_offset);
++ module_offset = sizeof(*header);
++ data_offset = header->index_offset + tlib_count*sizeof(*index);
++
++ for (i = 0; i < actctx->num_assemblies; i++)
+ {
++ struct assembly *assembly = &actctx->assemblies[i];
++ for (j = 0; j < assembly->num_dlls; j++)
++ {
++ struct dll_redirect *dll = &assembly->dlls[j];
++ for (k = 0; k < dll->entities.num; k++)
++ {
++ struct entity *entity = &dll->entities.base[k];
++ if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION)
++ {
++ ULONG module_len, help_len;
++ UNICODE_STRING str;
++ WCHAR *ptrW;
++
++ if (*entity->u.typelib.helpdir)
++ help_len = strlenW(entity->u.typelib.helpdir)*sizeof(WCHAR);
++ else
++ help_len = 0;
++
++ module_len = strlenW(dll->name)*sizeof(WCHAR);
++
++ /* setup new index entry */
++ RtlInitUnicodeString(&str, entity->u.typelib.tlbid);
++ RtlGUIDFromString(&str, &index->guid);
++ index->data_offset = data_offset;
++ index->data_len = sizeof(*data) + aligned_string_len(help_len);
++ index->rosterindex = i + 1;
++
++ /* setup data */
++ data = (struct tlibredirect_data*)((BYTE*)header + index->data_offset);
++ data->size = sizeof(*data);
++ data->res = 0;
++ data->name_len = module_len;
++ data->name_offset = module_offset;
++ /* FIXME: resourceid handling is really weird, and it doesn't seem to be useful */
++ data->langid = 0;
++ data->flags = entity->u.typelib.flags;
++ data->help_len = help_len;
++ data->help_offset = sizeof(*data);
++ data->major_version = entity->u.typelib.major;
++ data->minor_version = entity->u.typelib.minor;
++
++ /* module name */
++ ptrW = (WCHAR*)((BYTE*)header + data->name_offset);
++ memcpy(ptrW, dll->name, data->name_len);
++ ptrW[data->name_len/sizeof(WCHAR)] = 0;
++
++ /* help string */
++ if (data->help_len)
++ {
++ ptrW = (WCHAR*)((BYTE*)data + data->help_offset);
++ memcpy(ptrW, entity->u.typelib.helpdir, data->help_len);
++ ptrW[data->help_len/sizeof(WCHAR)] = 0;
++ }
++
++ data_offset += sizeof(*data);
++ if (help_len)
++ data_offset += aligned_string_len(help_len + sizeof(WCHAR));
++
++ module_offset += module_len + sizeof(WCHAR);
++
++ index++;
++ }
++ }
++ }
++ }
++
++ *section = header;
++
++ return STATUS_SUCCESS;
++}
++
++static inline struct tlibredirect_data *get_tlib_data(ACTIVATION_CONTEXT *actctx, struct guid_index *index)
++{
++ return (struct tlibredirect_data*)((BYTE*)actctx->tlib_section + index->data_offset);
++}
++
++static NTSTATUS find_tlib_redirection(ACTIVATION_CONTEXT* actctx, const GUID *guid, ACTCTX_SECTION_KEYED_DATA* data)
++{
++ struct guid_index *index = NULL;
++ struct tlibredirect_data *tlib;
++
++ if (!(actctx->sections & TLIBREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;
++
++ if (!actctx->tlib_section)
++ {
++ struct guidsection_header *section;
++
++ NTSTATUS status = build_tlib_section(actctx, §ion);
++ if (status) return status;
++
++ if (InterlockedCompareExchangePointer((void**)&actctx->tlib_section, section, NULL))
++ RtlFreeHeap(RtlGetProcessHeap(), 0, section);
++ }
++
++ index = find_guid_index(actctx->tlib_section, guid);
++ if (!index) return STATUS_SXS_KEY_NOT_FOUND;
++
++ tlib = get_tlib_data(actctx, index);
++
++ data->ulDataFormatVersion = 1;
++ data->lpData = tlib;
++ /* full length includes string length with nulls */
++ data->ulLength = tlib->size + tlib->help_len + sizeof(WCHAR);
++ data->lpSectionGlobalData = (BYTE*)actctx->tlib_section + actctx->tlib_section->names_offset;
++ data->ulSectionGlobalDataLength = actctx->tlib_section->names_len;
++ data->lpSectionBase = actctx->tlib_section;
++ data->ulSectionTotalLength = RtlSizeHeap( RtlGetProcessHeap(), 0, actctx->tlib_section );
++ data->hActCtx = NULL;
++
++ if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
++ data->ulAssemblyRosterIndex = index->rosterindex;
++
++ return STATUS_SUCCESS;
++}
++
++static void generate_uuid(ULONG *seed, GUID *guid)
++{
++ ULONG *ptr = (ULONG*)guid;
++ int i;
++
++ /* GUID is 16 bytes long */
++ for (i = 0; i < sizeof(GUID)/sizeof(ULONG); i++, ptr++)
++ *ptr = RtlUniform(seed);
++
++ guid->Data3 &= 0x0fff;
++ guid->Data3 |= (4 << 12);
++ guid->Data4[0] &= 0x3f;
++ guid->Data4[0] |= 0x80;
++}
++
++static void get_comserver_datalen(const struct entity_array *entities, const struct dll_redirect *dll,
++ unsigned int *count, unsigned int *len, unsigned int *module_len)
++{
++ unsigned int i;
++
++ for (i = 0; i < entities->num; i++)
++ {
++ struct entity *entity = &entities->base[i];
++ if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)
++ {
++ /* each entry needs two index entries, extra one goes for alias GUID */
++ *len += 2*sizeof(struct guid_index);
++ /* To save some memory we don't allocated two data structures,
++ instead alias index and normal index point to the same data structure. */
++ *len += sizeof(struct comclassredirect_data);
++
++ /* for clrClass store some more */
++ if (entity->u.comclass.name)
++ {
++ unsigned int str_len;
++
++ /* all string data is stored together in aligned block */
++ str_len = strlenW(entity->u.comclass.name)+1;
++ if (entity->u.comclass.progid)
++ str_len += strlenW(entity->u.comclass.progid)+1;
++ if (entity->u.comclass.version)
++ str_len += strlenW(entity->u.comclass.version)+1;
++
++ *len += sizeof(struct clrclass_data);
++ *len += aligned_string_len(str_len*sizeof(WCHAR));
++
++ /* module name is forced to mscoree.dll, and stored two times with different case */
++ *module_len += sizeof(mscoreeW) + sizeof(mscoree2W);
++ }
++ else
++ {
++ /* progid string is stored separately */
++ if (entity->u.comclass.progid)
++ *len += aligned_string_len((strlenW(entity->u.comclass.progid)+1)*sizeof(WCHAR));
++
++ *module_len += (strlenW(dll->name)+1)*sizeof(WCHAR);
++ }
++
++ *count += 1;
++ }
++ }
++}
++
++static void add_comserver_record(const struct guidsection_header *section, const struct entity_array *entities,
++ const struct dll_redirect *dll, struct guid_index **index, ULONG *data_offset, ULONG *module_offset,
++ ULONG *seed, ULONG rosterindex)
++{
++ unsigned int i;
++
++ for (i = 0; i < entities->num; i++)
++ {
++ struct entity *entity = &entities->base[i];
++ if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)
++ {
++ ULONG module_len, progid_len, str_len = 0;
++ struct comclassredirect_data *data;
++ struct guid_index *alias_index;
++ struct clrclass_data *clrdata;
++ UNICODE_STRING str;
++ WCHAR *ptrW;
++
++ if (entity->u.comclass.progid)
++ progid_len = strlenW(entity->u.comclass.progid)*sizeof(WCHAR);
++ else
++ progid_len = 0;
++
++ module_len = dll ? strlenW(dll->name)*sizeof(WCHAR) : strlenW(mscoreeW)*sizeof(WCHAR);
++
++ /* setup new index entry */
++ RtlInitUnicodeString(&str, entity->u.comclass.clsid);
++ RtlGUIDFromString(&str, &(*index)->guid);
++
++ (*index)->data_offset = *data_offset;
++ (*index)->data_len = sizeof(*data); /* additional length added later */
++ (*index)->rosterindex = rosterindex;
++
++ /* Setup new index entry for alias guid. Alias index records are placed after
++ normal records, so normal guids are hit first on search. Note that class count
++ is doubled. */
++ alias_index = (*index) + section->count/2;
++ generate_uuid(seed, &alias_index->guid);
++ alias_index->data_offset = (*index)->data_offset;
++ alias_index->data_len = 0;
++ alias_index->rosterindex = (*index)->rosterindex;
++
++ /* setup data */
++ data = (struct comclassredirect_data*)((BYTE*)section + (*index)->data_offset);
++ data->size = sizeof(*data);
++ data->res = 0;
++ data->res1[0] = 0;
++ data->res1[1] = 0;
++ data->model = entity->u.comclass.model;
++ data->clsid = (*index)->guid;
++ data->alias = alias_index->guid;
++ data->clsid2 = data->clsid;
++ if (entity->u.comclass.tlbid)
++ {
++ RtlInitUnicodeString(&str, entity->u.comclass.tlbid);
++ RtlGUIDFromString(&str, &data->tlbid);
++ }
++ else
++ memset(&data->tlbid, 0, sizeof(data->tlbid));
++ data->name_len = module_len;
++ data->name_offset = *module_offset;
++ data->progid_len = progid_len;
++ data->progid_offset = data->progid_len ? data->size : 0; /* in case of clrClass additional offset is added later */
++ data->clrdata_len = 0; /* will be set later */
++ data->clrdata_offset = entity->u.comclass.name ? sizeof(*data) : 0;
++ data->miscstatus = entity->u.comclass.miscstatus;
++ data->miscstatuscontent = entity->u.comclass.miscstatuscontent;
++ data->miscstatusthumbnail = entity->u.comclass.miscstatusthumbnail;
++ data->miscstatusicon = entity->u.comclass.miscstatusicon;
++ data->miscstatusdocprint = entity->u.comclass.miscstatusdocprint;
++
++ /* mask describes which misc* data is available */
++ data->miscmask = 0;
++ if (data->miscstatus)
++ data->miscmask |= MiscStatus;
++ if (data->miscstatuscontent)
++ data->miscmask |= MiscStatusContent;
++ if (data->miscstatusthumbnail)
++ data->miscmask |= MiscStatusThumbnail;
++ if (data->miscstatusicon)
++ data->miscmask |= MiscStatusIcon;
++ if (data->miscstatusdocprint)
++ data->miscmask |= MiscStatusDocPrint;
++
++ if (data->clrdata_offset)
++ {
++ clrdata = (struct clrclass_data*)((BYTE*)data + data->clrdata_offset);
++
++ clrdata->size = sizeof(*clrdata);
++ clrdata->res[0] = 0;
++ clrdata->res[1] = 2; /* FIXME: unknown field */
++ clrdata->module_len = strlenW(mscoreeW)*sizeof(WCHAR);
++ clrdata->module_offset = *module_offset + data->name_len + sizeof(WCHAR);
++ clrdata->name_len = strlenW(entity->u.comclass.name)*sizeof(WCHAR);
++ clrdata->name_offset = clrdata->size;
++ clrdata->version_len = entity->u.comclass.version ? strlenW(entity->u.comclass.version)*sizeof(WCHAR) : 0;
++ clrdata->version_offset = clrdata->version_len ? clrdata->name_offset + clrdata->name_len + sizeof(WCHAR) : 0;
++ clrdata->res2[0] = 0;
++ clrdata->res2[1] = 0;
++
++ data->clrdata_len = clrdata->size + clrdata->name_len + sizeof(WCHAR);
++
++ /* module name */
++ ptrW = (WCHAR*)((BYTE*)section + clrdata->module_offset);
++ memcpy(ptrW, mscoree2W, clrdata->module_len);
++ ptrW[clrdata->module_len/sizeof(WCHAR)] = 0;
++
++ ptrW = (WCHAR*)((BYTE*)section + data->name_offset);
++ memcpy(ptrW, mscoreeW, data->name_len);
++ ptrW[data->name_len/sizeof(WCHAR)] = 0;
++
++ /* class name */
++ ptrW = (WCHAR*)((BYTE*)clrdata + clrdata->name_offset);
++ memcpy(ptrW, entity->u.comclass.name, clrdata->name_len);
++ ptrW[clrdata->name_len/sizeof(WCHAR)] = 0;
++
++ /* runtime version, optional */
++ if (clrdata->version_len)
++ {
++ data->clrdata_len += clrdata->version_len + sizeof(WCHAR);
++
++ ptrW = (WCHAR*)((BYTE*)clrdata + clrdata->version_offset);
++ memcpy(ptrW, entity->u.comclass.version, clrdata->version_len);
++ ptrW[clrdata->version_len/sizeof(WCHAR)] = 0;
++ }
++
++ if (data->progid_len)
++ data->progid_offset += data->clrdata_len;
++ (*index)->data_len += sizeof(*clrdata);
++ }
++ else
++ {
++ clrdata = NULL;
++
++ /* module name */
++ ptrW = (WCHAR*)((BYTE*)section + data->name_offset);
++ memcpy(ptrW, dll->name, data->name_len);
++ ptrW[data->name_len/sizeof(WCHAR)] = 0;
++ }
++
++ /* progid string */
++ if (data->progid_len)
++ {
++ ptrW = (WCHAR*)((BYTE*)data + data->progid_offset);
++ memcpy(ptrW, entity->u.comclass.progid, data->progid_len);
++ ptrW[data->progid_len/sizeof(WCHAR)] = 0;
++ }
++
++ /* string block length */
++ str_len = 0;
++ if (clrdata)
++ {
++ str_len += clrdata->name_len + sizeof(WCHAR);
++ if (clrdata->version_len)
++ str_len += clrdata->version_len + sizeof(WCHAR);
++ }
++ if (progid_len)
++ str_len += progid_len + sizeof(WCHAR);
++
++ (*index)->data_len += aligned_string_len(str_len);
++ alias_index->data_len = (*index)->data_len;
++
++ /* move to next data record */
++ (*data_offset) += sizeof(*data) + aligned_string_len(str_len);
++ (*module_offset) += module_len + sizeof(WCHAR);
++
++ if (clrdata)
++ {
++ (*data_offset) += sizeof(*clrdata);
++ (*module_offset) += clrdata->module_len + sizeof(WCHAR);
++ }
++ (*index) += 1;
++ }
++ }
++}
++
++static NTSTATUS build_comserver_section(ACTIVATION_CONTEXT* actctx, struct guidsection_header **section)
++{
++ unsigned int i, j, total_len = 0, class_count = 0, names_len = 0;
++ struct guidsection_header *header;
++ ULONG module_offset, data_offset;
++ struct guid_index *index;
++ ULONG seed;
++
++ /* compute section length */
++ for (i = 0; i < actctx->num_assemblies; i++)
++ {
++ struct assembly *assembly = &actctx->assemblies[i];
++ get_comserver_datalen(&assembly->entities, NULL, &class_count, &total_len, &names_len);
++ for (j = 0; j < assembly->num_dlls; j++)
++ {
++ struct dll_redirect *dll = &assembly->dlls[j];
++ get_comserver_datalen(&dll->entities, dll, &class_count, &total_len, &names_len);
++ }
++ }
++
++ total_len += aligned_string_len(names_len);
++ total_len += sizeof(*header);
++
++ header = RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len);
++ if (!header) return STATUS_NO_MEMORY;
++
++ memset(header, 0, sizeof(*header));
++ header->magic = GUIDSECTION_MAGIC;
++ header->size = sizeof(*header);
++ header->count = 2*class_count;
++ header->index_offset = sizeof(*header) + aligned_string_len(names_len);
++ index = (struct guid_index*)((BYTE*)header + header->index_offset);
++ module_offset = sizeof(*header);
++ data_offset = header->index_offset + 2*class_count*sizeof(*index);
++
++ seed = NtGetTickCount();
++ for (i = 0; i < actctx->num_assemblies; i++)
++ {
++ struct assembly *assembly = &actctx->assemblies[i];
++ add_comserver_record(header, &assembly->entities, NULL, &index, &data_offset, &module_offset, &seed, i+1);
++ for (j = 0; j < assembly->num_dlls; j++)
++ {
++ struct dll_redirect *dll = &assembly->dlls[j];
++ add_comserver_record(header, &dll->entities, dll, &index, &data_offset, &module_offset, &seed, i+1);
++ }
++ }
++
++ *section = header;
++
++ return STATUS_SUCCESS;
++}
++
++static inline struct comclassredirect_data *get_comclass_data(ACTIVATION_CONTEXT *actctx, struct guid_index *index)
++{
++ return (struct comclassredirect_data*)((BYTE*)actctx->comserver_section + index->data_offset);
++}
++
++static NTSTATUS find_comserver_redirection(ACTIVATION_CONTEXT* actctx, const GUID *guid, ACTCTX_SECTION_KEYED_DATA* data)
++{
++ struct comclassredirect_data *comclass;
++ struct guid_index *index = NULL;
++
++ if (!(actctx->sections & SERVERREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;
++
++ if (!actctx->comserver_section)
++ {
++ struct guidsection_header *section;
++
++ NTSTATUS status = build_comserver_section(actctx, §ion);
++ if (status) return status;
++
++ if (InterlockedCompareExchangePointer((void**)&actctx->comserver_section, section, NULL))
++ RtlFreeHeap(RtlGetProcessHeap(), 0, section);
++ }
++
++ index = find_guid_index(actctx->comserver_section, guid);
++ if (!index) return STATUS_SXS_KEY_NOT_FOUND;
++
++ comclass = get_comclass_data(actctx, index);
++
++ data->ulDataFormatVersion = 1;
++ data->lpData = comclass;
++ /* full length includes string length with nulls */
++ data->ulLength = comclass->size + comclass->clrdata_len;
++ if (comclass->progid_len) data->ulLength += comclass->progid_len + sizeof(WCHAR);
++ data->lpSectionGlobalData = (BYTE*)actctx->comserver_section + actctx->comserver_section->names_offset;
++ data->ulSectionGlobalDataLength = actctx->comserver_section->names_len;
++ data->lpSectionBase = actctx->comserver_section;
++ data->ulSectionTotalLength = RtlSizeHeap( RtlGetProcessHeap(), 0, actctx->comserver_section );
++ data->hActCtx = NULL;
++
++ if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
++ data->ulAssemblyRosterIndex = index->rosterindex;
++
++ return STATUS_SUCCESS;
++}
++
++static void get_ifaceps_datalen(const struct entity_array *entities, unsigned int *count, unsigned int *len)
++{
++ unsigned int i;
++
++ for (i = 0; i < entities->num; i++)
++ {
++ struct entity *entity = &entities->base[i];
++ if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION)
++ {
++ *len += sizeof(struct guid_index) + sizeof(struct ifacepsredirect_data);
++ if (entity->u.ifaceps.name)
++ *len += aligned_string_len((strlenW(entity->u.ifaceps.name)+1)*sizeof(WCHAR));
++ *count += 1;
++ }
++ }
++}
++
++static void add_ifaceps_record(struct guidsection_header *section, struct entity_array *entities,
++ struct guid_index **index, ULONG *data_offset, ULONG rosterindex)
++{
++ unsigned int i;
++
++ for (i = 0; i < entities->num; i++)
++ {
++ struct entity *entity = &entities->base[i];
++ if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION)
++ {
++ struct ifacepsredirect_data *data = (struct ifacepsredirect_data*)((BYTE*)section + *data_offset);
++ UNICODE_STRING str;
++ ULONG name_len;
++
++ if (entity->u.ifaceps.name)
++ name_len = strlenW(entity->u.ifaceps.name)*sizeof(WCHAR);
++ else
++ name_len = 0;
++
++ /* setup index */
++ RtlInitUnicodeString(&str, entity->u.ifaceps.iid);
++ RtlGUIDFromString(&str, &(*index)->guid);
++ (*index)->data_offset = *data_offset;
++ (*index)->data_len = sizeof(*data) + name_len ? aligned_string_len(name_len + sizeof(WCHAR)) : 0;
++ (*index)->rosterindex = rosterindex;
++
++ /* setup data record */
++ data->size = sizeof(*data);
++ data->mask = entity->u.ifaceps.mask;
++
++ /* proxyStubClsid32 value is only stored for external PS,
++ if set it's used as iid, otherwise 'iid' attribute value is used */
++ if (entity->u.ifaceps.ps32)
++ {
++ RtlInitUnicodeString(&str, entity->u.ifaceps.ps32);
++ RtlGUIDFromString(&str, &data->iid);
++ }
++ else
++ data->iid = (*index)->guid;
++
++ data->nummethods = entity->u.ifaceps.nummethods;
++
++ if (entity->u.ifaceps.tlib)
++ {
++ RtlInitUnicodeString(&str, entity->u.ifaceps.tlib);
++ RtlGUIDFromString(&str, &data->tlbid);
++ }
++ else
++ memset(&data->tlbid, 0, sizeof(data->tlbid));
++
++ if (entity->u.ifaceps.base)
++ {
++ RtlInitUnicodeString(&str, entity->u.ifaceps.base);
++ RtlGUIDFromString(&str, &data->base);
++ }
++ else
++ memset(&data->base, 0, sizeof(data->base));
++
++ data->name_len = name_len;
++ data->name_offset = data->name_len ? sizeof(*data) : 0;
++
++ /* name string */
++ if (data->name_len)
++ {
++ WCHAR *ptrW = (WCHAR*)((BYTE*)data + data->name_offset);
++ memcpy(ptrW, entity->u.ifaceps.name, data->name_len);
++ ptrW[data->name_len/sizeof(WCHAR)] = 0;
++ }
++
++ /* move to next record */
++ (*index) += 1;
++ *data_offset += sizeof(*data);
++ if (data->name_len)
++ *data_offset += aligned_string_len(data->name_len + sizeof(WCHAR));
++ }
++ }
++}
++
++static NTSTATUS build_ifaceps_section(ACTIVATION_CONTEXT* actctx, struct guidsection_header **section)
++{
++ unsigned int i, j, total_len = 0, count = 0;
++ struct guidsection_header *header;
++ struct guid_index *index;
++ ULONG data_offset;
++
++ /* compute section length */
++ for (i = 0; i < actctx->num_assemblies; i++)
++ {
++ struct assembly *assembly = &actctx->assemblies[i];
++
++ get_ifaceps_datalen(&assembly->entities, &count, &total_len);
++ for (j = 0; j < assembly->num_dlls; j++)
++ {
++ struct dll_redirect *dll = &assembly->dlls[j];
++ get_ifaceps_datalen(&dll->entities, &count, &total_len);
++ }
++ }
++
++ total_len += sizeof(*header);
++
++ header = RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len);
++ if (!header) return STATUS_NO_MEMORY;
++
++ memset(header, 0, sizeof(*header));
++ header->magic = GUIDSECTION_MAGIC;
++ header->size = sizeof(*header);
++ header->count = count;
++ header->index_offset = sizeof(*header);
++ index = (struct guid_index*)((BYTE*)header + header->index_offset);
++ data_offset = header->index_offset + count*sizeof(*index);
++
++ for (i = 0; i < actctx->num_assemblies; i++)
++ {
++ struct assembly *assembly = &actctx->assemblies[i];
++
++ add_ifaceps_record(header, &assembly->entities, &index, &data_offset, i + 1);
++ for (j = 0; j < assembly->num_dlls; j++)
++ {
++ struct dll_redirect *dll = &assembly->dlls[j];
++ add_ifaceps_record(header, &dll->entities, &index, &data_offset, i + 1);
++ }
++ }
++
++ *section = header;
++
++ return STATUS_SUCCESS;
++}
++
++static inline struct ifacepsredirect_data *get_ifaceps_data(ACTIVATION_CONTEXT *actctx, struct guid_index *index)
++{
++ return (struct ifacepsredirect_data*)((BYTE*)actctx->ifaceps_section + index->data_offset);
++}
++
++static NTSTATUS find_cominterface_redirection(ACTIVATION_CONTEXT* actctx, const GUID *guid, ACTCTX_SECTION_KEYED_DATA* data)
++{
++ struct ifacepsredirect_data *iface;
++ struct guid_index *index = NULL;
++
++ if (!(actctx->sections & IFACEREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;
++
++ if (!actctx->ifaceps_section)
++ {
++ struct guidsection_header *section;
++
++ NTSTATUS status = build_ifaceps_section(actctx, §ion);
++ if (status) return status;
++
++ if (InterlockedCompareExchangePointer((void**)&actctx->ifaceps_section, section, NULL))
++ RtlFreeHeap(RtlGetProcessHeap(), 0, section);
++ }
++
++ index = find_guid_index(actctx->ifaceps_section, guid);
++ if (!index) return STATUS_SXS_KEY_NOT_FOUND;
++
++ iface = get_ifaceps_data(actctx, index);
++
++ data->ulDataFormatVersion = 1;
++ data->lpData = iface;
++ data->ulLength = iface->size + (iface->name_len ? iface->name_len + sizeof(WCHAR) : 0);
++ data->lpSectionGlobalData = NULL;
++ data->ulSectionGlobalDataLength = 0;
++ data->lpSectionBase = actctx->ifaceps_section;
++ data->ulSectionTotalLength = RtlSizeHeap( RtlGetProcessHeap(), 0, actctx->ifaceps_section );
++ data->hActCtx = NULL;
++
++ if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
++ data->ulAssemblyRosterIndex = index->rosterindex;
++
++ return STATUS_SUCCESS;
++}
++
++static NTSTATUS build_clr_surrogate_section(ACTIVATION_CONTEXT* actctx, struct guidsection_header **section)
++{
++ unsigned int i, j, total_len = 0, count = 0;
++ struct guidsection_header *header;
++ struct clrsurrogate_data *data;
++ struct guid_index *index;
++ ULONG data_offset;
++
++ /* compute section length */
++ for (i = 0; i < actctx->num_assemblies; i++)
++ {
++ struct assembly *assembly = &actctx->assemblies[i];
++ for (j = 0; j < assembly->entities.num; j++)
++ {
++ struct entity *entity = &assembly->entities.base[j];
++ if (entity->kind == ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES)
++ {
++ ULONG len;
++
++ total_len += sizeof(*index) + sizeof(*data);
++ len = strlenW(entity->u.clrsurrogate.name) + 1;
++ if (entity->u.clrsurrogate.version)
++ len += strlenW(entity->u.clrsurrogate.version) + 1;
++ total_len += aligned_string_len(len*sizeof(WCHAR));
++
++ count++;
++ }
++ }
++ }
++
++ total_len += sizeof(*header);
++
++ header = RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len);
++ if (!header) return STATUS_NO_MEMORY;
++
++ memset(header, 0, sizeof(*header));
++ header->magic = GUIDSECTION_MAGIC;
++ header->size = sizeof(*header);
++ header->count = count;
++ header->index_offset = sizeof(*header);
++ index = (struct guid_index*)((BYTE*)header + header->index_offset);
++ data_offset = header->index_offset + count*sizeof(*index);
++
++ for (i = 0; i < actctx->num_assemblies; i++)
++ {
++ struct assembly *assembly = &actctx->assemblies[i];
++ for (j = 0; j < assembly->entities.num; j++)
++ {
++ struct entity *entity = &assembly->entities.base[j];
++ if (entity->kind == ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES)
++ {
++ ULONG version_len, name_len;
++ UNICODE_STRING str;
++ WCHAR *ptrW;
++
++ if (entity->u.clrsurrogate.version)
++ version_len = strlenW(entity->u.clrsurrogate.version)*sizeof(WCHAR);
++ else
++ version_len = 0;
++ name_len = strlenW(entity->u.clrsurrogate.name)*sizeof(WCHAR);
++
++ /* setup new index entry */
++ RtlInitUnicodeString(&str, entity->u.clrsurrogate.clsid);
++ RtlGUIDFromString(&str, &index->guid);
++
++ index->data_offset = data_offset;
++ index->data_len = sizeof(*data) + aligned_string_len(name_len + sizeof(WCHAR) + (version_len ? version_len + sizeof(WCHAR) : 0));
++ index->rosterindex = i + 1;
++
++ /* setup data */
++ data = (struct clrsurrogate_data*)((BYTE*)header + index->data_offset);
++ data->size = sizeof(*data);
++ data->res = 0;
++ data->clsid = index->guid;
++ data->version_offset = version_len ? data->size : 0;
++ data->version_len = version_len;
++ data->name_offset = data->size + version_len;
++ if (version_len)
++ data->name_offset += sizeof(WCHAR);
++ data->name_len = name_len;
++
++ /* surrogate name */
++ ptrW = (WCHAR*)((BYTE*)data + data->name_offset);
++ memcpy(ptrW, entity->u.clrsurrogate.name, data->name_len);
++ ptrW[data->name_len/sizeof(WCHAR)] = 0;
++
++ /* runtime version */
++ if (data->version_len)
++ {
++ ptrW = (WCHAR*)((BYTE*)data + data->version_offset);
++ memcpy(ptrW, entity->u.clrsurrogate.version, data->version_len);
++ ptrW[data->version_len/sizeof(WCHAR)] = 0;
++ }
++
++ data_offset += index->data_offset;
++ index++;
++ }
++ }
++ }
++
++ *section = header;
++
++ return STATUS_SUCCESS;
++}
++
++static inline struct clrsurrogate_data *get_surrogate_data(ACTIVATION_CONTEXT *actctx, const struct guid_index *index)
++{
++ return (struct clrsurrogate_data*)((BYTE*)actctx->clrsurrogate_section + index->data_offset);
++}
++
++static NTSTATUS find_clr_surrogate(ACTIVATION_CONTEXT* actctx, const GUID *guid, ACTCTX_SECTION_KEYED_DATA* data)
++{
++ struct clrsurrogate_data *surrogate;
++ struct guid_index *index = NULL;
++
++ if (!(actctx->sections & CLRSURROGATES_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;
++
++ if (!actctx->clrsurrogate_section)
++ {
++ struct guidsection_header *section;
++
++ NTSTATUS status = build_clr_surrogate_section(actctx, §ion);
++ if (status) return status;
++
++ if (InterlockedCompareExchangePointer((void**)&actctx->clrsurrogate_section, section, NULL))
++ RtlFreeHeap(RtlGetProcessHeap(), 0, section);
++ }
++
++ index = find_guid_index(actctx->clrsurrogate_section, guid);
++ if (!index) return STATUS_SXS_KEY_NOT_FOUND;
++
++ surrogate = get_surrogate_data(actctx, index);
++
++ data->ulDataFormatVersion = 1;
++ data->lpData = surrogate;
++ /* full length includes string length with nulls */
++ data->ulLength = surrogate->size + surrogate->name_len + sizeof(WCHAR);
++ if (surrogate->version_len)
++ data->ulLength += surrogate->version_len + sizeof(WCHAR);
++
++ data->lpSectionGlobalData = NULL;
++ data->ulSectionGlobalDataLength = 0;
++ data->lpSectionBase = actctx->clrsurrogate_section;
++ data->ulSectionTotalLength = RtlSizeHeap( RtlGetProcessHeap(), 0, actctx->clrsurrogate_section );
++ data->hActCtx = NULL;
++
++ if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
++ data->ulAssemblyRosterIndex = index->rosterindex;
++
++ return STATUS_SUCCESS;
++}
++
++static void get_progid_datalen(struct entity_array *entities, unsigned int *count, unsigned int *total_len)
++{
++ unsigned int i, j, single_len;
++
++ single_len = sizeof(struct progidredirect_data) + sizeof(struct string_index) + sizeof(GUID);
++ for (i = 0; i < entities->num; i++)
++ {
++ struct entity *entity = &entities->base[i];
++ if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)
++ {
++ if (entity->u.comclass.progid)
++ {
++ *total_len += single_len + aligned_string_len((strlenW(entity->u.comclass.progid)+1)*sizeof(WCHAR));
++ *count += 1;
++ }
++
++ for (j = 0; j < entity->u.comclass.progids.num; j++)
++ *total_len += aligned_string_len((strlenW(entity->u.comclass.progids.progids[j])+1)*sizeof(WCHAR));
++
++ *total_len += single_len*entity->u.comclass.progids.num;
++ *count += entity->u.comclass.progids.num;
++ }
++ }
++}
++
++static void write_progid_record(struct strsection_header *section, const WCHAR *progid, const GUID *alias,
++ struct string_index **index, ULONG *data_offset, ULONG *global_offset, ULONG rosterindex)
++{
++ struct progidredirect_data *data;
++ UNICODE_STRING str;
++ GUID *guid_ptr;
++ WCHAR *ptrW;
++
++ /* setup new index entry */
++
++ /* hash progid name */
++ RtlInitUnicodeString(&str, progid);
++ RtlHashUnicodeString(&str, TRUE, HASH_STRING_ALGORITHM_X65599, &(*index)->hash);
++
++ (*index)->name_offset = *data_offset;
++ (*index)->name_len = str.Length;
++ (*index)->data_offset = (*index)->name_offset + aligned_string_len(str.MaximumLength);
++ (*index)->data_len = sizeof(*data);
++ (*index)->rosterindex = rosterindex;
++
++ *data_offset += aligned_string_len(str.MaximumLength);
++
++ /* setup data structure */
++ data = (struct progidredirect_data*)((BYTE*)section + *data_offset);
++ data->size = sizeof(*data);
++ data->reserved = 0;
++ data->clsid_offset = *global_offset;
++
++ /* write progid string */
++ ptrW = (WCHAR*)((BYTE*)section + (*index)->name_offset);
++ memcpy(ptrW, progid, (*index)->name_len);
++ ptrW[(*index)->name_len/sizeof(WCHAR)] = 0;
++
++ /* write guid to global area */
++ guid_ptr = (GUID*)((BYTE*)section + data->clsid_offset);
++ *guid_ptr = *alias;
++
++ /* to next entry */
++ *global_offset += sizeof(GUID);
++ *data_offset += data->size;
++ (*index) += 1;
++}
++
++static void add_progid_record(ACTIVATION_CONTEXT* actctx, struct strsection_header *section, const struct entity_array *entities,
++ struct string_index **index, ULONG *data_offset, ULONG *global_offset, ULONG rosterindex)
++{
++ unsigned int i, j;
++
++ for (i = 0; i < entities->num; i++)
++ {
++ struct entity *entity = &entities->base[i];
++ if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)
++ {
++ const struct progids *progids = &entity->u.comclass.progids;
++ struct comclassredirect_data *comclass;
++ struct guid_index *guid_index;
++ UNICODE_STRING str;
++ GUID clsid;
++
++ RtlInitUnicodeString(&str, entity->u.comclass.clsid);
++ RtlGUIDFromString(&str, &clsid);
++
++ guid_index = find_guid_index(actctx->comserver_section, &clsid);
++ comclass = get_comclass_data(actctx, guid_index);
++
++ if (entity->u.comclass.progid)
++ write_progid_record(section, entity->u.comclass.progid, &comclass->alias,
++ index, data_offset, global_offset, rosterindex);
++
++ for (j = 0; j < progids->num; j++)
++ write_progid_record(section, progids->progids[j], &comclass->alias,
++ index, data_offset, global_offset, rosterindex);
++ }
++ }
++}
++
++static NTSTATUS build_progid_section(ACTIVATION_CONTEXT* actctx, struct strsection_header **section)
++{
++ unsigned int i, j, total_len = 0, count = 0;
++ struct strsection_header *header;
++ ULONG data_offset, global_offset;
++ struct string_index *index;
++
++ /* compute section length */
++ for (i = 0; i < actctx->num_assemblies; i++)
++ {
++ struct assembly *assembly = &actctx->assemblies[i];
++
++ get_progid_datalen(&assembly->entities, &count, &total_len);
++ for (j = 0; j < assembly->num_dlls; j++)
++ {
++ struct dll_redirect *dll = &assembly->dlls[j];
++ get_progid_datalen(&dll->entities, &count, &total_len);
++ }
++ }
++
++ total_len += sizeof(*header);
++
++ header = RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len);
++ if (!header) return STATUS_NO_MEMORY;
++
++ memset(header, 0, sizeof(*header));
++ header->magic = STRSECTION_MAGIC;
++ header->size = sizeof(*header);
++ header->count = count;
++ header->global_offset = header->size;
++ header->global_len = count*sizeof(GUID);
++ header->index_offset = header->size + header->global_len;
++
++ index = (struct string_index*)((BYTE*)header + header->index_offset);
++ data_offset = header->index_offset + count*sizeof(*index);
++ global_offset = header->global_offset;
++
++ for (i = 0; i < actctx->num_assemblies; i++)
++ {
++ struct assembly *assembly = &actctx->assemblies[i];
++
++ add_progid_record(actctx, header, &assembly->entities, &index, &data_offset, &global_offset, i + 1);
++ for (j = 0; j < assembly->num_dlls; j++)
++ {
++ struct dll_redirect *dll = &assembly->dlls[j];
++ add_progid_record(actctx, header, &dll->entities, &index, &data_offset, &global_offset, i + 1);
++ }
++ }
++
++ *section = header;
++
++ return STATUS_SUCCESS;
++}
++
++static inline struct progidredirect_data *get_progid_data(ACTIVATION_CONTEXT *actctx, const struct string_index *index)
++{
++ return (struct progidredirect_data*)((BYTE*)actctx->progid_section + index->data_offset);
++}
++
++static NTSTATUS find_progid_redirection(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *name,
++ PACTCTX_SECTION_KEYED_DATA data)
++{
++ struct progidredirect_data *progid;
++ struct string_index *index;
++
++ if (!(actctx->sections & PROGIDREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;
++
++ if (!actctx->comserver_section)
++ {
++ struct guidsection_header *section;
++
++ NTSTATUS status = build_comserver_section(actctx, §ion);
++ if (status) return status;
++
++ if (InterlockedCompareExchangePointer((void**)&actctx->comserver_section, section, NULL))
++ RtlFreeHeap(RtlGetProcessHeap(), 0, section);
++ }
++
++ if (!actctx->progid_section)
++ {
++ struct strsection_header *section;
++
++ NTSTATUS status = build_progid_section(actctx, §ion);
++ if (status) return status;
++
++ if (InterlockedCompareExchangePointer((void**)&actctx->progid_section, section, NULL))
++ RtlFreeHeap(RtlGetProcessHeap(), 0, section);
++ }
++
++ index = find_string_index(actctx->progid_section, name);
++ if (!index) return STATUS_SXS_KEY_NOT_FOUND;
++
++ progid = get_progid_data(actctx, index);
++
++ data->ulDataFormatVersion = 1;
++ data->lpData = progid;
++ data->ulLength = progid->size;
++ data->lpSectionGlobalData = (BYTE*)actctx->progid_section + actctx->progid_section->global_offset;
++ data->ulSectionGlobalDataLength = actctx->progid_section->global_len;
++ data->lpSectionBase = actctx->progid_section;
++ data->ulSectionTotalLength = RtlSizeHeap( RtlGetProcessHeap(), 0, actctx->progid_section );
++ data->hActCtx = NULL;
++
++ if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
++ data->ulAssemblyRosterIndex = index->rosterindex;
++
++ return STATUS_SUCCESS;
++}
++
++static NTSTATUS find_string(ACTIVATION_CONTEXT* actctx, ULONG section_kind,
++ const UNICODE_STRING *section_name,
++ DWORD flags, PACTCTX_SECTION_KEYED_DATA data)
++{
++ NTSTATUS status;
++
++ switch (section_kind)
++ {
++ case ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION:
++ status = find_dll_redirection(actctx, section_name, data);
++ break;
++ case ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION:
++ status = find_window_class(actctx, section_name, data);
++ break;
++ case ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION:
++ status = find_progid_redirection(actctx, section_name, data);
++ break;
++ case ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE:
++ DPRINT1("Unsupported yet section_kind %x\n", section_kind);
++ return STATUS_SXS_SECTION_NOT_FOUND;
++ default:
++ DPRINT1("Unknown section_kind %x\n", section_kind);
++ return STATUS_SXS_SECTION_NOT_FOUND;
++ }
++
++ if (status != STATUS_SUCCESS) return status;
++
++ if (flags & FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX)
++ {
++ actctx_addref(actctx);
++ data->hActCtx = actctx;
++ }
++ return STATUS_SUCCESS;
++}
++
++static NTSTATUS find_guid(ACTIVATION_CONTEXT* actctx, ULONG section_kind,
++ const GUID *guid, DWORD flags, PACTCTX_SECTION_KEYED_DATA data)
++{
++ NTSTATUS status;
++
++ switch (section_kind)
++ {
++ case ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION:
++ status = find_tlib_redirection(actctx, guid, data);
++ break;
++ case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION:
++ status = find_comserver_redirection(actctx, guid, data);
++ break;
++ case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION:
++ status = find_cominterface_redirection(actctx, guid, data);
++ break;
++ case ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES:
++ status = find_clr_surrogate(actctx, guid, data);
++ break;
+ default:
+ DPRINT("Unknown section_kind %x\n", section_kind);
+ return STATUS_SXS_SECTION_NOT_FOUND;
+ }
+
+ if (status != STATUS_SUCCESS) return status;
+
+ if (flags & FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX)
+ {
+ actctx_addref(actctx);
+ data->hActCtx = actctx;
+ }
+ return STATUS_SUCCESS;
+}
+
+/* initialize the activation context for the current process */
+void actctx_init(void)
+{
+ ACTCTXW ctx;
+ HANDLE handle;
+
+ ctx.cbSize = sizeof(ctx);
+ ctx.lpSource = NULL;
+ ctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
+ ctx.hModule = NtCurrentTeb()->ProcessEnvironmentBlock->ImageBaseAddress;
+ ctx.lpResourceName = (LPCWSTR)CREATEPROCESS_MANIFEST_RESOURCE_ID;
+
+ if (NT_SUCCESS(RtlCreateActivationContext(0, (PVOID)&ctx, 0, NULL, NULL, &handle)))
+ {
+ process_actctx = check_actctx(handle);
+ }
+}
+
+/* FUNCTIONS ***************************************************************/
+
+NTSTATUS
+NTAPI
+RtlCreateActivationContext(IN ULONG Flags,
+ IN PACTIVATION_CONTEXT_DATA ActivationContextData,
+ IN ULONG ExtraBytes,
+ IN PVOID NotificationRoutine,
+ IN PVOID NotificationContext,
+ OUT PACTIVATION_CONTEXT *ActCtx)
+{
+ const ACTCTXW *pActCtx = (PVOID)ActivationContextData;
+ const WCHAR *directory = NULL;
+ PACTIVATION_CONTEXT_WRAPPED ActualActCtx;
+ ACTIVATION_CONTEXT *actctx;
+ UNICODE_STRING nameW;
+ ULONG lang = 0;
+ NTSTATUS status = STATUS_NO_MEMORY;
+ HANDLE file = 0;
+ struct actctx_loader acl;
+
+ DPRINT("%p %08x\n", pActCtx, pActCtx ? pActCtx->dwFlags : 0);
+
+ if (!pActCtx || pActCtx->cbSize < sizeof(*pActCtx) ||
+ (pActCtx->dwFlags & ~ACTCTX_FLAGS_ALL))
+ return STATUS_INVALID_PARAMETER;
+
+
+ if (!(ActualActCtx = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ActualActCtx))))
+ return STATUS_NO_MEMORY;
+
+ ActualActCtx->MagicMarker = ACTCTX_MAGIC_MARKER;
+
+ actctx = &ActualActCtx->ActivationContext;
+ actctx->RefCount = 1;
+ actctx->config.type = ACTIVATION_CONTEXT_PATH_TYPE_NONE;
+ actctx->config.info = NULL;
+ actctx->appdir.type = ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE;
+ if (pActCtx->dwFlags & ACTCTX_FLAG_APPLICATION_NAME_VALID)
+ {
+ if (!(actctx->appdir.info = strdupW( pActCtx->lpApplicationName ))) goto error;
+ }
+ else
+ {
+ UNICODE_STRING dir;
+ WCHAR *p;
+ HMODULE module;
+
+ if (pActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID) module = pActCtx->hModule;
+ else module = NtCurrentTeb()->ProcessEnvironmentBlock->ImageBaseAddress;
+
+ status = get_module_filename(module, &dir, 0);
+ if (!NT_SUCCESS(status)) goto error;
+ if ((p = strrchrW( dir.Buffer, '\\' ))) p[1] = 0;
+ actctx->appdir.info = dir.Buffer;
+ }
+
+ nameW.Buffer = NULL;
+
+ /* open file only if it's going to be used */
+ if (pActCtx->lpSource && !((pActCtx->dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID) &&
+ (pActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID)))
+ {
+ if (!RtlDosPathNameToNtPathName_U(pActCtx->lpSource, &nameW, NULL, NULL))
+ {
+ status = STATUS_NO_SUCH_FILE;
+ goto error;
+ }
+ status = open_nt_file( &file, &nameW );
+ if (!NT_SUCCESS(status))
+ {
+ RtlFreeUnicodeString( &nameW );
+ goto error;
+ }
+ }
+
+ acl.actctx = actctx;
+ acl.dependencies = NULL;
+ acl.num_dependencies = 0;
+ acl.allocated_dependencies = 0;
+
+ if (pActCtx->dwFlags & ACTCTX_FLAG_LANGID_VALID) lang = pActCtx->wLangId;
+ if (pActCtx->dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID) directory = pActCtx->lpAssemblyDirectory;
+
+ if (pActCtx->dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID)
+ {
+ /* if we have a resource it's a PE file */
+ if (pActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID)
+ {
+ status = get_manifest_in_module( &acl, NULL, NULL, directory, FALSE, pActCtx->hModule,
+ pActCtx->lpResourceName, lang );
+ if (status && status != STATUS_SXS_CANT_GEN_ACTCTX)
+ /* FIXME: what to do if pActCtx->lpSource is set */
+ status = get_manifest_in_associated_manifest( &acl, NULL, NULL, directory,
+ pActCtx->hModule, pActCtx->lpResourceName );
+ }
+ else if (pActCtx->lpSource)
+ {
+ status = get_manifest_in_pe_file( &acl, NULL, nameW.Buffer, directory, FALSE,
+ file, pActCtx->lpResourceName, lang );
+ if (status && status != STATUS_SXS_CANT_GEN_ACTCTX)
+ status = get_manifest_in_associated_manifest( &acl, NULL, nameW.Buffer, directory,
+ NULL, pActCtx->lpResourceName );
+ }
+ else status = STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ status = get_manifest_in_manifest_file( &acl, NULL, nameW.Buffer, directory, FALSE, file );
+ }
+
+ if (file) NtClose( file );
+ RtlFreeUnicodeString( &nameW );
+
+ if (NT_SUCCESS(status)) status = parse_depend_manifests(&acl);
+ free_depend_manifests( &acl );
+
+ if (NT_SUCCESS(status))
+ *ActCtx = actctx;
+ else actctx_release( actctx );
+ return status;
+
+error:
+ if (file) NtClose( file );
+ actctx_release( actctx );
+ return status;
+}
+
+#if 0
+#define ACT_CTX_VALID(p) ((((ULONG_PTR)p - 1) | 7) != -1)
+
+VOID
+NTAPI
+RtlAddRefActivationContext(IN PACTIVATION_CONTEXT Handle)
+{
+ PIACTIVATION_CONTEXT ActCtx = (PIACTIVATION_CONTEXT)Handle;
+ LONG OldRefCount, NewRefCount;
+
+ if ((ActCtx) && (ACT_CTX_VALID(ActCtx)) && (ActCtx->RefCount != LONG_MAX))
+ {
+ RtlpValidateActCtx(ActCtx);
+
+ while (TRUE)
+ {
+ OldRefCount = ActCtx->RefCount;
+ ASSERT(OldRefCount > 0);
+
+ if (OldRefCount == LONG_MAX) break;
+
+ NewRefCount = OldRefCount + 1;
+ if (InterlockedCompareExchange(&ActCtx->RefCount,
+ NewRefCount,
+ OldRefCount) == OldRefCount)
+ {
+ break;
+ }
+ }
+
+ NewRefCount = LONG_MAX;
+ ASSERT(NewRefCount > 0);
+ }
+}
+
+VOID
+NTAPI
+RtlReleaseActivationContext( HANDLE handle )
+{
+ PIACTIVATION_CONTEXT ActCtx = (PIACTIVATION_CONTEXT) Handle;
+
+ if ((ActCtx) && (ACT_CTX_VALID(ActCtx)) && (ActCtx->RefCount != LONG_MAX))
+ {
+ RtlpValidateActCtx(ActCtx);
+
+ actctx_release(ActCtx);
+ }
+}
+#else
+VOID
+NTAPI
+RtlAddRefActivationContext( HANDLE handle )
+{
+ ACTIVATION_CONTEXT *actctx;
+
+ if ((actctx = check_actctx(handle))) actctx_addref(actctx);
+}
+
+VOID
+NTAPI
+RtlReleaseActivationContext( HANDLE handle )
+{
+ ACTIVATION_CONTEXT *actctx;
+
+ if ((actctx = check_actctx(handle))) actctx_release(actctx);
+}
+#endif
+
+NTSTATUS
+NTAPI RtlActivateActivationContextEx( ULONG flags, PTEB tebAddress, HANDLE handle, PULONG_PTR cookie )
+{
+ RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
+
+ if (!(frame = RtlAllocateHeap( RtlGetProcessHeap(), 0, sizeof(*frame) )))
+ return STATUS_NO_MEMORY;
+
+ frame->Previous = tebAddress->ActivationContextStackPointer->ActiveFrame;
+ frame->ActivationContext = handle;
+ frame->Flags = 0;
+
+ tebAddress->ActivationContextStackPointer->ActiveFrame = frame;
+ RtlAddRefActivationContext( handle );
+
+ *cookie = (ULONG_PTR)frame;
+ DPRINT( "%p cookie=%lx\n", handle, *cookie );
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+NTAPI RtlActivateActivationContext( ULONG flags, HANDLE handle, PULONG_PTR cookie )
+{
+ return RtlActivateActivationContextEx(flags, NtCurrentTeb(), handle, cookie);
+}
+
+NTSTATUS
+NTAPI
+RtlDeactivateActivationContext( ULONG flags, ULONG_PTR cookie )
+{
+ RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame, *top;
+
+ DPRINT( "%x cookie=%lx\n", flags, cookie );
+
+ /* find the right frame */
+ top = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame;
+ for (frame = top; frame; frame = frame->Previous)
+ if ((ULONG_PTR)frame == cookie) break;
+
+ if (!frame)
+ RtlRaiseStatus( STATUS_SXS_INVALID_DEACTIVATION );
+
+ if (frame != top && !(flags & RTL_DEACTIVATE_ACTIVATION_CONTEXT_FLAG_FORCE_EARLY_DEACTIVATION))
+ RtlRaiseStatus( STATUS_SXS_EARLY_DEACTIVATION );
+
+ /* pop everything up to and including frame */
+ NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = frame->Previous;
+
+ while (top != NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame)
+ {
+ frame = top->Previous;
+ RtlReleaseActivationContext( top->ActivationContext );
+ RtlFreeHeap( RtlGetProcessHeap(), 0, top );
+ top = frame;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+RtlFreeActivationContextStack(IN PACTIVATION_CONTEXT_STACK Stack)
+{
+ PRTL_ACTIVATION_CONTEXT_STACK_FRAME ActiveFrame, PrevFrame;
+
+ /* Nothing to do if there is no stack */
+ if (!Stack) return;
+
+ /* Get the current active frame */
+ ActiveFrame = Stack->ActiveFrame;
+
+ /* Go through them in backwards order and release */
+ while (ActiveFrame)
+ {
+ PrevFrame = ActiveFrame->Previous;
+ RtlReleaseActivationContext(ActiveFrame->ActivationContext);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, ActiveFrame);
+ ActiveFrame = PrevFrame;
+ }
+
+ /* Zero out the active frame */
+ Stack->ActiveFrame = NULL;
+
+ /* TODO: Empty the Frame List Cache */
+ ASSERT(IsListEmpty(&Stack->FrameListCache));
+
+ /* Free activation stack memory */
+ RtlFreeHeap(RtlGetProcessHeap(), 0, Stack);
+}
+
+VOID
+NTAPI RtlFreeThreadActivationContextStack(VOID)
+{
+ RtlFreeActivationContextStack(NtCurrentTeb()->ActivationContextStackPointer);
+ NtCurrentTeb()->ActivationContextStackPointer = NULL;
+}
+
+
+NTSTATUS
+NTAPI RtlGetActiveActivationContext( HANDLE *handle )
+{
+ if (NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame)
+ {
+ *handle = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame->ActivationContext;
+ RtlAddRefActivationContext( *handle );
+ }
+ else
+ *handle = 0;
+
+ return STATUS_SUCCESS;
+}
+
+
+BOOLEAN
+NTAPI RtlIsActivationContextActive( HANDLE handle )
+{
+ RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
+
+ for (frame = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame; frame; frame = frame->Previous)
+ if (frame->ActivationContext == handle) return TRUE;
+ return FALSE;
+}
+
+NTSTATUS
+NTAPI
+RtlQueryInformationActivationContext( ULONG flags, HANDLE handle, PVOID subinst,
+ ULONG class, PVOID buffer,
+ SIZE_T bufsize, SIZE_T *retlen )
+{
+ ACTIVATION_CONTEXT *actctx;
+ NTSTATUS status;
+
+ DPRINT("%08x %p %p %u %p %Iu %p\n", flags, handle,
+ subinst, class, buffer, bufsize, retlen);
+
+ if (retlen) *retlen = 0;
+ if ((status = find_query_actctx( &handle, flags, class ))) return status;
+
+ switch (class)
+ {
+ case ActivationContextBasicInformation:
+ {
+ ACTIVATION_CONTEXT_BASIC_INFORMATION *info = buffer;
+
+ if (retlen) *retlen = sizeof(*info);
+ if (!info || bufsize < sizeof(*info)) return STATUS_BUFFER_TOO_SMALL;
+
+ info->hActCtx = handle;
+ info->dwFlags = 0; /* FIXME */
+ if (!(flags & RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF)) RtlAddRefActivationContext(handle);
+ }
+ break;
+
+ case ActivationContextDetailedInformation:
+ {
+ ACTIVATION_CONTEXT_DETAILED_INFORMATION *acdi = buffer;
+ struct assembly *assembly = NULL;
+ SIZE_T len, manifest_len = 0, config_len = 0, appdir_len = 0;
+ LPWSTR ptr;
+
+ if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;
+
+ if (actctx->num_assemblies) assembly = actctx->assemblies;
+
+ if (assembly && assembly->manifest.info)
+ manifest_len = strlenW(assembly->manifest.info) + 1;
+ if (actctx->config.info) config_len = strlenW(actctx->config.info) + 1;
+ if (actctx->appdir.info) appdir_len = strlenW(actctx->appdir.info) + 1;
+ len = sizeof(*acdi) + (manifest_len + config_len + appdir_len) * sizeof(WCHAR);
+
+ if (retlen) *retlen = len;
+ if (!buffer || bufsize < len) return STATUS_BUFFER_TOO_SMALL;
+
+ acdi->dwFlags = 0;
+ acdi->ulFormatVersion = assembly ? 1 : 0; /* FIXME */
+ acdi->ulAssemblyCount = actctx->num_assemblies;
+ acdi->ulRootManifestPathType = assembly ? assembly->manifest.type : 0 /* FIXME */;
+ acdi->ulRootManifestPathChars = assembly && assembly->manifest.info ? (DWORD)manifest_len - 1 : 0;
+ acdi->ulRootConfigurationPathType = actctx->config.type;
+ acdi->ulRootConfigurationPathChars = actctx->config.info ? (DWORD)config_len - 1 : 0;
+ acdi->ulAppDirPathType = actctx->appdir.type;
+ acdi->ulAppDirPathChars = actctx->appdir.info ? (DWORD)appdir_len - 1 : 0;
+ ptr = (LPWSTR)(acdi + 1);
+ if (manifest_len)
+ {
+ acdi->lpRootManifestPath = ptr;
+ memcpy(ptr, assembly->manifest.info, manifest_len * sizeof(WCHAR));
+ ptr += manifest_len;
+ }
+ else acdi->lpRootManifestPath = NULL;
+ if (config_len)
+ {
+ acdi->lpRootConfigurationPath = ptr;
+ memcpy(ptr, actctx->config.info, config_len * sizeof(WCHAR));
+ ptr += config_len;
+ }
+ else acdi->lpRootConfigurationPath = NULL;
+ if (appdir_len)
+ {
+ acdi->lpAppDirPath = ptr;
+ memcpy(ptr, actctx->appdir.info, appdir_len * sizeof(WCHAR));
+ }
+ else acdi->lpAppDirPath = NULL;
+ }
+ break;
+
+ case AssemblyDetailedInformationInActivationContext:
+ {
+ ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *afdi = buffer;
+ struct assembly *assembly;
+ WCHAR *assembly_id;
+ DWORD index;
+ SIZE_T len, id_len = 0, ad_len = 0, path_len = 0;
+ LPWSTR ptr;
+
+ if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;
+ if (!subinst) return STATUS_INVALID_PARAMETER;
+
+ index = *(DWORD*)subinst;
+ if (!index || index > actctx->num_assemblies) return STATUS_INVALID_PARAMETER;
+
+ assembly = &actctx->assemblies[index - 1];
+
+ if (!(assembly_id = build_assembly_id( &assembly->id ))) return STATUS_NO_MEMORY;
+ id_len = strlenW(assembly_id) + 1;
+ if (assembly->directory) ad_len = strlenW(assembly->directory) + 1;
+
+ if (assembly->manifest.info &&
+ (assembly->type == ASSEMBLY_MANIFEST || assembly->type == ASSEMBLY_SHARED_MANIFEST))
+ path_len = strlenW(assembly->manifest.info) + 1;
+
+ len = sizeof(*afdi) + (id_len + ad_len + path_len) * sizeof(WCHAR);
+
+ if (retlen) *retlen = len;
+ if (!buffer || bufsize < len)
+ {
+ RtlFreeHeap( RtlGetProcessHeap(), 0, assembly_id );
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ afdi->ulFlags = 0; /* FIXME */
+ afdi->ulEncodedAssemblyIdentityLength = (DWORD)(id_len - 1) * sizeof(WCHAR);
+ afdi->ulManifestPathType = assembly->manifest.type;
+ afdi->ulManifestPathLength = assembly->manifest.info ? (DWORD)(path_len - 1) * sizeof(WCHAR) : 0;
+ /* FIXME afdi->liManifestLastWriteTime = 0; */
+ afdi->ulPolicyPathType = ACTIVATION_CONTEXT_PATH_TYPE_NONE; /* FIXME */
+ afdi->ulPolicyPathLength = 0;
+ /* FIXME afdi->liPolicyLastWriteTime = 0; */
+ afdi->ulMetadataSatelliteRosterIndex = 0; /* FIXME */
+ afdi->ulManifestVersionMajor = 1;
+ afdi->ulManifestVersionMinor = 0;
+ afdi->ulPolicyVersionMajor = 0; /* FIXME */
+ afdi->ulPolicyVersionMinor = 0; /* FIXME */
+ afdi->ulAssemblyDirectoryNameLength = ad_len ? (DWORD)(ad_len - 1) * sizeof(WCHAR) : 0;
+ ptr = (LPWSTR)(afdi + 1);
+ afdi->lpAssemblyEncodedAssemblyIdentity = ptr;
+ memcpy( ptr, assembly_id, id_len * sizeof(WCHAR) );
+ ptr += id_len;
+ if (path_len)
+ {
+ afdi->lpAssemblyManifestPath = ptr;
+ memcpy(ptr, assembly->manifest.info, path_len * sizeof(WCHAR));
+ ptr += path_len;
+ } else afdi->lpAssemblyManifestPath = NULL;
+ afdi->lpAssemblyPolicyPath = NULL; /* FIXME */
+ if (ad_len)
+ {
+ afdi->lpAssemblyDirectoryName = ptr;
+ memcpy(ptr, assembly->directory, ad_len * sizeof(WCHAR));
+ }
+ else afdi->lpAssemblyDirectoryName = NULL;
+ RtlFreeHeap( RtlGetProcessHeap(), 0, assembly_id );
+ }
+ break;
+
+ case FileInformationInAssemblyOfAssemblyInActivationContext:
+ {
+ const ACTIVATION_CONTEXT_QUERY_INDEX *acqi = subinst;
+ ASSEMBLY_FILE_DETAILED_INFORMATION *afdi = buffer;
+ struct assembly *assembly;
+ struct dll_redirect *dll;
+ SIZE_T len, dll_len = 0;
+ LPWSTR ptr;
+
+ if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;
+ if (!acqi) return STATUS_INVALID_PARAMETER;
+
+ if (acqi->ulAssemblyIndex >= actctx->num_assemblies)
+ return STATUS_INVALID_PARAMETER;
+ assembly = &actctx->assemblies[acqi->ulAssemblyIndex];
+
+ if (acqi->ulFileIndexInAssembly >= assembly->num_dlls)
+ return STATUS_INVALID_PARAMETER;
+ dll = &assembly->dlls[acqi->ulFileIndexInAssembly];
+
+ if (dll->name) dll_len = strlenW(dll->name) + 1;
+ len = sizeof(*afdi) + dll_len * sizeof(WCHAR);
+
+ if (!buffer || bufsize < len)
+ {
+ if (retlen) *retlen = len;
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+ if (retlen) *retlen = 0; /* yes that's what native does !! */
+ afdi->ulFlags = ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION;
+ afdi->ulFilenameLength = dll_len ? (DWORD)(dll_len - 1) * sizeof(WCHAR) : 0;
+ afdi->ulPathLength = 0; /* FIXME */
+ ptr = (LPWSTR)(afdi + 1);
+ if (dll_len)
+ {
+ afdi->lpFileName = ptr;
+ memcpy( ptr, dll->name, dll_len * sizeof(WCHAR) );
+ } else afdi->lpFileName = NULL;
+ afdi->lpFilePath = NULL; /* FIXME */
+ }
+ break;
+
+ default:
+ DPRINT( "class %u not implemented\n", class );
+ return STATUS_NOT_IMPLEMENTED;
+ }
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+RtlQueryInformationActiveActivationContext(ULONG ulInfoClass,
+ PVOID pvBuffer,
+ SIZE_T cbBuffer OPTIONAL,
+ SIZE_T *pcbWrittenOrRequired OPTIONAL)
+{
+ return RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT,
+ NULL,
+ NULL,
+ ulInfoClass,
+ pvBuffer,
+ cbBuffer,
+ pcbWrittenOrRequired);
+}
+
+#define FIND_ACTCTX_RETURN_FLAGS 0x00000002
+#define FIND_ACTCTX_RETURN_ASSEMBLY_METADATA 0x00000004
+#define FIND_ACTCTX_VALID_MASK (FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX | FIND_ACTCTX_RETURN_FLAGS | FIND_ACTCTX_RETURN_ASSEMBLY_METADATA)
+
+NTSTATUS
+NTAPI
+RtlpFindActivationContextSection_CheckParameters( ULONG flags, const GUID *guid, ULONG section_kind,
- UNICODE_STRING *section_name, PVOID ptr )
++ const UNICODE_STRING *section_name, PACTCTX_SECTION_KEYED_DATA data )
+{
+ /* Check general parameter combinations */
+ if (!section_name ||
+ (flags & ~FIND_ACTCTX_VALID_MASK) ||
+ ((flags & FIND_ACTCTX_VALID_MASK) && !data) ||
+ (data && data->cbSize < offsetof(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex)))
+ {
+ DPRINT1("invalid parameter\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* TODO */
+ if (flags & FIND_ACTCTX_RETURN_FLAGS ||
+ flags & FIND_ACTCTX_RETURN_ASSEMBLY_METADATA)
+ {
+ DPRINT1("unknown flags %08x\n", flags);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+RtlFindActivationContextSectionString( ULONG flags, const GUID *guid, ULONG section_kind,
++ const UNICODE_STRING *section_name, PVOID ptr )
+{
+ PACTCTX_SECTION_KEYED_DATA data = ptr;
+ NTSTATUS status;
+
+ status = RtlpFindActivationContextSection_CheckParameters(flags, guid, section_kind, section_name, data);
+ if (!NT_SUCCESS(status)) return status;
+
+ status = STATUS_SXS_KEY_NOT_FOUND;
+
+ /* if there is no data, but params are valid,
+ we return that sxs key is not found to be at least somehow compatible */
+ if (!data) return status;
+
+ ASSERT(NtCurrentTeb());
+ ASSERT(NtCurrentTeb()->ActivationContextStackPointer);
+
+ if (NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame)
+ {
+ ACTIVATION_CONTEXT *actctx = check_actctx(NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame->ActivationContext);
+ if (actctx) status = find_string( actctx, section_kind, section_name, flags, data );
+ }
+
+ if (status != STATUS_SUCCESS)
+ status = find_string( process_actctx, section_kind, section_name, flags, data );
+
+ return status;
+}
+
+NTSTATUS WINAPI RtlFindActivationContextSectionGuid( ULONG flags, const GUID *extguid, ULONG section_kind,
+ const GUID *guid, void *ptr )
+{
+ ACTCTX_SECTION_KEYED_DATA *data = ptr;
+ NTSTATUS status = STATUS_SXS_KEY_NOT_FOUND;
+
+ if (extguid)
+ {
+ DPRINT1("expected extguid == NULL\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (flags & ~FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX)
+ {
+ DPRINT1("unknown flags %08x\n", flags);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (!data || data->cbSize < FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) || !guid)
+ return STATUS_INVALID_PARAMETER;
+
+ if (NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame)
+ {
+ ACTIVATION_CONTEXT *actctx = check_actctx(NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame->ActivationContext);
+ if (actctx) status = find_guid( actctx, section_kind, guid, flags, data );
+ }
+
+ if (status != STATUS_SUCCESS)
+ status = find_guid( process_actctx, section_kind, guid, flags, data );
+
+ return status;
+}
+
+/* Stubs */
+
+NTSTATUS
+NTAPI
+RtlAllocateActivationContextStack(IN PACTIVATION_CONTEXT_STACK *Stack)
+{
+ PACTIVATION_CONTEXT_STACK ContextStack;
+
+ /* Check if it's already allocated */
+ if (*Stack) return STATUS_SUCCESS;
+
+ /* Allocate space for the context stack */
+ ContextStack = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACTIVATION_CONTEXT_STACK));
+ if (!ContextStack)
+ {
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Initialize the context stack */
+ ContextStack->Flags = 0;
+ ContextStack->ActiveFrame = NULL;
+ InitializeListHead(&ContextStack->FrameListCache);
+ ContextStack->NextCookieSequenceNumber = 1;
+ ContextStack->StackId = 1; //TODO: Timer-based
+
+ *Stack = ContextStack;
+
+ return STATUS_SUCCESS;
+}
+
+PRTL_ACTIVATION_CONTEXT_STACK_FRAME
+FASTCALL
+RtlActivateActivationContextUnsafeFast(IN PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame,
+ IN PVOID Context)
+{
+#if NEW_NTDLL_LOADER
+ RTL_ACTIVATION_CONTEXT_STACK_FRAME *ActiveFrame;
+
+ /* Get the curren active frame */
+ ActiveFrame = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame;
+
+ DPRINT1("ActiveFrame %p, &Frame->Frame %p, Context %p\n", ActiveFrame, &Frame->Frame, Context);
+
+ /* Actually activate it */
+ Frame->Frame.Previous = ActiveFrame;
+ Frame->Frame.ActivationContext = Context;
+ Frame->Frame.Flags = 0;
+
+ /* Check if we can activate this context */
+ if ((ActiveFrame && (ActiveFrame->ActivationContext != Context)) ||
+ Context)
+ {
+ /* Set new active frame */
+ NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = &Frame->Frame;
+ return &Frame->Frame;
+ }
+
+ /* We can get here only one way: it was already activated */
+ DPRINT1("Trying to activate improper activation context\n");
+
+ /* Activate only if we are allowing multiple activation */
+ if (!RtlpNotAllowingMultipleActivation)
+ {
+ NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = &Frame->Frame;
+ }
+ else
+ {
+ /* Set flag */
+ Frame->Frame.Flags = 0x30;
+ }
+
+ /* Return pointer to the activation frame */
+ return &Frame->Frame;
+#else
+
+ RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame = &Frame->Frame;
+
+ frame->Previous = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame;
+ frame->ActivationContext = Context;
+ frame->Flags = 0;
+
+ NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = frame;
+
+ return STATUS_SUCCESS;
+#endif
+}
+
+PRTL_ACTIVATION_CONTEXT_STACK_FRAME
+FASTCALL
+RtlDeactivateActivationContextUnsafeFast(IN PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame)
+{
+ RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
+ //RTL_ACTIVATION_CONTEXT_STACK_FRAME *top;
+
+ /* find the right frame */
+ //top = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame;
+ frame = &Frame->Frame;
+
+ if (!frame)
+ {
+ DPRINT1("No top frame!\n");
+ RtlRaiseStatus( STATUS_SXS_INVALID_DEACTIVATION );
+ }
+
+ /* pop everything up to and including frame */
+ NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = frame->Previous;
+
+ return frame;
+}
+
+
+NTSTATUS
+NTAPI
+RtlZombifyActivationContext(PVOID Context)
+{
+ UNIMPLEMENTED;
+
+ if (Context == ACTCTX_FAKE_HANDLE)
+ return STATUS_SUCCESS;
+
+ return STATUS_NOT_IMPLEMENTED;
+}
+
--- /dev/null
- reactos/dll/win32/kernel32/wine/actctx.c # Partly synced
+# ReactOS WINE porting guide for 0.3
+# Update this file when you port a dll/program from WINE.
+
+The ReactOS Project shares quite a bit of code with the WINE project.
+This document should provide a compleate reference for all of the
+locations in the ReactOS source tree where code is shared between the
+two projects. If you find something is missing from this documentation
+please add it.
+
+If you find that a function in ReactOS that is not implemented properly
+and is based on WINE sources, check the latest Winehq CVS and see if
+it has been fixed there. If so, please submit a patch to
+ros-dev@reactos.org. Otherwise please send a patch to both
+wine-patches@winehq.com and ros-dev@reactos.org
+
+When porting a new DLL from Wine to ReactOS, please do the following steps
+- Create a new directory in dll/win32/ of the same name as the new Wine DLL
+- Add a new entry in dll/win32/win32.rbuild
+- Follow the guide "Update process for autosync DLLs" at the bottom of this file
+
+
+The following build tools are shared with Wine.
+
+reactos/tools/unicode # Synced to Wine-1.7.17
+reactos/tools/widl # Synced to Wine-1.7.17
+reactos/tools/wpp # Synced to Wine-1.7.17
+
+The following libraries are shared with Wine.
+
+reactos/dll/directx/wine/amstream # Synced to Wine-1.7.17
+reactos/dll/directx/wine/d3d8 # Synced to Wine-1.7.17
+reactos/dll/directx/wine/d3d9 # Synced to Wine-1.7.17
+reactos/dll/directx/wine/d3dcompiler_43 # Synced to Wine-1.7.17
+reactos/dll/directx/wine/d3dx9_24 => 43 # Synced to Wine-1.7.17
+reactos/dll/directx/wine/d3dxof # Synced to Wine-1.7.17
+reactos/dll/directx/wine/ddraw # Synced to Wine-1.7.17
+reactos/dll/directx/wine/devenum # Synced to Wine-1.7.17
+reactos/dll/directx/wine/dinput # Synced to Wine-1.7.17
+reactos/dll/directx/wine/dinput8 # Synced to Wine-1.7.17
+reactos/dll/directx/wine/dmusic # Synced to Wine-1.7.17
+reactos/dll/directx/wine/dplay # Synced to Wine-1.7.17
+reactos/dll/directx/wine/dplayx # Synced to Wine-1.7.17
+reactos/dll/directx/wine/dsound # Synced to Wine-1.5.26
+reactos/dll/directx/wine/dxdiagn # Synced to Wine-1.7.17
+reactos/dll/directx/wine/dxgi # Synced to Wine-1.7.17
+reactos/dll/directx/wine/msdmo # Synced to Wine-1.7.17
+reactos/dll/directx/wine/qedit # Synced to Wine-1.7.17
+reactos/dll/directx/wine/quartz # Synced to Wine-1.7.17
+reactos/dll/directx/wine/wined3d # Synced to Wine-1.7.17
+
+reactos/dll/win32/activeds # Synced to Wine-1.7.17
+reactos/dll/win32/actxprxy # Synced to Wine-1.7.17
+reactos/dll/win32/advpack # Synced to Wine-1.7.17
+reactos/dll/win32/atl # Synced to Wine-1.7.17
+reactos/dll/win32/atl100 # Synced to Wine-1.7.17
+reactos/dll/win32/atl80 # Synced to Wine-1.7.17
+reactos/dll/win32/avifil32 # Synced to Wine-1.7.17
+reactos/dll/win32/bcrypt # Synced to Wine-1.7.17
+reactos/dll/win32/browseui # Out of sync
+reactos/dll/win32/cabinet # Synced to Wine-1.7.17
+reactos/dll/win32/clusapi # Synced to Wine-1.7.17
+reactos/dll/win32/comcat # Synced to Wine-1.7.17
+reactos/dll/win32/comctl32 # Synced to Wine-1.7.17
+reactos/dll/win32/comdlg32 # Synced to Wine-1.7.17
+reactos/dll/win32/compstui # Synced to Wine-1.7.17
+reactos/dll/win32/credui # Synced to Wine-1.7.17
+reactos/dll/win32/crypt32 # Synced to Wine-1.7.17
+reactos/dll/win32/cryptdlg # Synced to Wine-1.7.17
+reactos/dll/win32/cryptdll # Synced to Wine-1.7.17
+reactos/dll/win32/cryptnet # Synced to Wine-1.7.17
+reactos/dll/win32/cryptui # Synced to Wine-1.7.17
+reactos/dll/win32/dbghelp # Synced to Wine-1.7.17
+reactos/dll/win32/dciman32 # Synced to Wine-1.7.17
+reactos/dll/win32/dwmapi # Synced to Wine-1.7.17
+reactos/dll/win32/faultrep # Synced to Wine-1.7.17
+reactos/dll/win32/fusion # Synced to Wine-1.7.17
+reactos/dll/win32/gdiplus # Synced to Wine-1.7.17
+reactos/dll/win32/hhctrl.ocx # Synced to Wine-1.7.17
+reactos/dll/win32/hlink # Synced to Wine-1.7.17
+reactos/dll/win32/hnetcfg # Synced to Wine-1.7.17
+reactos/dll/win32/httpapi # Synced to Wine-1.7.17
+reactos/dll/win32/iccvid # Synced to Wine-1.7.17
+reactos/dll/win32/icmp # Out of sync
+reactos/dll/win32/ieframe # Synced to Wine-1.7.17
+reactos/dll/win32/imaadp32.acm # Synced to Wine-1.7.17
+reactos/dll/win32/imagehlp # Synced to Wine-1.7.17
+reactos/dll/win32/imm32 # Synced to Wine-1.7.17
+reactos/dll/win32/inetcomm # Synced to Wine-1.7.17
+reactos/dll/win32/inetmib1 # Synced to Wine-1.7.1
+reactos/dll/win32/initpki # Synced to Wine-1.7.17
+reactos/dll/win32/inseng # Synced to Wine-1.7.17
+reactos/dll/win32/iphlpapi # Out of sync
+reactos/dll/win32/itircl # Synced to Wine-1.7.17
+reactos/dll/win32/itss # Synced to Wine-1.7.17
+reactos/dll/win32/jscript # Synced to Wine-1.7.17
+reactos/dll/win32/loadperf # Synced to Wine-1.7.17
+reactos/dll/win32/localspl # Synced to Wine-1.7.17
+reactos/dll/win32/localui # Synced to Wine-1.7.17
+reactos/dll/win32/lz32 # Synced to Wine-1.7.17
+reactos/dll/win32/mapi32 # Synced to Wine-1.7.17
+reactos/dll/win32/mciavi32 # Synced to Wine-1.7.17
+reactos/dll/win32/mcicda # Synced to Wine-1.7.17
+reactos/dll/win32/mciqtz32 # Synced to Wine-1.7.17
+reactos/dll/win32/mciseq # Synced to Wine-1.7.17
+reactos/dll/win32/mciwave # Synced to Wine-1.7.17
+reactos/dll/win32/mlang # Synced to Wine-1.7.17
+reactos/dll/win32/mmdevapi # Synced to Wine-1.7.1
+reactos/dll/win32/mpr # Synced to Wine-1.7.17
+reactos/dll/win32/mprapi # Synced to Wine-1.7.17
+reactos/dll/win32/msacm32 # Synced to Wine-1.7.17
+reactos/dll/win32/msacm32/msacm32.drv # Synced to Wine-1.7.17
+reactos/dll/win32/msadp32.acm # Synced to Wine-1.7.17
+reactos/dll/win32/mscat32 # Synced to Wine-1.7.17
+reactos/dll/win32/mscms # Synced to Wine-1.7.17
+reactos/dll/win32/mscoree # Synced to Wine-1.5.4
+reactos/dll/win32/msctf # Synced to Wine-1.7.17
+reactos/dll/win32/msftedit # Synced to Wine-1.7.17
+reactos/dll/win32/msg711.acm # Synced to Wine-1.7.17
+reactos/dll/win32/msgsm32.acm # Synced to Wine-1.7.17
+reactos/dll/win32/mshtml # Synced to Wine-1.7.17
+reactos/dll/win32/mshtml.tlb # Synced to Wine-1.7.17
+reactos/dll/win32/msi # Synced to Wine-1.7.17
+reactos/dll/win32/msimg32 # Synced to Wine-1.7.17
+reactos/dll/win32/msimtf # Synced to Wine-1.7.17
+reactos/dll/win32/msisip # Synced to Wine-1.7.17
+reactos/dll/win32/msisys.ocx # Synced to Wine-1.7.17
+reactos/dll/win32/msnet32 # Synced to Wine-1.7.17
+reactos/dll/win32/msrle32 # Synced to Wine-1.7.17
+reactos/dll/win32/mssign32 # Synced to Wine-1.7.17
+reactos/dll/win32/mssip32 # Synced to Wine-1.7.17
+reactos/dll/win32/mstask # Synced to Wine-1.7.17
+reactos/dll/win32/msvcrt20 # Out of sync
+reactos/dll/win32/msvcrt40 # Out of sync
+reactos/dll/win32/msvfw32 # Synced to Wine-1.7.17
+reactos/dll/win32/msvidc32 # Synced to Wine-1.7.17
+reactos/dll/win32/msxml # Synced to Wine-1.7.17
+reactos/dll/win32/msxml2 # Synced to Wine-1.7.17
+reactos/dll/win32/msxml3 # Synced to Wine-1.7.17
+reactos/dll/win32/msxml4 # Synced to Wine-1.7.17
+reactos/dll/win32/msxml6 # Synced to Wine-1.7.17
+reactos/dll/win32/nddeapi # Synced to Wine-1.7.17
+reactos/dll/win32/netapi32 # Forked at Wine-1.3.34
+reactos/dll/win32/ntdsapi # Synced to Wine-1.7.17
+reactos/dll/win32/ntprint # Synced to Wine-1.7.17
+reactos/dll/win32/objsel # Synced to Wine-1.7.17
+reactos/dll/win32/odbc32 # Synced to Wine-1.7.17. Depends on port of Linux ODBC.
+reactos/dll/win32/odbccp32 # Synced to Wine-1.7.17
+reactos/dll/win32/ole32 # Synced to Wine-1.7.17
+reactos/dll/win32/oleacc # Synced to Wine-1.7.17
+reactos/dll/win32/oleaut32 # Synced to Wine-1.7.17
+reactos/dll/win32/olecli32 # Synced to Wine-1.7.17
+reactos/dll/win32/oledlg # Synced to Wine-1.7.17
+reactos/dll/win32/olepro32 # Synced to Wine-1.7.17
+reactos/dll/win32/olesvr32 # Synced to Wine-1.7.17
+reactos/dll/win32/olethk32 # Synced to Wine-1.7.17
+reactos/dll/win32/pdh # Synced to Wine-1.7.17
+reactos/dll/win32/pidgen # Synced to Wine-1.7.17
+reactos/dll/win32/powrprof # Forked at Wine-1.0rc5
+reactos/dll/win32/printui # Synced to Wine-1.7.17
+reactos/dll/win32/propsys # Synced to Wine-1.7.17
+reactos/dll/win32/pstorec # Synced to Wine-1.7.17
+reactos/dll/win32/qmgr # Synced to Wine-1.7.17
+reactos/dll/win32/qmgrprxy # Synced to Wine-1.7.17
+reactos/dll/win32/query # Synced to Wine-1.7.17
+reactos/dll/win32/rasapi32 # Synced to Wine-1.7.17
+reactos/dll/win32/resutils # Synced to Wine-1.7.17
+reactos/dll/win32/riched20 # Synced to Wine-1.7.17
+reactos/dll/win32/riched32 # Synced to Wine-1.7.17
+reactos/dll/win32/rpcrt4 # Synced to Wine-1.7.17
+reactos/dll/win32/rsabase # Synced to Wine-1.7.17
+reactos/dll/win32/rsaenh # Synced to Wine-1.7.17
+reactos/dll/win32/sccbase # Synced to Wine-1.7.17
+reactos/dll/win32/schannel # Synced to Wine-1.7.17
+reactos/dll/win32/scrrun # Synced to Wine-1.7.17
+reactos/dll/win32/secur32 # Forked
+reactos/dll/win32/security # Forked (different .spec)
+reactos/dll/win32/sensapi # Synced to Wine-1.7.17
+reactos/dll/win32/setupapi # Forked at Wine-20050524
+reactos/dll/win32/shdoclc # Synced to Wine-1.7.17
+reactos/dll/win32/shdocvw # Synced to Wine-1.7.17
+reactos/dll/win32/shell32 # Forked at Wine-20071011
+reactos/dll/win32/shfolder # Synced to Wine-1.7.17
+reactos/dll/win32/shlwapi # Synced to Wine-1.7.17
+reactos/dll/win32/slbcsp # Synced to Wine-1.7.17
+reactos/dll/win32/snmpapi # Synced to Wine-1.7.17
+reactos/dll/win32/softpub # Synced to Wine-1.7.17
+reactos/dll/win32/spoolss # Synced to Wine-1.7.17
+reactos/dll/win32/stdole2.tlb # Synced to Wine-1.7.17
+reactos/dll/win32/stdole32.tlb # Synced to Wine-1.7.17
+reactos/dll/win32/sti # Synced to Wine-1.7.17
+reactos/dll/win32/sxs # Synced to Wine-1.7.17
+reactos/dll/win32/tapi32 # Synced to Wine-1.7.17
+reactos/dll/win32/traffic # Synced to Wine-1.7.17
+reactos/dll/win32/twain_32 # Synced to Wine-1.7.17
+reactos/dll/win32/unicows # Synced to Wine-1.3.32 (Win9x only, why do we need this?!)
+reactos/dll/win32/updspapi # Synced to Wine-1.7.17
+reactos/dll/win32/url # Synced to Wine-1.7.17
+reactos/dll/win32/urlmon # Synced to Wine-1.7.17
+reactos/dll/win32/usp10 # Synced to Wine-1.7.17
+reactos/dll/win32/uxtheme # Forked
+reactos/dll/win32/vbscript # Synced to Wine-1.7.17
+reactos/dll/win32/version # Synced to Wine-1.7.17
+reactos/dll/win32/wbemdisp # Synced to Wine-1.7.17
+reactos/dll/win32/wbemprox # Synced to Wine-1.7.17
+reactos/dll/win32/wer # Autosync
+reactos/dll/win32/windowscodecs # Synced to Wine-1.7.17
+reactos/dll/win32/windowscodecsext # Synced to Wine-1.7.17
+reactos/dll/win32/winemp3.acm # Synced to Wine-1.7.17
+reactos/dll/win32/wing32 # Out of sync
+reactos/dll/win32/winhttp # Synced to Wine-1.7.17
+reactos/dll/win32/wininet # Synced to Wine-1.7.17
+reactos/dll/win32/winmm # Forked at Wine-20050628
+reactos/dll/win32/winmm/midimap # Forked at Wine-20050628
+reactos/dll/win32/winmm/wavemap # Forked at Wine-20050628
+reactos/dll/win32/wintrust # Synced to Wine-1.7.17
+reactos/dll/win32/wldap32 # Synced to Wine-1.7.17
+reactos/dll/win32/wmi # Synced to Wine-1.7.17
+reactos/dll/win32/wtsapi32 # Synced to Wine-1.7.17
+reactos/dll/win32/wuapi # Synced to Wine-1.7.17
+reactos/dll/win32/xinput1_1 # Synced to Wine-1.7.17
+reactos/dll/win32/xinput1_2 # Synced to Wine-1.7.17
+reactos/dll/win32/xinput1_3 # Synced to Wine-1.7.17
+reactos/dll/win32/xinput9_1_0 # Synced to Wine-1.7.17
+reactos/dll/win32/xmllite # Synced to Wine-1.7.17
+
+reactos/dll/cpl/inetcpl # Synced to Wine-1.7.1
+
+ReactOS shares the following programs with Winehq.
+
+reactos/base/applications/cmdutils/reg # Synced to Wine-1.7.1
+reactos/base/applications/cmdutils/taskkill # Synced to Wine-1.7.1
+reactos/base/applications/cmdutils/wmic # Synced to Wine-1.7.1
+reactos/base/applications/cmdutils/xcopy # Synced to Wine-1.7.1
+reactos/base/applications/games/winmine # Forked at Wine-1_3_5
+reactos/base/applications/extrac32 # Synced to Wine-1.7.1
+reactos/base/applications/iexplore # Synced to Wine-1.7.1
+reactos/base/applications/notepad # Forked at Wine-20041201
+reactos/base/applications/regedit # Out of sync
+reactos/base/applications/winhlp32 # Synced to Wine-1.5.26
+reactos/base/applications/wordpad # Synced to Wine-1.7.9
+reactos/base/services/rpcss # Synced to Wine-1.7.1
+reactos/base/system/expand # Synced to Wine-1.7.1
+reactos/base/system/msiexec # Synced to Wine-1.7.1
+reactos/modules/rosapps/winfile # Autosync
+
+In addition the following libs, dlls and source files are mostly based on code ported
+from Winehq CVS. If you are looking to update something in these files
+check Wine current souces first as it may already be fixed.
+
+reactos/lib/3rdparty/strmbase # Synced to Wine-1.7.17
+
+advapi32 -
+ reactos/dll/win32/advapi32/crypt/*.c # Synced to Wine-1.7.1
+ reactos/dll/win32/advapi32/sec/cred.c # Synced to Wine-1.7.1
+ reactos/dll/win32/advapi32/sec/sid.c # Out of Sync
+
+gdi32 -
+ reactos/dll/win32/gdi32/objects/linedda.c # Synced at 20090410
+
+kernel32 -
++ reactos/dll/win32/kernel32/wine/actctx.c # Partly synced with Wine 1.7.17
+ reactos/dll/win32/kernel32/wine/comm.c # Synced in r52754
+ reactos/dll/win32/kernel32/wine/lzexpand.c # Synced in r52754
+ reactos/dll/win32/kernel32/wine/profile.c # Synced in r52754
+ reactos/dll/win32/kernel32/wine/res.c # Synced in r52754
+ reactos/dll/win32/kernel32/winnls/string/casemap.c # Synced in r52754
+ reactos/dll/win32/kernel32/winnls/string/chartype.c # Synced in r52754
+ reactos/dll/win32/kernel32/winnls/string/collation.c # Synced in r52754
+ reactos/dll/win32/kernel32/winnls/string/format_msg.c # Synced to Wine-1.5.4
+ reactos/dll/win32/kernel32/winnls/string/lang.c # Synced in r52754
+ reactos/dll/win32/kernel32/winnls/string/lcformat.c # Synced in r52754
+ reactos/dll/win32/kernel32/winnls/string/nls.c # Synced in r52754
+ reactos/dll/win32/kernel32/winnls/string/sortkey.c # Synced in r52754
+
+msvcrt -
+ reactos/lib/sdk/crt/except/cpp.c # Synced at 20080528
+ reactos/lib/sdk/crt/except/cppexcept.c # Synced at 20071111
++ reactos/lib/sdk/crt/signal/xcptinfo.c # Synced to Wine-1.7.17
+ reactos/lib/sdk/crt/string/scanf.c/h # Synced to Wine-1_1_27
+ reactos/lib/sdk/crt/strings/wcs.c # Synced at 20080611
+ reactos/lib/sdk/crt/wine/heap.c # Synced at 20080529
+ reactos/lib/sdk/crt/wine/undname.c # Synced at 20081130
+ reactos/lib/sdk/crt/thread/thread.c # Synced at 20080604
+
+User32 -
+ reactos/dll/win32/user32/controls/button.c # Synced to Wine-1_1_39
+ reactos/dll/win32/user32/controls/combo.c # Synced to Wine-1.5.10
+ reactos/dll/win32/user32/controls/edit.c # Synced to Wine-1_1_40
+ reactos/dll/win32/user32/controls/icontitle.c # Synced to Wine-1_1_39
+ reactos/dll/win32/user32/controls/listbox.c # Synced to Wine-1_1_39
+ reactos/dll/win32/user32/controls/scrollbar.c # Forked
+ reactos/dll/win32/user32/controls/static.c # Synced to Wine-1_1_39
+
+ reactos/dll/win32/user32/include/dde_private.h # Synced to Wine-1.1.24
+
+ reactos/dll/win32/user32/misc/dde.c # Synced to Wine-1.1.24 (dde_misc.c)
+ reactos/dll/win32/user32/misc/ddeclient.c # Synced to Wine-1_1_23
+ reactos/dll/win32/user32/misc/ddeserver.c # Synced to Wine-1_1_23
+ reactos/dll/win32/user32/misc/exticon.c # Synced to Wine-1_1_22
+ reactos/dll/win32/user32/misc/resources.c # Forked?
+ reactos/dll/win32/user32/misc/winhelp.c # Last sync date unknown
+ reactos/dll/win32/user32/misc/wsprintf.c # Synced to Wine-1_1_23
+
+ reactos/dll/win32/user32/windows/cursoricon # Forked from Wine-1.2-rc7
+ reactos/dll/win32/user32/windows/defwnd.c # Forked
+ reactos/dll/win32/user32/windows/draw.c # Forked at Wine-20020904 (uitools.c)
+ reactos/dll/win32/user32/windows/mdi.c # Synced to Wine-1_1_40
+ reactos/dll/win32/user32/windows/menu.c # Forked
+ reactos/dll/win32/user32/windows/messagebox.c # Forked
+ reactos/dll/win32/user32/windows/rect.c # Forked (uitools.c)
+ reactos/dll/win32/user32/windows/spy.c # Synced to Wine-1_1_40
+ reactos/dll/win32/user32/windows/text.c # Forked (lstr.c)
+ reactos/dll/win32/user32/windows/winpos.c # Forked
+
+ws2_32 -
+ reactos/dll/win32/ws2_32/misc/async.c # Synced to Wine-1.5.4
+
+Update process for autosync DLLs
+
+*** This process can only be done on Microsoft Windows ***
+- Download wineimport.cmd at svn://svn.reactos.org/project-tools/trunk/
+- Download cvs command line program and be sure to put it in your path
+ (available at http://ftp.gnu.org/non-gnu/cvs/binary/stable/x86-woe/ )
+- Download svn command line program and be sure to put it in your path
+ (available at http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91 )
+- Download patch command line program and be sure to put it in your path
+ (available at http://gnuwin32.sourceforge.net/packages/patch.htm )
+- Optionally, download junction.exe and put it in your path
+ (available at http://www.sysinternals.com/Utilities/Junction.html )
+- Cd to the directory containing wineimport.cmd
+- Run
+ "wineimport.cmd fullprocessing {path_to_your_reactos_directory} {name_of_the_wine_dll}"
+- In case of error, you can
+ 1) add missing definitions to ReactOS headers
+ 2) fix {name_of_the_wine_dll}_ros.diff patch file, by removing outdated changes
+ 3) or modify Wine code, by adding a {name_of_the_wine_dll}_ros.diff patch,
+ which will be applied after Wine source checkout
+ DO NOT DIRECTLY MODIFY WINE SOURCE CODE
+- Once Wine DLL compiles, install and run ReactOS and search for regressions
+- In case of regression, you can
+ 1) Fix ReactOS code (not in the shared DLL)
+ 2) or update the {name_of_the_wine_dll}_ros.diff patch file
+- Commit your changes with the "Autosyncing with Wine HEAD" commit message
--- /dev/null
- PMENU FORCEINLINE MENU_GetMenu(HMENU hMenu)
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS user32.dll
+ * FILE: user32/windows/menu.c
+ * PURPOSE: Menus
+ *
+ * PROGRAMMERS: Casper S. Hornstrup
+ * James Tabor
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <user32.h>
+#include <wine/debug.h>
+
+LRESULT DefWndNCPaint(HWND hWnd, HRGN hRgn, BOOL Active);
+BOOL WINAPI GdiValidateHandle(HGDIOBJ hobj);
++LRESULT DefWndNCHitTest(HWND hWnd, POINT Point);
++void FASTCALL NcGetSysPopupPos(HWND Wnd, RECT *Rect);
+
+WINE_DEFAULT_DEBUG_CHANNEL(menu);
+
+/* internal popup menu window messages */
+
+#define MM_SETMENUHANDLE (WM_USER + 0)
+#define MM_GETMENUHANDLE (WM_USER + 1)
+
+/* internal flags for menu tracking */
+
+#define TF_ENDMENU 0x10000
+#define TF_SUSPENDPOPUP 0x20000
+#define TF_SKIPREMOVE 0x40000
+
+#define ITEM_PREV -1
+#define ITEM_NEXT 1
+
+/* Internal MenuTrackMenu() flags */
+#define TPM_INTERNAL 0xF0000000
+#define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
+#define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
+
+/* top and bottom margins for popup menus */
+#define MENU_TOP_MARGIN 3
+#define MENU_BOTTOM_MARGIN 2
+
+#define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
+
+#define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
+
+#define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
+
+#define MENUITEMINFO_TYPE_MASK \
+ (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
+ MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
+ MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
+
+#define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
+
+#define STATE_MASK (~TYPE_MASK)
+
+#define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
+
+#define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
+
+/* macro to test that flags do not indicate bitmap, ownerdraw or separator */
+#define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
+#define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
+
+#define IS_SYSTEM_MENU(MenuInfo) \
+ (0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN))
+
+#define IS_SYSTEM_POPUP(MenuInfo) \
+ (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN))
+
+#define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
+
+/* Use global popup window because there's no way 2 menus can
+ * be tracked at the same time. */
+static HWND top_popup;
+static HMENU top_popup_hmenu;
+
+/* Flag set by EndMenu() to force an exit from menu tracking */
+static BOOL fEndMenu = FALSE;
+
+#define MENU_ITEM_HBMP_SPACE (5)
+#define MENU_BAR_ITEMS_SPACE (12)
+#define SEPARATOR_HEIGHT (5)
+#define MENU_TAB_SPACE (8)
+
+typedef struct
+{
+ UINT TrackFlags;
+ HMENU CurrentMenu; /* current submenu (can be equal to hTopMenu)*/
+ HMENU TopMenu; /* initial menu */
+ HWND OwnerWnd; /* where notifications are sent */
+ POINT Pt;
+} MTRACKER;
+
+
+/*********************************************************************
+ * PopupMenu class descriptor
+ */
+const struct builtin_class_descr POPUPMENU_builtin_class =
+{
+ WC_MENU, /* name */
+ CS_SAVEBITS | CS_DBLCLKS, /* style */
+ (WNDPROC) NULL, /* FIXME - procA */
+ (WNDPROC) PopupMenuWndProcW, /* FIXME - procW */
+ sizeof(MENUINFO *), /* extra */
+ (LPCWSTR) IDC_ARROW, /* cursor */
+ (HBRUSH)(COLOR_MENU + 1) /* brush */
+};
+
+#ifndef GET_WORD
+#define GET_WORD(ptr) (*(WORD *)(ptr))
+#endif
+#ifndef GET_DWORD
+#define GET_DWORD(ptr) (*(DWORD *)(ptr))
+#endif
+
+HFONT hMenuFont = NULL;
+HFONT hMenuFontBold = NULL;
+
+/* Dimension of the menu bitmaps */
+static HBITMAP BmpSysMenu = NULL;
+
+static SIZE MenuCharSize;
+
+
+/***********************************************************************
+ * MENU_GetMenu
+ *
+ * Validate the given menu handle and returns the menu structure pointer.
+ */
- return ValidateHandle(hMenu, TYPE_MENU);
++FORCEINLINE PMENU MENU_GetMenu(HMENU hMenu)
+{
- //pItem = &menu->rgItems[*nPos];
- i = 0;
- while(pItem) // Do this for now.
- {
- if (i < (INT)menu->cItems)
- {
- if ( *nPos == i ) return pItem;
- }
- pItem = pItem->Next ? DesktopPtrToUser(pItem->Next) : NULL;
- i++;
- }
++ return ValidateHandleNoErr(hMenu, TYPE_MENU);
++}
++
++/***********************************************************************
++ * get_win_sys_menu
++ *
++ * Get the system menu of a window
++ */
++static HMENU get_win_sys_menu( HWND hwnd )
++{
++ HMENU ret = 0;
++ WND *win = ValidateHwnd( hwnd );
++ if (win)
++ {
++ ret = win->SystemMenu;
++ }
++ return ret;
+}
+
+/***********************************************************************
+ * MENU_FindItem
+ *
+ * Find a menu item. Return a pointer on the item, and modifies *hmenu
+ * in case the item was in a sub-menu.
+ */
+ITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
+{
+ MENU *menu;
+ ITEM *fallback = NULL;
+ UINT fallback_pos = 0;
+ UINT i;
+ PITEM pItem;
+
+ if ((*hmenu == (HMENU)0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
+ if (wFlags & MF_BYPOSITION)
+ {
+ if (*nPos >= menu->cItems) return NULL;
+ pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
- for (i = 0; item ,i < menu->cItems; i++, item = item->Next ? DesktopPtrToUser(item->Next) : NULL)//, item++)
++ if (pItem) pItem = &pItem[*nPos];
++ return pItem;
+ }
+ else
+ {
+ PITEM item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
- UINT x = 0;
- UINT res = -1;
- UINT sres;
++ for (i = 0; item, i < menu->cItems; i++, item++)
+ {
+ if (item->spSubMenu)
+ {
+ PMENU pSubMenu = DesktopPtrToUser(item->spSubMenu);
+ HMENU hsubmenu = UserHMGetHandle(pSubMenu);
+ ITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
+ if (subitem)
+ {
+ *hmenu = hsubmenu;
+ return subitem;
+ }
+ else if (item->wID == *nPos)
+ {
+ /* fallback to this item if nothing else found */
+ fallback_pos = i;
+ fallback = item;
+ }
+ }
+ else if (item->wID == *nPos)
+ {
+ *nPos = i;
+ return item;
+ }
+ }
+ }
+
+ if (fallback)
+ *nPos = fallback_pos;
+
+ return fallback;
+}
+
+#define MAX_GOINTOSUBMENU (0x10)
+UINT FASTCALL
+IntGetMenuDefaultItem(PMENU Menu, BOOL fByPos, UINT gmdiFlags, DWORD *gismc)
+{
- while(Item)
- {
- if (Item->fState & MFS_DEFAULT)
- {
- if (!(gmdiFlags & GMDI_USEDISABLED) &&
- (Item->fState & MFS_DISABLED) )
- break;
++ UINT i = 0;
+ PITEM Item = Menu->rgItems ? DesktopPtrToUser(Menu->rgItems) : NULL;
+
- res = fByPos ? x : Item->wID;
++ /* empty menu */
++ if (!Item) return -1;
+
- if ((*gismc < MAX_GOINTOSUBMENU) &&
- (gmdiFlags & GMDI_GOINTOPOPUPS) &&
- Item->spSubMenu)
- {
- if (DesktopPtrToUser(Item->spSubMenu) == Menu)
- break;
++ while ( !( Item->fState & MFS_DEFAULT ) )
++ {
++ i++; Item++;
++ if (i >= Menu->cItems ) return -1;
++ }
+
- (*gismc)++;
- sres = IntGetMenuDefaultItem( DesktopPtrToUser(Item->spSubMenu), fByPos, gmdiFlags, gismc);
- (*gismc)--;
++ /* default: don't return disabled items */
++ if ( (!(GMDI_USEDISABLED & gmdiFlags)) && (Item->fState & MFS_DISABLED )) return -1;
+
- if(sres > (UINT)-1)
- res = sres;
- }
- break;
- }
- Item = Item->Next ? DesktopPtrToUser(Item->Next) : NULL;
- x++;
++ /* search rekursiv when needed */
++ if ( (Item->fType & MF_POPUP) && (gmdiFlags & GMDI_GOINTOPOPUPS) && Item->spSubMenu)
++ {
++ UINT ret;
++ (*gismc)++;
++ ret = IntGetMenuDefaultItem( DesktopPtrToUser(Item->spSubMenu), fByPos, gmdiFlags, gismc );
++ (*gismc)--;
++ if ( -1 != ret ) return ret;
+
- return res;
++ /* when item not found in submenu, return the popup item */
+ }
- //SetLastError(ERROR_INVALID_PARAMETER);
++ return ( fByPos ) ? i : Item->wID;
+}
+
+static BOOL GetMenuItemInfo_common ( HMENU hmenu,
+ UINT item,
+ BOOL bypos,
+ LPMENUITEMINFOW lpmii,
+ BOOL unicode)
+{
+ ITEM *pItem = MENU_FindItem (&hmenu, &item, bypos ? MF_BYPOSITION : 0);
+
+ //debug_print_menuitem("GetMenuItemInfo_common: ", pItem, "");
+
+ if (!pItem)
+ {
+ SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
- lpmii->fState = pItem->fState & MII_STATE_MASK; //MENUITEMINFO_STATE_MASK;
+ return FALSE;
+ }
+
+ if( lpmii->fMask & MIIM_TYPE)
+ {
+ if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP))
+ {
+ ERR("invalid combination of fMask bits used\n");
+ /* this does not happen on Win9x/ME */
+ SetLastError( ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ lpmii->fType = pItem->fType & MENUITEMINFO_TYPE_MASK;
+ if( pItem->hbmp) lpmii->fType |= MFT_BITMAP;
+ lpmii->hbmpItem = pItem->hbmp; /* not on Win9x/ME */
+ if( lpmii->fType & MFT_BITMAP)
+ {
+ lpmii->dwTypeData = (LPWSTR) pItem->hbmp;
+ lpmii->cch = 0;
+ }
+ else if( lpmii->fType & (MFT_OWNERDRAW | MFT_SEPARATOR))
+ {
+ /* this does not happen on Win9x/ME */
+ lpmii->dwTypeData = 0;
+ lpmii->cch = 0;
+ }
+ }
+
+ /* copy the text string */
+ if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)))
+ {
+ if( !pItem->Xlpstr )
+ { // Very strange this fixes a wine test with a crash.
+ if(lpmii->dwTypeData && lpmii->cch && !(GdiValidateHandle((HGDIOBJ)lpmii->dwTypeData)) )
+ {
+ lpmii->cch = 0;
+ if( unicode)
+ *((WCHAR *)lpmii->dwTypeData) = 0;
+ else
+ *((CHAR *)lpmii->dwTypeData) = 0;
+ }
+ }
+ else
+ {
+ int len;
+ LPWSTR text = DesktopPtrToUser(pItem->Xlpstr);
+ if (unicode)
+ {
+ len = strlenW(text);
+ if(lpmii->dwTypeData && lpmii->cch)
+ lstrcpynW(lpmii->dwTypeData, text, lpmii->cch);
+ }
+ else
+ {
+ len = WideCharToMultiByte( CP_ACP, 0, text, -1, NULL, 0, NULL, NULL ) - 1;
+ if(lpmii->dwTypeData && lpmii->cch)
+ if (!WideCharToMultiByte( CP_ACP, 0, text, -1,
+ (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
+ ((LPSTR)lpmii->dwTypeData)[lpmii->cch - 1] = 0;
+ }
+ /* if we've copied a substring we return its length */
+ if(lpmii->dwTypeData && lpmii->cch)
+ if (lpmii->cch <= len + 1)
+ lpmii->cch--;
+ else
+ lpmii->cch = len;
+ else
+ {
+ /* return length of string */
+ /* not on Win9x/ME if fType & MFT_BITMAP */
+ lpmii->cch = len;
+ }
+ }
+ }
+
+ if (lpmii->fMask & MIIM_FTYPE)
+ lpmii->fType = pItem->fType & MENUITEMINFO_TYPE_MASK;
+
+ if (lpmii->fMask & MIIM_BITMAP)
+ lpmii->hbmpItem = pItem->hbmp;
+
+ if (lpmii->fMask & MIIM_STATE)
- if (!(pMenu = ValidateHandle(Menu, TYPE_MENU))) return FALSE;
++ lpmii->fState = pItem->fState & MENUITEMINFO_STATE_MASK;
+
+ if (lpmii->fMask & MIIM_ID)
+ lpmii->wID = pItem->wID;
+
+ if (lpmii->fMask & MIIM_SUBMENU && pItem->spSubMenu )
+ {
+ PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
+ HMENU hSubMenu = UserHMGetHandle(pSubMenu);
+ lpmii->hSubMenu = hSubMenu;
+ }
+ else
+ {
+ /* hSubMenu is always cleared
+ * (not on Win9x/ME ) */
+ lpmii->hSubMenu = 0;
+ }
+
+ if (lpmii->fMask & MIIM_CHECKMARKS)
+ {
+ lpmii->hbmpChecked = pItem->hbmpChecked;
+ lpmii->hbmpUnchecked = pItem->hbmpUnchecked;
+ }
+ if (lpmii->fMask & MIIM_DATA)
+ lpmii->dwItemData = pItem->dwItemData;
+
+ return TRUE;
+}
+
+/***********************************************************************
+ * MenuGetRosMenuInfo
+ *
+ * Get full information about menu
+ */
+static BOOL FASTCALL
+MenuGetRosMenuInfo(PROSMENUINFO MenuInfo, HMENU Menu)
+{
+ PMENU pMenu;
- DWORD FASTCALL
- IntBuildMenuItemList(PMENU MenuObject, PVOID Buffer, ULONG nMax)
- {
- DWORD res = 0;
- ROSMENUITEMINFO mii;
- PVOID Buf;
- PITEM CurItem = MenuObject->rgItems ? DesktopPtrToUser(MenuObject->rgItems) : NULL;
- PWCHAR StrOut;
- WCHAR NulByte;
-
- if (0 != nMax)
- {
- if (nMax < MenuObject->cItems * sizeof(ROSMENUITEMINFO))
- {
- return 0;
- }
- StrOut = (PWCHAR)((char *) Buffer + MenuObject->cItems * sizeof(ROSMENUITEMINFO));
- nMax -= MenuObject->cItems * sizeof(ROSMENUITEMINFO);
- Buf = Buffer;
- mii.cbSize = sizeof(ROSMENUITEMINFO);
- mii.fMask = 0;
- NulByte = L'\0';
-
- while (NULL != CurItem)
- {
- mii.cch = CurItem->lpstr.Length / sizeof(WCHAR);
- mii.dwItemData = CurItem->dwItemData;
- if (0 != CurItem->lpstr.Length)
- {
- mii.dwTypeData = StrOut;
- }
- else
- {
- mii.dwTypeData = NULL;
- }
- mii.fState = CurItem->fState;
- mii.fType = CurItem->fType;
- mii.wID = CurItem->wID;
- mii.hbmpChecked = CurItem->hbmpChecked;
- mii.hbmpItem = CurItem->hbmp;
- mii.hbmpUnchecked = CurItem->hbmpUnchecked;
- if (CurItem->spSubMenu)
- {
- PMENU pSubMenu = DesktopPtrToUser(CurItem->spSubMenu);
- HMENU hSubMenu = UserHMGetHandle(pSubMenu);
- mii.hSubMenu = hSubMenu;
- }
- else
- mii.hSubMenu = NULL;
- mii.Rect.left = CurItem->xItem;
- mii.Rect.top = CurItem->yItem;
- mii.Rect.right = CurItem->cxItem; // Do this for now......
- mii.Rect.bottom = CurItem->cyItem;
- mii.dxTab = CurItem->dxTab;
- mii.lpstr = CurItem->lpstr.Buffer; // Can be read from user side!
- //mii.maxBmpSize.cx = CurItem->cxBmp;
- //mii.maxBmpSize.cy = CurItem->cyBmp;
-
- RtlCopyMemory(Buf, &mii, sizeof(ROSMENUITEMINFO));
- Buf = (PVOID)((ULONG_PTR)Buf + sizeof(ROSMENUITEMINFO));
-
- if (0 != CurItem->lpstr.Length && (nMax >= CurItem->lpstr.Length + sizeof(WCHAR)))
- {
- LPWSTR lpstr = CurItem->lpstr.Buffer ? DesktopPtrToUser(CurItem->lpstr.Buffer) : NULL;
- if (lpstr)
- {
- /* Copy string */
- RtlCopyMemory(StrOut, lpstr, CurItem->lpstr.Length);
-
- StrOut += CurItem->lpstr.Length / sizeof(WCHAR);
- RtlCopyMemory(StrOut, &NulByte, sizeof(WCHAR));
- StrOut++;
- nMax -= CurItem->lpstr.Length + sizeof(WCHAR);
- }
- }
- else if (0 != CurItem->lpstr.Length)
- {
- break;
- }
-
- CurItem = CurItem->Next ? DesktopPtrToUser(CurItem->Next) : NULL;
- res++;
- }
- }
- else
- {
- while (NULL != CurItem)
- {
- res += sizeof(ROSMENUITEMINFO) + CurItem->lpstr.Length + sizeof(WCHAR);
- CurItem = CurItem->Next ? DesktopPtrToUser(CurItem->Next) : NULL;
- }
- }
- return res;
- }
-
- /***********************************************************************
- * MenuGetAllRosMenuItemInfo
- *
- * Get full information about all menu items
- */
- static INT FASTCALL
- MenuGetAllRosMenuItemInfo(HMENU Menu, PROSMENUITEMINFO *ItemInfo)
- {
- DWORD BufSize;
- PMENU pMenu;
-
- if (!(pMenu = ValidateHandle(Menu, TYPE_MENU))) return -1;
-
- BufSize = IntBuildMenuItemList(pMenu, (PVOID)1, 0);
- if (BufSize == (DWORD) -1 || BufSize == 0)
- {
- return -1;
- }
- *ItemInfo = HeapAlloc(GetProcessHeap(), 0, BufSize);
- if (NULL == *ItemInfo)
- {
- return -1;
- }
-
- return IntBuildMenuItemList(pMenu, (PVOID)*ItemInfo, BufSize);
- }
-
- /***********************************************************************
- * MenuCleanupAllRosMenuItemInfo
- *
- * Cleanup after use of MenuGetAllRosMenuItemInfo
- */
- static VOID FASTCALL
- MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
- {
- HeapFree(GetProcessHeap(), 0, ItemInfo);
- }
-
++ if (!(pMenu = ValidateHandleNoErr(Menu, TYPE_MENU))) return FALSE;
+
+ MenuInfo->hbrBack = pMenu->hbrBack;
+ MenuInfo->dwContextHelpID = pMenu->dwContextHelpId;
+ MenuInfo->cyMax = pMenu->cyMax;
+ MenuInfo->dwMenuData = pMenu->dwMenuData;
+ MenuInfo->dwStyle = pMenu->fFlags & MNS_STYLE_MASK;
+
+ MenuInfo->cItems = pMenu->cItems;
+
+ MenuInfo->iItem = pMenu->iItem;
+ MenuInfo->cxMenu = pMenu->cxMenu;
+ MenuInfo->cyMenu = pMenu->cyMenu;
+ MenuInfo->spwndNotify = pMenu->spwndNotify;
+ MenuInfo->cxTextAlign = pMenu->cxTextAlign;
+ MenuInfo->iTop = pMenu->iMaxTop;
+ MenuInfo->iMaxTop = pMenu->iMaxTop;
+ MenuInfo->dwArrowsOn = pMenu->dwArrowsOn;
+
+ MenuInfo->fFlags = pMenu->fFlags;
+ MenuInfo->Self = pMenu->head.h;
+ MenuInfo->TimeToHide = pMenu->TimeToHide;
+ MenuInfo->Wnd = pMenu->hWnd;
+ return TRUE;
+}
+
+/***********************************************************************
+ * MenuSetRosMenuInfo
+ *
+ * Set full information about menu
+ */
+static BOOL FASTCALL
+MenuSetRosMenuInfo(PROSMENUINFO MenuInfo)
+{
+ MenuInfo->cbSize = sizeof(ROSMENUINFO);
+ MenuInfo->fMask = MIM_BACKGROUND | MIM_HELPID | MIM_MAXHEIGHT | MIM_MENUDATA | MIM_STYLE;
+
+ return NtUserThunkedMenuInfo(MenuInfo->Self, (LPCMENUINFO)MenuInfo);
+}
+
+/***********************************************************************
+ * MenuInitRosMenuItemInfo
+ *
+ * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
+ */
+static VOID FASTCALL
+MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
+{
+ ZeroMemory(ItemInfo, sizeof(ROSMENUITEMINFO));
+ ItemInfo->cbSize = sizeof(ROSMENUITEMINFO);
+}
+
+/***********************************************************************
+ * MenuGetRosMenuItemInfo
+ *
+ * Get full information about a menu item
+ */
+static BOOL FASTCALL
+MenuGetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo)
+{
+ PITEM pItem;
+ UINT Save_Mask = ItemInfo->fMask; /* Save the org mask bits. */
+
+ if (ItemInfo->dwTypeData != NULL)
+ {
+ HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData);
+ }
+
+ ItemInfo->dwTypeData = NULL;
+
+ if (!(pItem = MENU_FindItem(&Menu, &Index, MF_BYPOSITION)))
+ {
+ ItemInfo->fType = 0;
+ return FALSE;
+ }
+
+ ItemInfo->fType = pItem->fType;
+ ItemInfo->hbmpItem = pItem->hbmp;
+ ItemInfo->hbmpChecked = pItem->hbmpChecked;
+ ItemInfo->hbmpUnchecked = pItem->hbmpUnchecked;
+ ItemInfo->dwItemData = pItem->dwItemData;
+ ItemInfo->wID = pItem->wID;
+ ItemInfo->fState = pItem->fState;
+
+ if (pItem->spSubMenu)
+ {
+ PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
+ HMENU hSubMenu = UserHMGetHandle(pSubMenu);
+ ItemInfo->hSubMenu = hSubMenu;
+ }
+ else
+ ItemInfo->hSubMenu = NULL;
+
+ if (MENU_ITEM_TYPE(ItemInfo->fType) == MF_STRING)
+ {
+ LPWSTR lpstr = pItem->lpstr.Buffer ? DesktopPtrToUser(pItem->lpstr.Buffer) : NULL;
+ if (lpstr)
+ {
+ ItemInfo->cch = pItem->lpstr.Length / sizeof(WCHAR);
+ ItemInfo->cch++;
+ ItemInfo->dwTypeData = HeapAlloc(GetProcessHeap(), 0, ItemInfo->cch * sizeof(WCHAR));
+ if (ItemInfo->dwTypeData == NULL)
+ {
+ return FALSE;
+ }
+ RtlCopyMemory(ItemInfo->dwTypeData, lpstr, min(ItemInfo->cch * sizeof(WCHAR), pItem->lpstr.MaximumLength));
+ }
+ else
+ {
+ ItemInfo->cch = 0;
+ }
+ }
+
+ ItemInfo->Rect.left = pItem->xItem;
+ ItemInfo->Rect.top = pItem->yItem;
+ ItemInfo->Rect.right = pItem->cxItem; // Do this for now......
+ ItemInfo->Rect.bottom = pItem->cyItem;
+ ItemInfo->dxTab = pItem->dxTab;
+ ItemInfo->lpstr = pItem->lpstr.Buffer;
+ ItemInfo->maxBmpSize.cx = pItem->cxBmp;
+ ItemInfo->maxBmpSize.cy = pItem->cyBmp;
+
+ ItemInfo->fMask = Save_Mask;
+ return TRUE;
+}
+
+/***********************************************************************
+ * MenuSetRosMenuItemInfo
+ *
+ * Set selected information about a menu item, need to set the mask bits.
+ */
+static BOOL FASTCALL
+MenuSetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo)
+{
+ BOOL Ret;
+
+ if (MENU_ITEM_TYPE(ItemInfo->fType) == MF_STRING &&
+ ItemInfo->dwTypeData != NULL)
+ {
+ ItemInfo->cch = strlenW(ItemInfo->dwTypeData);
+ }
++ if (ItemInfo->hSubMenu)
++ {
++ if (!IsMenu(ItemInfo->hSubMenu)) ItemInfo->hSubMenu = NULL;
++ }
+ Ret = NtUserThunkedMenuItemInfo(Menu, Index, TRUE, FALSE, (LPMENUITEMINFOW)ItemInfo, NULL);
+ return Ret;
+}
+
+/***********************************************************************
+ * MenuCleanupRosMenuItemInfo
+ *
+ * Cleanup after use of MenuGet/SetRosMenuItemInfo
+ */
+static VOID FASTCALL
+MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
+{
+ if (ItemInfo->dwTypeData != NULL)
+ {
+ HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData);
+ ItemInfo->dwTypeData = NULL;
+ }
+}
+
- static UINT MenuGetStartOfNextColumn(
- PROSMENUINFO MenuInfo)
+/***********************************************************************
+ * MenuInitSysMenuPopup
+ *
+ * Grey the appropriate items in System menu.
+ */
+void FASTCALL MenuInitSysMenuPopup(HMENU hmenu, DWORD style, DWORD clsStyle, LONG HitTest )
+{
+ BOOL gray;
+ UINT DefItem;
+ #if 0
+ MENUITEMINFOW mii;
+ #endif
+
+ gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
+ EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
+ gray = ((style & WS_MAXIMIZE) != 0);
+ EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
+ gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
+ EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
+ gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
+ EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
+ gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
+ EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
+ gray = (clsStyle & CS_NOCLOSE) != 0;
+
+ /* The menu item must keep its state if it's disabled */
+ if(gray)
+ EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
+
+ /* Set default menu item */
+ if(style & WS_MINIMIZE) DefItem = SC_RESTORE;
+ else if(HitTest == HTCAPTION) DefItem = ((style & (WS_MAXIMIZE | WS_MINIMIZE)) ? SC_RESTORE : SC_MAXIMIZE);
+ else DefItem = SC_CLOSE;
+#if 0
+ mii.cbSize = sizeof(MENUITEMINFOW);
+ mii.fMask |= MIIM_STATE;
+ if((DefItem != SC_CLOSE) && GetMenuItemInfoW(hmenu, DefItem, FALSE, &mii) &&
+ (mii.fState & (MFS_GRAYED | MFS_DISABLED))) DefItem = SC_CLOSE;
+#endif
+ SetMenuDefaultItem(hmenu, DefItem, MF_BYCOMMAND);
+}
+
+/******************************************************************************
+ *
+ * UINT MenuGetStartOfNextColumn(
+ * PROSMENUINFO MenuInfo)
+ *
+ *****************************************************************************/
- PROSMENUITEMINFO MenuItems;
++
++static UINT MENU_GetStartOfNextColumn(
++ HMENU hMenu )
+{
- i = MenuInfo->iItem;
- if ( i == NO_SELECTED_ITEM )
- return i;
++ MENU *menu = MENU_GetMenu(hMenu);
++ PITEM pItem;
+ UINT i;
+
- if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &MenuItems) <= 0)
- return NO_SELECTED_ITEM;
++ if(!menu)
++ return NO_SELECTED_ITEM;
+
- for (i++ ; i < MenuInfo->cItems; i++)
- if (0 != (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)))
- return i;
++ i = menu->iItem + 1;
++ if( i == NO_SELECTED_ITEM )
++ return i;
+
-
- static UINT FASTCALL MenuGetStartOfPrevColumn(
- PROSMENUINFO MenuInfo)
++ pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
++ if (!pItem) return NO_SELECTED_ITEM;
++ for( ; i < menu->cItems; ++i ) {
++ if (pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))
++ return i;
++ }
+
+ return NO_SELECTED_ITEM;
+}
+
+/******************************************************************************
+ *
+ * UINT MenuGetStartOfPrevColumn(
+ * PROSMENUINFO MenuInfo)
+ *
+ *****************************************************************************/
- PROSMENUITEMINFO MenuItems;
- UINT i;
++static UINT MENU_GetStartOfPrevColumn(
++ HMENU hMenu )
+{
- if (!MenuInfo->iItem || MenuInfo->iItem == NO_SELECTED_ITEM)
- return NO_SELECTED_ITEM;
++ MENU *menu = MENU_GetMenu(hMenu);
++ UINT i;
++ PITEM pItem;
+
- if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &MenuItems) <= 0)
- return NO_SELECTED_ITEM;
++ if( !menu )
++ return NO_SELECTED_ITEM;
+
- for (i = MenuInfo->iItem;
- 0 != i && 0 == (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK));
- --i)
- {
- ; /* empty */
- }
++ if( menu->iItem == 0 || menu->iItem == NO_SELECTED_ITEM )
++ return NO_SELECTED_ITEM;
++
++ pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
++ if (!pItem) return NO_SELECTED_ITEM;
+
+ /* Find the start of the column */
- if (i == 0)
- {
- MenuCleanupAllRosMenuItemInfo(MenuItems);
- return NO_SELECTED_ITEM;
- }
+
- for (--i; 0 != i; --i)
- if (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))
- break;
++ for(i = menu->iItem; i != 0 &&
++ !(pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK));
++ --i); /* empty */
+
- MenuCleanupAllRosMenuItemInfo(MenuItems);
++ if(i == 0)
++ return NO_SELECTED_ITEM;
++
++ for(--i; i != 0; --i) {
++ if (pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))
++ break;
++ }
+
- for (i = 0; i < menu->cItems; i++, item = item->Next ? DesktopPtrToUser(item->Next) : NULL)//item++)
+ TRACE("ret %d.\n", i );
+
+ return i;
+}
+
+/***********************************************************************
+ * MenuLoadBitmaps
+ *
+ * Load the arrow bitmap. We can't do this from MenuInit since user32
+ * can also be used (and thus initialized) from text-mode.
+ */
+static void FASTCALL
+MenuLoadBitmaps(VOID)
+{
+ /* Load system buttons bitmaps */
+ if (NULL == BmpSysMenu)
+ {
+ BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
+ }
+}
+/////////// Make gpsi OBMI via callback //////////////
+/***********************************************************************
+ * get_arrow_bitmap
+ */
+HBITMAP get_arrow_bitmap(void)
+{
+ static HBITMAP arrow_bitmap;
+
+ if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW));
+ return arrow_bitmap;
+}
+
+/***********************************************************************
+ * get_down_arrow_bitmap DFCS_MENUARROWDOWN
+ */
+HBITMAP get_down_arrow_bitmap(void)
+{
+ static HBITMAP arrow_bitmap;
+
+ if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROW));
+ return arrow_bitmap;
+}
+
+/***********************************************************************
+ * get_down_arrow_inactive_bitmap DFCS_MENUARROWDOWN | DFCS_INACTIVE
+ */
+HBITMAP get_down_arrow_inactive_bitmap(void)
+{
+ static HBITMAP arrow_bitmap;
+
+ if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROWI));
+ return arrow_bitmap;
+}
+
+/***********************************************************************
+ * get_up_arrow_bitmap DFCS_MENUARROWUP
+ */
+HBITMAP get_up_arrow_bitmap(void)
+{
+ static HBITMAP arrow_bitmap;
+
+ if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROW));
+ return arrow_bitmap;
+}
+
+/***********************************************************************
+ * get_up_arrow_inactive_bitmap DFCS_MENUARROWUP | DFCS_INACTIVE
+ */
+static HBITMAP get_up_arrow_inactive_bitmap(void)
+{
+ static HBITMAP arrow_bitmap;
+
+ if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROWI));
+ return arrow_bitmap;
+}
+////////////////
+/***********************************************************************
+ * MenuFindSubMenu
+ *
+ * Find a Sub menu. Return the position of the submenu, and modifies
+ * *hmenu in case it is found in another sub-menu.
+ * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
+ */
+static UINT FASTCALL MenuFindSubMenu(HMENU *hmenu, HMENU hSubTarget )
+{
+ PMENU menu, pSubMenu;
+ HMENU hSubMenu;
+ UINT i;
+ PITEM item;
+
+ if (((*hmenu)==(HMENU)0xffff) ||(!(menu = MENU_GetMenu(*hmenu))))
+ return NO_SELECTED_ITEM;
+
+ item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
- static UINT FASTCALL MenuFindItemByKey(HWND WndOwner, PROSMENUINFO MenuInfo,
++ for (i = 0; i < menu->cItems; i++, item++)
+ {
+ if (!item->spSubMenu)
+ continue;
+ else
+ {
+ pSubMenu = DesktopPtrToUser(item->spSubMenu);
+ hSubMenu = UserHMGetHandle(pSubMenu);
+ if (hSubMenu == hSubTarget)
+ {
+ return i;
+ }
+ else
+ {
+ HMENU hsubmenu = hSubMenu;
+ UINT pos = MenuFindSubMenu( &hsubmenu, hSubTarget );
+ if (pos != NO_SELECTED_ITEM)
+ {
+ *hmenu = hsubmenu;
+ return pos;
+ }
+ }
+ }
+ }
+ return NO_SELECTED_ITEM;
+}
+
+/***********************************************************************
+ * MENU_AdjustMenuItemRect
+ *
+ * Adjust menu item rectangle according to scrolling state.
+ */
+static void
+MENU_AdjustMenuItemRect(PROSMENUINFO menu, LPRECT rect)
+{
+ if (menu->dwArrowsOn)
+ {
+ UINT arrow_bitmap_height;
+ BITMAP bmp;
+
+ GetObjectW(get_up_arrow_bitmap(), sizeof(bmp), &bmp);
+ arrow_bitmap_height = bmp.bmHeight;
+ rect->top += arrow_bitmap_height - menu->iTop;
+ rect->bottom += arrow_bitmap_height - menu->iTop;
+ }
+}
+
+/***********************************************************************
+ * MenuDrawPopupGlyph
+ *
+ * Draws popup magic glyphs (can be found in system menu).
+ */
+static void FASTCALL
+MenuDrawPopupGlyph(HDC dc, LPRECT r, INT_PTR popupMagic, BOOL inactive, BOOL hilite)
+{
+ LOGFONTW lf;
+ HFONT hFont, hOldFont;
+ COLORREF clrsave;
+ INT bkmode;
+ TCHAR symbol;
+ switch (popupMagic)
+ {
+ case (INT_PTR) HBMMENU_POPUP_RESTORE:
+ symbol = '2';
+ break;
+ case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
+ symbol = '0';
+ break;
+ case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
+ symbol = '1';
+ break;
+ case (INT_PTR) HBMMENU_POPUP_CLOSE:
+ symbol = 'r';
+ break;
+ default:
+ ERR("Invalid popup magic bitmap %d\n", (int)popupMagic);
+ return;
+ }
+ ZeroMemory(&lf, sizeof(LOGFONTW));
+ InflateRect(r, -2, -2);
+ lf.lfHeight = r->bottom - r->top;
+ lf.lfWidth = 0;
+ lf.lfWeight = FW_NORMAL;
+ lf.lfCharSet = DEFAULT_CHARSET;
+ lstrcpy(lf.lfFaceName, TEXT("Marlett"));
+ hFont = CreateFontIndirect(&lf);
+ /* save font and text color */
+ hOldFont = SelectObject(dc, hFont);
+ clrsave = GetTextColor(dc);
+ bkmode = GetBkMode(dc);
+ /* set color and drawing mode */
+ SetBkMode(dc, TRANSPARENT);
+ if (inactive)
+ {
+ /* draw shadow */
+ if (!hilite)
+ {
+ SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ TextOut(dc, r->left + 1, r->top + 1, &symbol, 1);
+ }
+ }
+ SetTextColor(dc, GetSysColor(inactive ? COLOR_GRAYTEXT : (hilite ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT)));
+ /* draw selected symbol */
+ TextOut(dc, r->left, r->top, &symbol, 1);
+ /* restore previous settings */
+ SetTextColor(dc, clrsave);
+ SelectObject(dc, hOldFont);
+ SetBkMode(dc, bkmode);
+ DeleteObject(hFont);
+}
+
+/***********************************************************************
+ * MenuFindItemByKey
+ *
+ * Find the menu item selected by a key press.
+ * Return item id, -1 if none, -2 if we should close the menu.
+ */
- ROSMENUINFO SysMenuInfo;
- PROSMENUITEMINFO Items, ItemInfo;
++static UINT FASTCALL MENU_FindItemByKey(HWND WndOwner, HMENU hmenu,
+ WCHAR Key, BOOL ForceMenuChar)
+{
- UINT i;
+ LRESULT MenuChar;
- TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key, Key, MenuInfo);
+ WORD Flags = 0;
+
- if (NULL == MenuInfo || ! IsMenu(MenuInfo->Self))
- {
- if (MenuGetRosMenuInfo(&SysMenuInfo, GetSystemMenu(WndOwner, FALSE)))
- {
- MenuInfo = &SysMenuInfo;
- }
- else
- {
- MenuInfo = NULL;
- }
- }
++ TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key, Key, hmenu );
+
- if (NULL != MenuInfo)
- {
- if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &Items) <= 0)
- {
- return -1;
- }
- if ( !ForceMenuChar )
- {
- ItemInfo = Items;
- for (i = 0; i < MenuInfo->cItems; i++, ItemInfo++)
- {
- if ((ItemInfo->lpstr) && NULL != ItemInfo->dwTypeData)
- {
- WCHAR *p = (WCHAR *) ItemInfo->dwTypeData - 2;
- do
- {
- p = strchrW (p + 2, '&');
- }
- while (p != NULL && p [1] == '&');
- if (p && (toupperW(p[1]) == toupperW(Key))) return i;
- }
- }
- }
++ if (!IsMenu( hmenu )) hmenu = GetSubMenu( get_win_sys_menu(WndOwner), 0);
++ if (hmenu)
++ {
++ MENU *menu = MENU_GetMenu( hmenu );
++ ITEM *item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
+
- Flags |= MenuInfo->fFlags & MNF_POPUP ? MF_POPUP : 0;
- Flags |= MenuInfo->fFlags & MNF_SYSDESKMN ? MF_SYSMENU : 0;
++ if( !ForceMenuChar )
++ {
++ UINT i;
++ BOOL cjk = GetSystemMetrics( SM_DBCSENABLED );
++
++ for (i = 0; i < menu->cItems; i++, item++)
++ {
++ LPWSTR text = item->Xlpstr ? DesktopPtrToUser(item->Xlpstr) : NULL;
++ if( text)
++ {
++ const WCHAR *p = text - 2;
++ do
++ {
++ const WCHAR *q = p + 2;
++ p = strchrW (q, '&');
++ if (!p && cjk) p = strchrW (q, '\036'); /* Japanese Win16 */
++ }
++ while (p != NULL && p [1] == '&');
++ if (p && (toupperW(p[1]) == toupperW(Key))) return i;
++ }
++ }
++ }
+
- MAKEWPARAM(Key, Flags), (LPARAM) MenuInfo->Self);
++ Flags |= menu->fFlags & MNF_POPUP ? MF_POPUP : 0;
++ Flags |= menu->fFlags & MNF_SYSDESKMN ? MF_SYSMENU : 0;
+
+ MenuChar = SendMessageW(WndOwner, WM_MENUCHAR,
- TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", lprect->left, lprect->top, lprect->right, lprect->bottom);
++ MAKEWPARAM(Key, Flags), (LPARAM) hmenu);
+ if (HIWORD(MenuChar) == MNC_EXECUTE) return LOWORD(MenuChar);
+ if (HIWORD(MenuChar) == MNC_CLOSE) return (UINT)(-2);
+ }
+ return (UINT)(-1);
+}
+
+/***********************************************************************
+ * MenuGetBitmapItemSize
+ *
+ * Get the size of a bitmap item.
+ */
+static void FASTCALL MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem, SIZE *size, HWND WndOwner)
+{
+ BITMAP bm;
+ HBITMAP bmp = lpitem->hbmpItem;
+
+ size->cx = size->cy = 0;
+
+ /* check if there is a magic menu item associated with this item */
+ if (IS_MAGIC_BITMAP(bmp))
+ {
+ switch((INT_PTR) bmp)
+ {
+ case (INT_PTR)HBMMENU_CALLBACK:
+ {
+ MEASUREITEMSTRUCT measItem;
+ measItem.CtlType = ODT_MENU;
+ measItem.CtlID = 0;
+ measItem.itemID = lpitem->wID;
+ measItem.itemWidth = lpitem->Rect.right - lpitem->Rect.left;
+ measItem.itemHeight = lpitem->Rect.bottom - lpitem->Rect.top;
+ measItem.itemData = lpitem->dwItemData;
+ SendMessageW( WndOwner, WM_MEASUREITEM, lpitem->wID, (LPARAM)&measItem);
+ size->cx = measItem.itemWidth;
+ size->cy = measItem.itemHeight;
+ return;
+ }
+ break;
+
+ case (INT_PTR) HBMMENU_SYSTEM:
+ if (0 != lpitem->dwItemData)
+ {
+ bmp = (HBITMAP) lpitem->dwItemData;
+ break;
+ }
+ /* fall through */
+ case (INT_PTR) HBMMENU_MBAR_RESTORE:
+ case (INT_PTR) HBMMENU_MBAR_MINIMIZE:
+ case (INT_PTR) HBMMENU_MBAR_CLOSE:
+ case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D:
+ case (INT_PTR) HBMMENU_MBAR_CLOSE_D:
+ case (INT_PTR) HBMMENU_POPUP_CLOSE:
+ case (INT_PTR) HBMMENU_POPUP_RESTORE:
+ case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
+ case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
+ /* FIXME: Why we need to subtract these magic values? */
+ /* to make them smaller than the menu bar? */
+ size->cx = GetSystemMetrics(SM_CXSIZE) - 2;
+ size->cy = GetSystemMetrics(SM_CYSIZE) - 4;
+ return;
+ }
+ }
+
+ if (GetObjectW(bmp, sizeof(BITMAP), &bm))
+ {
+ size->cx = bm.bmWidth;
+ size->cy = bm.bmHeight;
+ }
+}
+
+/***********************************************************************
+ * MenuDrawBitmapItem
+ *
+ * Draw a bitmap item.
+ */
+static void FASTCALL MenuDrawBitmapItem(HDC hdc, PROSMENUITEMINFO lpitem, const RECT *rect,
+ PROSMENUINFO MenuInfo, HWND WndOwner, UINT odaction, BOOL MenuBar)
+{
+ BITMAP bm;
+ DWORD rop;
+ HDC hdcMem;
+ HBITMAP bmp;
+ int w = rect->right - rect->left;
+ int h = rect->bottom - rect->top;
+ int bmp_xoffset = 0;
+ int left, top;
+ HBITMAP hbmToDraw = lpitem->hbmpItem;
+ bmp = hbmToDraw;
+
+ /* Check if there is a magic menu item associated with this item */
+ if (IS_MAGIC_BITMAP(hbmToDraw))
+ {
+ UINT flags = 0;
+ RECT r;
+
+ r = *rect;
+ switch ((INT_PTR)hbmToDraw)
+ {
+ case (INT_PTR)HBMMENU_SYSTEM:
+ if (lpitem->dwTypeData)
+ {
+ bmp = (HBITMAP)lpitem->dwTypeData;
+ if (!GetObjectW( bmp, sizeof(bm), &bm )) return;
+ }
+ else
+ {
+ if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
+ bmp = BmpSysMenu;
+ if (! GetObjectW(bmp, sizeof(bm), &bm)) return;
+ /* only use right half of the bitmap */
+ bmp_xoffset = bm.bmWidth / 2;
+ bm.bmWidth -= bmp_xoffset;
+ }
+ goto got_bitmap;
+ case (INT_PTR)HBMMENU_MBAR_RESTORE:
+ flags = DFCS_CAPTIONRESTORE;
+ break;
+ case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
+ r.right += 1;
+ flags = DFCS_CAPTIONMIN;
+ break;
+ case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
+ r.right += 1;
+ flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
+ break;
+ case (INT_PTR)HBMMENU_MBAR_CLOSE:
+ flags = DFCS_CAPTIONCLOSE;
+ break;
+ case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
+ flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
+ break;
+ case (INT_PTR)HBMMENU_CALLBACK:
+ {
+ DRAWITEMSTRUCT drawItem;
+ POINT origorg;
+ drawItem.CtlType = ODT_MENU;
+ drawItem.CtlID = 0;
+ drawItem.itemID = lpitem->wID;
+ drawItem.itemAction = odaction;
+ drawItem.itemState = (lpitem->fState & MF_CHECKED)?ODS_CHECKED:0;
+ drawItem.itemState |= (lpitem->fState & MF_DEFAULT)?ODS_DEFAULT:0;
+ drawItem.itemState |= (lpitem->fState & MF_DISABLED)?ODS_DISABLED:0;
+ drawItem.itemState |= (lpitem->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0;
+ drawItem.itemState |= (lpitem->fState & MF_HILITE)?ODS_SELECTED:0;
+ //drawItem.itemState |= (!(MenuInfo->fFlags & MNF_UNDERLINE))?ODS_NOACCEL:0;
+ //drawItem.itemState |= (MenuInfo->fFlags & MNF_INACTIVE)?ODS_INACTIVE:0;
+ drawItem.hwndItem = (HWND)MenuInfo->Self;
+ drawItem.hDC = hdc;
+ drawItem.rcItem = *rect;
+ drawItem.itemData = lpitem->dwItemData;
+ /* some applications make this assumption on the DC's origin */
+ SetViewportOrgEx( hdc, lpitem->Rect.left, lpitem->Rect.top, &origorg);
+ OffsetRect( &drawItem.rcItem, - lpitem->Rect.left, - lpitem->Rect.top);
+ SendMessageW( WndOwner, WM_DRAWITEM, 0, (LPARAM)&drawItem);
+ SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
+ return;
+ }
+ break;
+
+ case (INT_PTR) HBMMENU_POPUP_CLOSE:
+ case (INT_PTR) HBMMENU_POPUP_RESTORE:
+ case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
+ case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
+ MenuDrawPopupGlyph(hdc, &r, (INT_PTR)hbmToDraw, lpitem->fState & MF_GRAYED, lpitem->fState & MF_HILITE);
+ return;
+ }
+ InflateRect(&r, -1, -1);
+ if (0 != (lpitem->fState & MF_HILITE))
+ {
+ flags |= DFCS_PUSHED;
+ }
+ DrawFrameControl(hdc, &r, DFC_CAPTION, flags);
+ return;
+ }
+
+ if (!bmp || !GetObjectW( bmp, sizeof(bm), &bm )) return;
+
+ got_bitmap:
+ hdcMem = CreateCompatibleDC( hdc );
+ SelectObject( hdcMem, bmp );
+
+ /* handle fontsize > bitmap_height */
+ top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top;
+ left=rect->left;
+ rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmToDraw)) ? NOTSRCCOPY : SRCCOPY;
+ if ((lpitem->fState & MF_HILITE) && lpitem->hbmpItem)
+ SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
+ BitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop );
+ DeleteDC( hdcMem );
+}
+
+/***********************************************************************
+ * MenuCalcItemSize
+ *
+ * Calculate the size of the menu item and store it in lpitem->rect.
+ */
+static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMENUINFO MenuInfo, HWND hwndOwner,
+ INT orgX, INT orgY, BOOL menuBar, BOOL textandbmp)
+{
+ WCHAR *p;
+ UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
+ UINT arrow_bitmap_width;
+ BITMAP bm;
+ INT itemheight = 0;
+
+ TRACE("dc=%x owner=%x (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
+
+ GetObjectW( get_arrow_bitmap(), sizeof(bm), &bm );
+ arrow_bitmap_width = bm.bmWidth;
+
+ MenuCharSize.cx = GdiGetCharDimensions( hdc, NULL, &MenuCharSize.cy );
+
+ SetRect( &lpitem->Rect, orgX, orgY, orgX, orgY );
+
+ if (lpitem->fType & MF_OWNERDRAW)
+ {
+ MEASUREITEMSTRUCT mis;
+ mis.CtlType = ODT_MENU;
+ mis.CtlID = 0;
+ mis.itemID = lpitem->wID;
+ mis.itemData = lpitem->dwItemData;
+ mis.itemHeight = HIWORD( GetDialogBaseUnits());
+ mis.itemWidth = 0;
+ SendMessageW( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
+ /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
+ * width of a menufont character to the width of an owner-drawn menu.
+ */
+ lpitem->Rect.right += mis.itemWidth + 2 * MenuCharSize.cx;
+ if (menuBar) {
+ /* under at least win95 you seem to be given a standard
+ height for the menu and the height value is ignored */
+ lpitem->Rect.bottom += GetSystemMetrics(SM_CYMENUSIZE);
+ } else
+ lpitem->Rect.bottom += mis.itemHeight;
+ // Or this,
+ //Item->cxBmp = mis.itemWidth;
+ //Item->cyBmp = mis.itemHeight;
+ TRACE("id=%04lx size=%dx%d\n",
+ lpitem->wID, lpitem->Rect.right-lpitem->Rect.left,
+ lpitem->Rect.bottom-lpitem->Rect.top);
+ return;
+ }
+
+ if (lpitem->fType & MF_SEPARATOR)
+ {
+ lpitem->Rect.bottom += GetSystemMetrics( SM_CYMENUSIZE)/2;//SEPARATOR_HEIGHT;
+ if( !menuBar)
+ lpitem->Rect.right += arrow_bitmap_width/*check_bitmap_width*/ + MenuCharSize.cx;
+ return;
+ }
+
+ lpitem->dxTab = 0;
+
+ if (lpitem->hbmpItem)
+ {
+ SIZE size;
+
+ if (!menuBar) {
+ MenuGetBitmapItemSize(lpitem, &size, hwndOwner );
+ /* Keep the size of the bitmap in callback mode to be able
+ * to draw it correctly */
+ lpitem->maxBmpSize = size;
+ MenuInfo->cxTextAlign = max(MenuInfo->cxTextAlign, size.cx);
+ MenuSetRosMenuInfo(MenuInfo);
+ lpitem->Rect.right += size.cx + 2;
+ itemheight = size.cy + 2;
+
+ if( !(MenuInfo->dwStyle & MNS_NOCHECK))
+ lpitem->Rect.right += 2 * check_bitmap_width;
+ lpitem->Rect.right += 4 + MenuCharSize.cx;
+ lpitem->dxTab = lpitem->Rect.right;
+ lpitem->Rect.right += arrow_bitmap_width;//check_bitmap_width;
+ } else /* hbmpItem & MenuBar */ {
+ MenuGetBitmapItemSize(lpitem, &size, hwndOwner );
+ lpitem->Rect.right += size.cx;
+ if( lpitem->lpstr) lpitem->Rect.right += 2;
+ itemheight = size.cy;
+
+ /* Special case: Minimize button doesn't have a space behind it. */
+ if (lpitem->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE ||
+ lpitem->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D)
+ lpitem->Rect.right -= 1;
+ }
+ }
+ else if (!menuBar) {
+ if( !(MenuInfo->dwStyle & MNS_NOCHECK))
+ lpitem->Rect.right += check_bitmap_width;
+ lpitem->Rect.right += 4 + MenuCharSize.cx;
+ lpitem->dxTab = lpitem->Rect.right;
+ lpitem->Rect.right += check_bitmap_width;
+ }
+
+ /* it must be a text item - unless it's the system menu */
+ if (!(lpitem->fType & MF_SYSMENU) && lpitem->lpstr) {
+ HFONT hfontOld = NULL;
+ RECT rc = lpitem->Rect;
+ LONG txtheight, txtwidth;
+
+ if ( lpitem->fState & MFS_DEFAULT ) {
+ hfontOld = SelectObject( hdc, hMenuFontBold );
+ }
+ if (menuBar) {
+ txtheight = DrawTextW( hdc, lpitem->dwTypeData, -1, &rc,
+ DT_SINGLELINE|DT_CALCRECT);
+ lpitem->Rect.right += rc.right - rc.left;
+ itemheight = max( max( itemheight, txtheight),
+ GetSystemMetrics( SM_CYMENU) - 1);
+ lpitem->Rect.right += 2 * MenuCharSize.cx;
+ } else {
+ if ((p = strchrW( lpitem->dwTypeData, '\t' )) != NULL) {
+ RECT tmprc = rc;
+ LONG tmpheight;
+ int n = (int)( p - lpitem->dwTypeData);
+ /* Item contains a tab (only meaningful in popup menus) */
+ /* get text size before the tab */
+ txtheight = DrawTextW( hdc, lpitem->dwTypeData, n, &rc,
+ DT_SINGLELINE|DT_CALCRECT);
+ txtwidth = rc.right - rc.left;
+ p += 1; /* advance past the Tab */
+ /* get text size after the tab */
+ tmpheight = DrawTextW( hdc, p, -1, &tmprc,
+ DT_SINGLELINE|DT_CALCRECT);
+ lpitem->dxTab += txtwidth;
+ txtheight = max( txtheight, tmpheight);
+ txtwidth += MenuCharSize.cx + /* space for the tab */
+ tmprc.right - tmprc.left; /* space for the short cut */
+ } else {
+ txtheight = DrawTextW( hdc, lpitem->dwTypeData, -1, &rc,
+ DT_SINGLELINE|DT_CALCRECT);
+ txtwidth = rc.right - rc.left;
+ lpitem->dxTab += txtwidth;
+ }
+ lpitem->Rect.right += 2 + txtwidth;
+ itemheight = max( itemheight,
+ max( txtheight + 2, MenuCharSize.cy + 4));
+ }
+ if (hfontOld) SelectObject (hdc, hfontOld);
+ } else if( menuBar) {
+ itemheight = max( itemheight, GetSystemMetrics(SM_CYMENU)-1);
+ }
+ lpitem->Rect.bottom += itemheight;
+ TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem->Rect.left, lpitem->Rect.top, lpitem->Rect.right, lpitem->Rect.bottom);
+}
+
+/***********************************************************************
+ * MENU_GetMaxPopupHeight
+ */
+static UINT
+MENU_GetMaxPopupHeight(PROSMENUINFO lppop)
+{
+ if (lppop->cyMax)
+ return lppop->cyMax;
+ return GetSystemMetrics(SM_CYSCREEN) - GetSystemMetrics(SM_CYBORDER);
+}
+
+/***********************************************************************
+ * MenuPopupMenuCalcSize
+ *
+ * Calculate the size of a popup menu.
+ */
+static void FASTCALL MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner)
+{
+ ROSMENUITEMINFO lpitem;
+ HDC hdc;
+ int start, i;
+ int orgX, orgY, maxX, maxTab, maxTabWidth, maxHeight;
+ BOOL textandbmp = FALSE;
+
+ MenuInfo->cxMenu = MenuInfo->cyMenu = 0;
+ if (MenuInfo->cItems == 0)
+ {
+ MenuSetRosMenuInfo(MenuInfo);
+ return;
+ }
+
+ hdc = GetDC(NULL);
+ SelectObject( hdc, hMenuFont );
+
+ start = 0;
+ maxX = 2 + 1;
+
+ MenuInfo->cxTextAlign = 0;
+
+ MenuInitRosMenuItemInfo(&lpitem);
+ while (start < MenuInfo->cItems)
+ {
+ orgX = maxX;
+ orgY = 2;
+
+ maxTab = maxTabWidth = 0;
+
+ /* Parse items until column break or end of menu */
+ for (i = start; i < MenuInfo->cItems; i++)
+ {
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i, &lpitem))
+ {
+ MenuCleanupRosMenuItemInfo(&lpitem);
+ MenuSetRosMenuInfo(MenuInfo);
+ return;
+ }
+ if (i != start &&
+ (lpitem.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
+
+ if( lpitem.lpstr && lpitem.hbmpItem) textandbmp = TRUE;
+
+ MenuCalcItemSize(hdc, &lpitem, MenuInfo, WndOwner, orgX, orgY, FALSE, textandbmp);
+ if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &lpitem))
+ {
+ MenuCleanupRosMenuItemInfo(&lpitem);
+ MenuSetRosMenuInfo(MenuInfo);
+ return;
+ }
+// Not sure here,, The patch from wine removes this.
+// if ((lpitem.fType & MF_MENUBARBREAK) != 0)
+// {
+// OrgX++;
+// }
+ maxX = max(maxX, lpitem.Rect.right);
+ orgY = lpitem.Rect.bottom;
+ if ((lpitem.lpstr) && lpitem.dxTab )
+ {
+ maxTab = max( maxTab, lpitem.dxTab );
+ maxTabWidth = max(maxTabWidth, lpitem.Rect.right - lpitem.dxTab);
+ }
+ }
+
+ /* Finish the column (set all items to the largest width found) */
+ maxX = max( maxX, maxTab + maxTabWidth );
+ while (start < i)
+ {
+ if (MenuGetRosMenuItemInfo(MenuInfo->Self, start, &lpitem))
+ {
+ lpitem.Rect.right = maxX;
+ if ((lpitem.lpstr) && 0 != lpitem.dxTab)
+ {
+ lpitem.dxTab = maxTab;
+ }
+ MenuSetRosMenuItemInfo(MenuInfo->Self, start, &lpitem);
+ }
+ start++;
+ }
+ MenuInfo->cyMenu = max(MenuInfo->cyMenu, orgY);
+ }
+
+ MenuInfo->cxMenu = maxX;
+ /* if none of the items have both text and bitmap then
+ * the text and bitmaps are all aligned on the left. If there is at
+ * least one item with both text and bitmap then bitmaps are
+ * on the left and texts left aligned with the right hand side
+ * of the bitmaps */
+ if( !textandbmp) MenuInfo->cxTextAlign = 0;
+
+ /* space for 3d border */
+ MenuInfo->cyMenu += MENU_BOTTOM_MARGIN;
+ MenuInfo->cxMenu += 2;
+
+ /* Adjust popup height if it exceeds maximum */
+ maxHeight = MENU_GetMaxPopupHeight(MenuInfo);
+ MenuInfo->iMaxTop = MenuInfo->cyMenu - MENU_TOP_MARGIN;
+ if (MenuInfo->cyMenu >= maxHeight)
+ {
+ MenuInfo->cyMenu = maxHeight;
+ MenuInfo->dwArrowsOn = 1;
+ }
+ else
+ {
+ MenuInfo->dwArrowsOn = 0;
+ }
+
+ MenuCleanupRosMenuItemInfo(&lpitem);
+ MenuSetRosMenuInfo(MenuInfo);
+ ReleaseDC( 0, hdc );
+}
+
+/***********************************************************************
+ * MenuMenuBarCalcSize
+ *
+ * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
+ * height is off by 1 pixel which causes lengthy window relocations when
+ * active document window is maximized/restored.
+ *
+ * Calculate the size of the menu bar.
+ */
+static void FASTCALL MenuMenuBarCalcSize( HDC hdc, LPRECT lprect,
+ PROSMENUINFO MenuInfo, HWND hwndOwner )
+{
+ ROSMENUITEMINFO ItemInfo;
+ int start, i, orgX, orgY, maxY, helpPos;
+
+ if ((lprect == NULL) || (MenuInfo == NULL)) return;
+ if (MenuInfo->cItems == 0) return;
-
++ TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
+ MenuInfo->cxMenu = lprect->right - lprect->left;
+ MenuInfo->cyMenu = 0;
+ maxY = lprect->top + 1;
+ start = 0;
+ helpPos = -1;
+
+ MenuInfo->cxTextAlign = 0;
+
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ while (start < MenuInfo->cItems)
+ {
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ orgX = lprect->left;
+ orgY = maxY;
+
+ /* Parse items until line break or end of menu */
+ for (i = start; i < MenuInfo->cItems; i++)
+ {
+ if ((helpPos == -1) && (ItemInfo.fType & MF_RIGHTJUSTIFY)) helpPos = i;
+ if ((i != start) &&
+ (ItemInfo.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
+
+ TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX, orgY);
+ MenuCalcItemSize(hdc, &ItemInfo, MenuInfo, hwndOwner, orgX, orgY, TRUE, FALSE);
+ if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+
+ if (ItemInfo.Rect.right > lprect->right)
+ {
+ if (i != start) break;
+ else ItemInfo.Rect.right = lprect->right;
+ }
+ maxY = max( maxY, ItemInfo.Rect.bottom );
+ orgX = ItemInfo.Rect.right;
+ if (i + 1 < MenuInfo->cItems)
+ {
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i + 1, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ }
+ }
+
+/* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
+HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
+#if 0
+ /* Finish the line (set all items to the largest height found) */
+ while (start < i)
+ {
+ if (MenuGetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo))
+ {
+ ItemInfo.Rect.bottom = maxY;
+ MenuSetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo);
+ }
+ start++;
+ }
+#else
+ start = i; /* This works! */
+#endif
+ }
+
+ lprect->bottom = maxY;
+ MenuInfo->cyMenu = lprect->bottom - lprect->top;
+ MenuSetRosMenuInfo(MenuInfo);
+
+ if (helpPos != -1)
+ {
+ /* Flush right all items between the MF_RIGHTJUSTIFY and */
+ /* the last item (if several lines, only move the last line) */
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->cItems - 1, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ orgY = ItemInfo.Rect.top;
+ orgX = lprect->right;
+ for (i = MenuInfo->cItems - 1; helpPos <= i; i--)
+ {
+ if (i < helpPos)
+ {
+ break; /* done */
+ }
+ if (ItemInfo.Rect.top != orgY)
+ {
+ break; /* Other line */
+ }
+ if (orgX <= ItemInfo.Rect.right)
+ {
+ break; /* Too far right already */
+ }
+ ItemInfo.Rect.left += orgX - ItemInfo.Rect.right;
+ ItemInfo.Rect.right = orgX;
+ orgX = ItemInfo.Rect.left;
+ MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo);
+ if (helpPos + 1 <= i &&
+ ! MenuGetRosMenuItemInfo(MenuInfo->Self, i - 1, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ }
+ }
+
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+}
+
+/***********************************************************************
+ * MENU_DrawScrollArrows
+ *
+ * Draw scroll arrows.
+ */
+static void
+MENU_DrawScrollArrows(PROSMENUINFO lppop, HDC hdc)
+{
+ HDC hdcMem = CreateCompatibleDC(hdc);
+ HBITMAP hOrigBitmap;
+ UINT arrow_bitmap_width, arrow_bitmap_height;
+ BITMAP bmp;
+ RECT rect;
+
+ GetObjectW(get_down_arrow_bitmap(), sizeof(bmp), &bmp);
+ arrow_bitmap_width = bmp.bmWidth;
+ arrow_bitmap_height = bmp.bmHeight;
+
+
+ if (lppop->iTop)
+ hOrigBitmap = SelectObject(hdcMem, get_up_arrow_bitmap());
+ else
+ hOrigBitmap = SelectObject(hdcMem, get_up_arrow_inactive_bitmap());
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = lppop->cxMenu;
+ rect.bottom = arrow_bitmap_height;
+ FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENU));
+ BitBlt(hdc, (lppop->cxMenu - arrow_bitmap_width) / 2, 0,
+ arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY);
+ rect.top = lppop->cyMenu - arrow_bitmap_height;
+ rect.bottom = lppop->cyMenu;
+ FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENU));
+ if (lppop->iTop < lppop->iMaxTop - (MENU_GetMaxPopupHeight(lppop) - 2 * arrow_bitmap_height))
+ SelectObject(hdcMem, get_down_arrow_bitmap());
+ else
+ SelectObject(hdcMem, get_down_arrow_inactive_bitmap());
+ BitBlt(hdc, (lppop->cxMenu - arrow_bitmap_width) / 2,
+ lppop->cyMenu - arrow_bitmap_height,
+ arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY);
+ SelectObject(hdcMem, hOrigBitmap);
+ DeleteDC(hdcMem);
+}
+
- PWND Wnd = ValidateHwnd(hWnd);
+/***********************************************************************
+ * MenuDrawMenuItem
+ *
+ * Draw a single menu item.
+ */
+static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC hdc,
+ PROSMENUITEMINFO lpitem, UINT Height, BOOL menuBar, UINT odaction)
+{
+ RECT rect;
+ PWCHAR Text;
+ BOOL flat_menu = FALSE;
+ int bkgnd;
- rect.left += max(0, MenuInfo->cxTextAlign - GetSystemMetrics(SM_CXMENUCHECK));
++ PWND Wnd = ValidateHwndNoErr(hWnd);
+
+ if (!Wnd)
+ return;
+
+ if (lpitem->fType & MF_SYSMENU)
+ {
+ if ( (Wnd->style & WS_MINIMIZE))
+ {
+ UserGetInsideRectNC(Wnd, &rect);
+ UserDrawSysMenuButton(hWnd, hdc, &rect, lpitem->fState & (MF_HILITE | MF_MOUSESELECT));
+ }
+ return;
+ }
+
+ SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
+ bkgnd = (menuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU;
+
+ /* Setup colors */
+
+ if (lpitem->fState & MF_HILITE)
+ {
+ if(menuBar && !flat_menu) {
+ SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
+ SetBkColor(hdc, GetSysColor(COLOR_MENU));
+ } else {
+ if (lpitem->fState & MF_GRAYED)
+ SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
+ else
+ SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
+ }
+ }
+ else
+ {
+ if (lpitem->fState & MF_GRAYED)
+ SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
+ else
+ SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
+ SetBkColor( hdc, GetSysColor( bkgnd ) );
+ }
+
++ TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect));
+ rect = lpitem->Rect;
+ MENU_AdjustMenuItemRect(MenuInfo, &rect);
+
+ if (lpitem->fType & MF_OWNERDRAW)
+ {
+ /*
+ ** Experimentation under Windows reveals that an owner-drawn
+ ** menu is given the rectangle which includes the space it requested
+ ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
+ ** and a popup-menu arrow. This is the value of lpitem->rect.
+ ** Windows will leave all drawing to the application except for
+ ** the popup-menu arrow. Windows always draws that itself, after
+ ** the menu owner has finished drawing.
+ */
+ DRAWITEMSTRUCT dis;
+
+ dis.CtlType = ODT_MENU;
+ dis.CtlID = 0;
+ dis.itemID = lpitem->wID;
+ dis.itemData = (DWORD)lpitem->dwItemData;
+ dis.itemState = 0;
+ if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
+ if (lpitem->fState & MF_DEFAULT) dis.itemState |= ODS_DEFAULT;
+ if (lpitem->fState & MF_DISABLED) dis.itemState |= ODS_DISABLED;
+ if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED | ODS_DISABLED;
+ if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED;
+ //if (!(MenuInfo->fFlags & MNF_UNDERLINE)) dis.itemState |= ODS_NOACCEL;
+ //if (MenuInfo->fFlags & MNF_INACTIVE) dis.itemState |= ODS_INACTIVE;
+ dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
+ dis.hwndItem = (HWND) MenuInfo->Self;
+ dis.hDC = hdc;
+ dis.rcItem = rect;
+ TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
+ "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd,
+ dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
+ dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
+ dis.rcItem.bottom);
+ SendMessageW(WndOwner, WM_DRAWITEM, 0, (LPARAM) &dis);
+ /* Draw the popup-menu arrow */
+ if (lpitem->hSubMenu)
+ {
+ RECT rectTemp;
+ CopyRect(&rectTemp, &rect);
+ rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK);
+ DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
+ }
+ return;
+ }
+
+ if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
+
+ if (lpitem->fState & MF_HILITE)
+ {
+ if (flat_menu)
+ {
+ InflateRect (&rect, -1, -1);
+ FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENUHILIGHT));
+ InflateRect (&rect, 1, 1);
+ FrameRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
+ }
+ else
+ {
+ if(menuBar)
+ DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
+ else
+ FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
+ }
+ }
+ else
+ FillRect( hdc, &rect, GetSysColorBrush(bkgnd) );
+
+ SetBkMode( hdc, TRANSPARENT );
+
+ /* vertical separator */
+ if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
+ {
+ HPEN oldPen;
+ RECT rc = rect;
+
+ rc.left -= 3;
+ rc.top = 3;
+ rc.bottom = Height - 3;
+ if (flat_menu)
+ {
+ oldPen = SelectObject( hdc, GetStockObject(DC_PEN) );
+ SetDCPenColor(hdc, GetSysColor(COLOR_BTNSHADOW));
+ MoveToEx( hdc, rc.left, rc.top, NULL );
+ LineTo( hdc, rc.left, rc.bottom );
+ SelectObject( hdc, oldPen );
+ }
+ else
+ DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
+ }
+
+ /* horizontal separator */
+ if (lpitem->fType & MF_SEPARATOR)
+ {
+ HPEN oldPen;
+ RECT rc = rect;
+
+ rc.left++;
+ rc.right--;
+ rc.top += SEPARATOR_HEIGHT / 2;
+ if (flat_menu)
+ {
+ oldPen = SelectObject( hdc, GetStockObject(DC_PEN) );
+ SetDCPenColor( hdc, GetSysColor(COLOR_BTNSHADOW));
+ MoveToEx( hdc, rc.left, rc.top, NULL );
+ LineTo( hdc, rc.right, rc.top );
+ SelectObject( hdc, oldPen );
+ }
+ else
+ DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
+ return;
+ }
+
+#if 0
+ /* helper lines for debugging */
+ /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
+ FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
+ SelectObject(hdc, GetStockObject(DC_PEN));
+ SetDCPenColor(hdc, GetSysColor(COLOR_WINDOWFRAME));
+ MoveToEx(hdc, rect.left, (rect.top + rect.bottom) / 2, NULL);
+ LineTo(hdc, rect.right, (rect.top + rect.bottom) / 2);
+#endif
+
+ if (!menuBar)
+ {
+ HBITMAP bm;
+ INT y = rect.top + rect.bottom;
+ RECT rc = rect;
+ BOOL checked = FALSE;
+ UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
+ UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK );
+ /* Draw the check mark
+ *
+ * FIXME:
+ * Custom checkmark bitmaps are monochrome but not always 1bpp.
+ */
+ if( !(MenuInfo->dwStyle & MNS_NOCHECK)) {
+ bm = (lpitem->fState & MF_CHECKED) ? lpitem->hbmpChecked :
+ lpitem->hbmpUnchecked;
+ if (bm) /* we have a custom bitmap */
+ {
+ HDC hdcMem = CreateCompatibleDC( hdc );
+
+ SelectObject( hdcMem, bm );
+ BitBlt( hdc, rc.left, (y - check_bitmap_height) / 2,
+ check_bitmap_width, check_bitmap_height,
+ hdcMem, 0, 0, SRCCOPY );
+ DeleteDC( hdcMem );
+ checked = TRUE;
+ }
+ else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */
+ {
+ RECT r;
+ CopyRect(&r, &rect);
+ r.right = r.left + GetSystemMetrics(SM_CXMENUCHECK);
+ DrawFrameControl( hdc, &r, DFC_MENU,
+ (lpitem->fType & MFT_RADIOCHECK) ?
+ DFCS_MENUBULLET : DFCS_MENUCHECK);
+ checked = TRUE;
+ }
+ }
+ if ( lpitem->hbmpItem )
+ {
+ RECT bmpRect;
+ CopyRect(&bmpRect, &rect);
+ if (!(MenuInfo->dwStyle & MNS_CHECKORBMP) && !(MenuInfo->dwStyle & MNS_NOCHECK))
+ bmpRect.left += check_bitmap_width + 2;
+ if (!(checked && (MenuInfo->dwStyle & MNS_CHECKORBMP)))
+ {
+ bmpRect.right = bmpRect.left + lpitem->maxBmpSize.cx;
+ MenuDrawBitmapItem(hdc, lpitem, &bmpRect, MenuInfo, WndOwner, odaction, menuBar);
+ }
+ }
+ /* Draw the popup-menu arrow */
+ if (lpitem->hSubMenu)
+ {
+ RECT rectTemp;
+ CopyRect(&rectTemp, &rect);
+ rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK);
+ DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
+ }
+ rect.left += 4;
+ if( !(MenuInfo->dwStyle & MNS_NOCHECK))
+ rect.left += check_bitmap_width;
+ rect.right -= check_bitmap_width;
+ }
+ else if( lpitem->hbmpItem)
+ { /* Draw the bitmap */
+ MenuDrawBitmapItem(hdc, lpitem, &rect, MenuInfo, WndOwner, odaction, menuBar);
+ }
+
+ /* process text if present */
+ if (lpitem->lpstr)
+ {
+ register int i = 0;
+ HFONT hfontOld = 0;
+
+ UINT uFormat = menuBar ?
+ DT_CENTER | DT_VCENTER | DT_SINGLELINE :
+ DT_LEFT | DT_VCENTER | DT_SINGLELINE;
+
+ if((MenuInfo->dwStyle & MNS_CHECKORBMP))
- DWORD ex_style = 0;
++ rect.left += max(0, (int)(MenuInfo->cxTextAlign - GetSystemMetrics(SM_CXMENUCHECK)));
+ else
+ rect.left += MenuInfo->cxTextAlign;
+
+ if ( lpitem->fState & MFS_DEFAULT )
+ {
+ hfontOld = SelectObject(hdc, hMenuFontBold);
+ }
+
+ if (menuBar) {
+ rect.left += MENU_BAR_ITEMS_SPACE / 2;
+ rect.right -= MENU_BAR_ITEMS_SPACE / 2;
+ }
+
+ Text = (PWCHAR) lpitem->dwTypeData;
+ if(Text)
+ {
+ for (i = 0; L'\0' != Text[i]; i++)
+ if (Text[i] == L'\t' || Text[i] == L'\b')
+ break;
+ }
+
+ if(lpitem->fState & MF_GRAYED)
+ {
+ if (!(lpitem->fState & MF_HILITE) )
+ {
+ ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
+ SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
+ DrawTextW( hdc, Text, i, &rect, uFormat );
+ --rect.left; --rect.top; --rect.right; --rect.bottom;
+ }
+ SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
+ }
+
+ DrawTextW( hdc, Text, i, &rect, uFormat);
+
+ /* paint the shortcut text */
+ if (!menuBar && L'\0' != Text[i]) /* There's a tab or flush-right char */
+ {
+ if (L'\t' == Text[i])
+ {
+ rect.left = lpitem->dxTab;
+ uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
+ }
+ else
+ {
+ rect.right = lpitem->dxTab;
+ uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
+ }
+
+ if (lpitem->fState & MF_GRAYED)
+ {
+ if (!(lpitem->fState & MF_HILITE) )
+ {
+ ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
+ SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
+ DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat);
+ --rect.left; --rect.top; --rect.right; --rect.bottom;
+ }
+ SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
+ }
+ DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat );
+ }
+
+ if (hfontOld)
+ SelectObject (hdc, hfontOld);
+ }
+}
+
+/***********************************************************************
+ * MenuDrawPopupMenu
+ *
+ * Paint a popup menu.
+ */
+static void FASTCALL MenuDrawPopupMenu(HWND hwnd, HDC hdc, HMENU hmenu )
+{
+ HBRUSH hPrevBrush = 0;
+ RECT rect;
+
+ TRACE("wnd=%p dc=%p menu=%p\n", hwnd, hdc, hmenu);
+
+ GetClientRect( hwnd, &rect );
+
+ if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
+ && (SelectObject( hdc, hMenuFont)))
+ {
+ HPEN hPrevPen;
+
+ Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
+
+ hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
+ if ( hPrevPen )
+ {
+ BOOL flat_menu = FALSE;
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+
+ SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
+ if (flat_menu)
+ FrameRect(hdc, &rect, GetSysColorBrush(COLOR_BTNSHADOW));
+ else
+ DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
+
+ /* draw menu items */
++ //TRACE("hmenu %p Style %08x\n", hmenu, menu->dwStyle);
+ if (MenuGetRosMenuInfo(&MenuInfo, hmenu) && MenuInfo.cItems)
+ {
+ UINT u;
+ MenuInitRosMenuItemInfo(&ItemInfo);
+
+ for (u = 0; u < MenuInfo.cItems; u++)
+ {
+ if (MenuGetRosMenuItemInfo(MenuInfo.Self, u, &ItemInfo))
+ {
+ HWND WndOwner = MenuInfo.spwndNotify ? MenuInfo.spwndNotify->head.h : NULL;
+ MenuDrawMenuItem(hwnd, &MenuInfo, WndOwner, hdc, &ItemInfo,
+ MenuInfo.cyMenu, FALSE, ODA_DRAWENTIRE);
+ }
+ }
+
+ /* draw scroll arrows */
+ if (MenuInfo.dwArrowsOn)
+ MENU_DrawScrollArrows(&MenuInfo, hdc);
+
+ MenuSetRosMenuInfo(&MenuInfo);
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ }
+ } else
+ {
+ SelectObject( hdc, hPrevBrush );
+ }
+ }
+}
+
+/***********************************************************************
+ * MenuDrawMenuBar
+ *
+ * Paint a menu bar. Returns the height of the menu bar.
+ * called from [windows/nonclient.c]
+ */
+UINT MenuDrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
+ BOOL suppress_draw)
+{
+ ROSMENUINFO lppop;
+ HFONT hfontOld = 0;
+ HMENU hMenu = GetMenu(hwnd);
+
+ if (! MenuGetRosMenuInfo(&lppop, hMenu) || lprect == NULL)
+ {
+ return GetSystemMetrics(SM_CYMENU);
+ }
+
+ if (suppress_draw)
+ {
+ hfontOld = SelectObject(hDC, hMenuFont);
+
+ MenuMenuBarCalcSize(hDC, lprect, &lppop, hwnd);
+
+ lprect->bottom = lprect->top + lppop.cyMenu;
+
+ if (hfontOld) SelectObject( hDC, hfontOld);
+ return lppop.cyMenu;
+ }
+ else
+ return DrawMenuBarTemp(hwnd, hDC, lprect, hMenu, NULL);
+}
+
++/***********************************************************************
++ * MENU_InitPopup
++ *
++ * Popup menu initialization before WM_ENTERMENULOOP.
++ */
++static BOOL MENU_InitPopup( HWND hwndOwner, HMENU hmenu, UINT flags )
++{
++ MENU *menu;
++ DWORD ex_style = 0;
++ ROSMENUINFO MenuInfo;
++
++ TRACE("owner=%p hmenu=%p\n", hwndOwner, hmenu);
++
++ if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
++
++ /* store the owner for DrawItem */
++ if (!IsWindow( hwndOwner ))
++ {
++ SetLastError( ERROR_INVALID_WINDOW_HANDLE );
++ return FALSE;
++ }
++ MenuGetRosMenuInfo(&MenuInfo, menu->head.h);
++ //menu->hwndOwner = hwndOwner;
++ MenuInfo.spwndNotify = ValidateHwndNoErr( hwndOwner );
++
++ if (flags & TPM_LAYOUTRTL)
++ ex_style = WS_EX_LAYOUTRTL;
++
++ /* NOTE: In Windows, top menu popup is not owned. */
++ //menu->hWnd = CreateWindowExW( ex_style, WC_MENU, NULL,
++ MenuInfo.Wnd = CreateWindowExW( ex_style, WC_MENU, NULL,
++ WS_POPUP, 0, 0, 0, 0,
++ hwndOwner, 0, (HINSTANCE)GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE),
++ (LPVOID)hmenu );
++ MenuSetRosMenuInfo(&MenuInfo);
++ if( !menu->hWnd ) return FALSE;
++ return TRUE;
++}
+
+/***********************************************************************
+ * MenuShowPopup
+ *
+ * Display a popup menu.
+ */
+static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT flags,
+ INT x, INT y, INT xanchor, INT yanchor )
+{
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+ UINT width, height;
+ POINT pt;
+ HMONITOR monitor;
+ MONITORINFO info;
- /* store the owner for DrawItem */
- if (!IsWindow(hwndOwner))
- {
- SetLastError( ERROR_INVALID_WINDOW_HANDLE );
- return FALSE;
- }
- MenuInfo.spwndNotify = ValidateHwndNoErr(hwndOwner);
+
+ TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
+ hwndOwner, hmenu, id, x, y, xanchor, yanchor);
+
+ if (! MenuGetRosMenuInfo(&MenuInfo, hmenu)) return FALSE;
+ if (MenuInfo.iItem != NO_SELECTED_ITEM)
+ {
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.iItem, &ItemInfo))
+ {
+ ItemInfo.fMask |= MIIM_STATE;
+ ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT);
+ MenuSetRosMenuItemInfo(MenuInfo.Self, MenuInfo.iItem, &ItemInfo);
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ MenuInfo.iItem = NO_SELECTED_ITEM;
+ }
+
-
++ //menu->dwArrowsOn = 0;
++ MenuInfo.dwArrowsOn = 0;
+ MenuSetRosMenuInfo(&MenuInfo);
- {
- ex_style = WS_EX_LAYOUTRTL;
+ MenuPopupMenuCalcSize(&MenuInfo, hwndOwner);
+
+ /* adjust popup menu pos so that it fits within the desktop */
+
+ width = MenuInfo.cxMenu + GetSystemMetrics(SM_CXBORDER);
+ height = MenuInfo.cyMenu + GetSystemMetrics(SM_CYBORDER);
+
+ /* FIXME: should use item rect */
+ pt.x = x;
+ pt.y = y;
+ monitor = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST );
+ info.cbSize = sizeof(info);
+ GetMonitorInfoW( monitor, &info );
+
+ if (flags & TPM_LAYOUTRTL)
- }
+ flags ^= TPM_RIGHTALIGN;
- /* NOTE: In Windows, top menu popup is not owned. */
- MenuInfo.Wnd = CreateWindowExW( ex_style, WC_MENU, NULL,
- WS_POPUP, x, y, width, height,
- hwndOwner, 0, (HINSTANCE) GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE),
- (LPVOID) MenuInfo.Self);
- if ( !MenuInfo.Wnd || ! MenuSetRosMenuInfo(&MenuInfo)) return FALSE;
++
+ if( flags & TPM_RIGHTALIGN ) x -= width;
+ if( flags & TPM_CENTERALIGN ) x -= width / 2;
+
+ if( flags & TPM_BOTTOMALIGN ) y -= height;
+ if( flags & TPM_VCENTERALIGN ) y -= height / 2;
+
+ if( x + width > info.rcMonitor.right)
+ {
+ if( xanchor && x >= width - xanchor )
+ x -= width - xanchor;
+
+ if( x + width > info.rcMonitor.right)
+ x = info.rcMonitor.right - width;
+ }
+ if( x < info.rcMonitor.left ) x = info.rcMonitor.left;
+
+ if( y + height > info.rcMonitor.bottom)
+ {
+ if( yanchor && y >= height + yanchor )
+ y -= height + yanchor;
+
+ if( y + height > info.rcMonitor.bottom)
+ y = info.rcMonitor.bottom - height;
+ }
+ if( y < info.rcMonitor.top ) y = info.rcMonitor.top;
+
-
- IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, MenuInfo.Wnd, OBJID_CLIENT, CHILDID_SELF, 0);
-
+ if (!top_popup) {
+ top_popup = MenuInfo.Wnd;
+ top_popup_hmenu = hmenu;
+ }
- SetWindowPos( MenuInfo.Wnd, HWND_TOPMOST, 0, 0, 0, 0,
- SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
+ /* Display the window */
+
- pWnd = ValidateHwnd(Wnd);
++ SetWindowPos( MenuInfo.Wnd, HWND_TOPMOST, x, y, width, height,
++ SWP_SHOWWINDOW | SWP_NOACTIVATE);
+ UpdateWindow( MenuInfo.Wnd );
++
++ IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, MenuInfo.Wnd, OBJID_CLIENT, CHILDID_SELF, 0);
++
+ return TRUE;
+}
+
+/***********************************************************************
+ * MENU_EnsureMenuItemVisible
+ */
+void
+MENU_EnsureMenuItemVisible(PROSMENUINFO lppop, PROSMENUITEMINFO item, HDC hdc)
+{
+ if (lppop->dwArrowsOn)
+ {
+ //ITEM *item = &lppop->items[wIndex];
+ UINT nMaxHeight = MENU_GetMaxPopupHeight(lppop);
+ UINT nOldPos = lppop->iTop;
+ RECT rc;
+ UINT arrow_bitmap_height;
+ BITMAP bmp;
+
+ GetClientRect(lppop->Wnd, &rc);
+
+ GetObjectW(get_down_arrow_bitmap(), sizeof(bmp), &bmp);
+ arrow_bitmap_height = bmp.bmHeight;
+
+ rc.top += arrow_bitmap_height;
+ rc.bottom -= arrow_bitmap_height + MENU_BOTTOM_MARGIN;
+
+ nMaxHeight -= GetSystemMetrics(SM_CYBORDER) + 2 * arrow_bitmap_height;
+ if (item->Rect.bottom > lppop->iTop + nMaxHeight)
+ {
+ lppop->iTop = item->Rect.bottom - nMaxHeight;
+ ScrollWindow(lppop->Wnd, 0, nOldPos - lppop->iTop, &rc, &rc);
+ MENU_DrawScrollArrows(lppop, hdc);
+ }
+ else if (item->Rect.top - MENU_TOP_MARGIN < lppop->iTop)
+ {
+ lppop->iTop = item->Rect.top - MENU_TOP_MARGIN;
+ ScrollWindow(lppop->Wnd, 0, nOldPos - lppop->iTop, &rc, &rc);
+ MENU_DrawScrollArrows(lppop, hdc);
+ }
+ }
+}
+
+/***********************************************************************
+ * MenuSelectItem
+ */
+static void FASTCALL MenuSelectItem(HWND hwndOwner, PROSMENUINFO hmenu, UINT wIndex,
+ BOOL sendMenuSelect, HMENU topmenu)
+{
+ ROSMENUITEMINFO ItemInfo;
+ ROSMENUINFO TopMenuInfo;
+ HDC hdc;
+
+ TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
+
+ if (!hmenu || !hmenu->cItems || !hmenu->Wnd) return;
+ if (hmenu->iItem == wIndex) return;
+ if (hmenu->fFlags & MNF_POPUP) hdc = GetDC(hmenu->Wnd);
+ else hdc = GetDCEx(hmenu->Wnd, 0, DCX_CACHE | DCX_WINDOW);
+ if (!top_popup) {
+ top_popup = hmenu->Wnd;
+ top_popup_hmenu = hmenu->Self;
+ }
+
+ SelectObject( hdc, hMenuFont );
+
+ MenuInitRosMenuItemInfo(&ItemInfo);
+
+ /* Clear previous highlighted item */
+ if (hmenu->iItem != NO_SELECTED_ITEM)
+ {
+ if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo))
+ {
+ ItemInfo.fMask |= MIIM_STATE;
+ ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT);
+ MenuSetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo);
+ }
+ //MENU_EnsureMenuItemVisible(hmenu, &ItemInfo, hdc);
+ MenuDrawMenuItem(hmenu->Wnd, hmenu, hwndOwner, hdc, &ItemInfo,
+ hmenu->cyMenu, !(hmenu->fFlags & MNF_POPUP),
+ ODA_SELECT);
+ }
+
+ /* Highlight new item (if any) */
+ hmenu->iItem = wIndex;
+ MenuSetRosMenuInfo(hmenu);
+ if (hmenu->iItem != NO_SELECTED_ITEM)
+ {
+ if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo))
+ {
+ if (!(ItemInfo.fType & MF_SEPARATOR))
+ {
+ ItemInfo.fMask |= MIIM_STATE;
+ ItemInfo.fState |= MF_HILITE;
+ MenuSetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo);
+ MenuDrawMenuItem(hmenu->Wnd, hmenu, hwndOwner, hdc,
+ &ItemInfo, hmenu->cyMenu, !(hmenu->fFlags & MNF_POPUP),
+ ODA_SELECT);
+ }
+ if (sendMenuSelect)
+ {
+ WPARAM wParam = MAKEWPARAM( ItemInfo.hSubMenu ? wIndex : ItemInfo.wID,
+ ItemInfo.fType | ItemInfo.fState |
+ (ItemInfo.hSubMenu ? MF_POPUP : 0) |
+ (hmenu->fFlags & MNF_SYSDESKMN ? MF_SYSMENU : 0 ) );
+
+ SendMessageW(hwndOwner, WM_MENUSELECT, wParam, (LPARAM) hmenu->Self);
+ }
+ }
+ }
+ else if (sendMenuSelect)
+ {
+ if(topmenu)
+ {
+ int pos;
+ pos = MenuFindSubMenu(&topmenu, hmenu->Self);
+ if (pos != NO_SELECTED_ITEM)
+ {
+ if (MenuGetRosMenuInfo(&TopMenuInfo, topmenu)
+ && MenuGetRosMenuItemInfo(topmenu, pos, &ItemInfo))
+ {
+ WPARAM wParam = MAKEWPARAM( Pos, ItemInfo.fType | ItemInfo.fState |
+ (ItemInfo.hSubMenu ? MF_POPUP : 0) |
+ (TopMenuInfo.fFlags & MNF_SYSDESKMN ? MF_SYSMENU : 0 ) );
+
+ SendMessageW(hwndOwner, WM_MENUSELECT, wParam, (LPARAM) topmenu);
+ }
+ }
+ }
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ ReleaseDC(hmenu->Wnd, hdc);
+}
+
+/***********************************************************************
+ * MenuMoveSelection
+ *
+ * Moves currently selected item according to the Offset parameter.
+ * If there is no selection then it should select the last item if
+ * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
+ */
+static void FASTCALL
+MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset)
+{
+ INT i;
+ ROSMENUITEMINFO ItemInfo;
+ INT OrigPos;
+
+ TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner, MenuInfo, Offset);
+
+ /* Prevent looping */
+ if (0 == MenuInfo->cItems || 0 == Offset)
+ return;
+ else if (Offset < -1)
+ Offset = -1;
+ else if (Offset > 1)
+ Offset = 1;
+
+ MenuInitRosMenuItemInfo(&ItemInfo);
+
+ OrigPos = MenuInfo->iItem;
+ if (OrigPos == NO_SELECTED_ITEM) /* NO_SELECTED_ITEM is not -1 ! */
+ {
+ OrigPos = 0;
+ i = -1;
+ }
+ else
+ {
+ i = MenuInfo->iItem;
+ }
+
+ do
+ {
+ /* Step */
+ i += Offset;
+ /* Clip and wrap around */
+ if (i < 0)
+ {
+ i = MenuInfo->cItems - 1;
+ }
+ else if (i >= MenuInfo->cItems)
+ {
+ i = 0;
+ }
+ /* If this is a good candidate; */
+ if (MenuGetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo) &&
+ 0 == (ItemInfo.fType & MF_SEPARATOR))
+ {
+ MenuSelectItem(WndOwner, MenuInfo, i, TRUE, NULL);
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ } while (i != OrigPos);
+
+ /* Not found */
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+}
+
+#if 0
+LRESULT WINAPI
+PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
+{
+#ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
+ PWND pWnd;
+ PPOPUPMENU pPopupMenu;
+
-
++ pWnd = ValidateHwndNoErr(Wnd);
+ if (pWnd)
+ {
+ if (!pWnd->fnid)
+ {
+ if (Message != WM_NCCREATE)
+ {
+ return DefWindowProcW(Wnd, Message, wParam, lParam);
+ }
+ NtUserSetWindowFNID(Wnd, FNID_MENU);
+ pPopupMenu = HeapAlloc( GetProcessHeap(), 0, sizeof(POPUPMENU) );
+ pPopupMenu->spwndPopupMenu = pWnd;
+ SetWindowLongPtrW(Wnd, 0, (LONG_PTR)pPopupMenu);
+ }
+ else
+ {
+ if (pWnd->fnid != FNID_MENU)
+ {
+ ERR("Wrong window class for Menu!\n");
+ return 0;
+ }
+ pPopupMenu = ((PMENUWND)pWnd)->ppopupmenu;
+ }
+ }
+#endif
+
+ TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
+
+ switch(Message)
+ {
+ case WM_CREATE:
+ {
+ CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
+ pPopupMenu->spmenu = ValidateHandle(cs->lpCreateParams, TYPE_MENU);
+ return 0;
+ }
+
+ case WM_MOUSEACTIVATE: /* We don't want to be activated */
+ return MA_NOACTIVATE;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ BeginPaint(Wnd, &ps);
+ MenuDrawPopupMenu(Wnd, ps.hdc, pPopupMenu->spmenu->head.h);
+ EndPaint(Wnd, &ps);
+ return 0;
+ }
+
+ case WM_PRINTCLIENT:
+ {
+ MenuDrawPopupMenu( Wnd, (HDC)wParam, pPopupMenu->spmenu->head.h);
+ return 0;
+ }
+
+ case WM_ERASEBKGND:
+ return 1;
+
+ case WM_DESTROY:
+ /* zero out global pointer in case resident popup window was destroyed. */
+ if (Wnd == top_popup)
+ {
+ top_popup = NULL;
+ top_popup_hmenu = NULL;
+ }
+ break;
+
+ case WM_NCDESTROY:
+ {
+ HeapFree( GetProcessHeap(), 0, pPopupMenu );
+ SetWindowLongPtrW(Wnd, 0, 0);
+ NtUserSetWindowFNID(Wnd, FNID_DESTROY);
+ break;
+ }
+
+ case WM_SHOWWINDOW:
+ if (0 != wParam)
+ {
+ if (!pPopupMenu || !pPopupMenu->spmenu)
+ {
+ OutputDebugStringA("no menu to display\n");
+ }
+ }
+ /*else
+ {
+ pPopupMenu->spmenu = NULL; ///// WTF?
+ }*/
+ break;
+
+ case MM_SETMENUHANDLE:
+ {
+ PMENU pmenu = ValidateHandle((HMENU)wParam, TYPE_MENU);
+ if (!pmenu)
+ {
+ ERR("Bad Menu Handle\n");
+ break;
+ }
+ pPopupMenu->spmenu = pmenu;
+ break;
+ }
+
+ case MM_GETMENUHANDLE:
+ case MN_GETHMENU:
+ return (LRESULT)(pPopupMenu ? (pPopupMenu->spmenu ? pPopupMenu->spmenu->head.h : NULL) : NULL);
+
+ default:
+ return DefWindowProcW(Wnd, Message, wParam, lParam);
+ }
+
+ return 0;
+}
+#endif
+
+LRESULT WINAPI
+PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
+{
+#ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
+ PWND pWnd;
+
+ pWnd = ValidateHwnd(Wnd);
+ if (pWnd)
+ {
+ if (!pWnd->fnid)
+ {
+ if (Message != WM_NCCREATE)
+ {
+ return DefWindowProcW(Wnd, Message, wParam, lParam);
+ }
+ NtUserSetWindowFNID(Wnd, FNID_MENU);
+ }
+ else
+ {
+ if (pWnd->fnid != FNID_MENU)
+ {
+ ERR("Wrong window class for Menu!\n");
+ return 0;
+ }
+ }
+ }
+#endif
+
+ TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
+
+ switch(Message)
+ {
+ case WM_CREATE:
+ {
+ CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
+ SetWindowLongPtrW(Wnd, 0, (LONG_PTR)cs->lpCreateParams);
+ return 0;
+ }
+
+ case WM_MOUSEACTIVATE: /* We don't want to be activated */
+ return MA_NOACTIVATE;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ BeginPaint(Wnd, &ps);
+ MenuDrawPopupMenu(Wnd, ps.hdc, (HMENU)GetWindowLongPtrW(Wnd, 0));
+ EndPaint(Wnd, &ps);
+ return 0;
+ }
+
+ case WM_PRINTCLIENT:
+ {
+ MenuDrawPopupMenu( Wnd, (HDC)wParam,
+ (HMENU)GetWindowLongPtrW( Wnd, 0 ) );
+ return 0;
+ }
+
+ case WM_ERASEBKGND:
+ return 1;
+
+ case WM_DESTROY:
+ /* zero out global pointer in case resident popup window was destroyed. */
+ if (Wnd == top_popup)
+ {
+ top_popup = NULL;
+ top_popup_hmenu = NULL;
+ }
+ break;
+
++#ifdef __REACTOS__
++ case WM_NCDESTROY:
++ NtUserSetWindowFNID(Wnd, FNID_DESTROY);
++ break;
++#endif
++
+ case WM_SHOWWINDOW:
+ if (0 != wParam)
+ {
+ if (0 == GetWindowLongPtrW(Wnd, 0))
+ {
+ OutputDebugStringA("no menu to display\n");
+ }
+ }
+ else
+ {
+ SetWindowLongPtrW(Wnd, 0, 0);
+ }
+ break;
+
+ case MM_SETMENUHANDLE:
+ SetWindowLongPtrW(Wnd, 0, wParam);
+ break;
+
+ case MM_GETMENUHANDLE:
+ case MN_GETHMENU:
+ return GetWindowLongPtrW(Wnd, 0);
+
+ default:
+ return DefWindowProcW(Wnd, Message, wParam, lParam);
+ }
+
+ return 0;
+}
+
+//
+// This breaks some test results. Should handle A2U if called!
+//
+LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
+{
+ PWND pWnd;
+
+ pWnd = ValidateHwnd(Wnd);
+ if (pWnd && !pWnd->fnid && Message != WM_NCCREATE)
+ {
+ return DefWindowProcA(Wnd, Message, wParam, lParam);
+ }
+ TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
+
+ switch(Message)
+ {
+ case WM_NCCREATE:
+ case WM_CREATE:
+ case WM_MOUSEACTIVATE:
+ case WM_PAINT:
+ case WM_PRINTCLIENT:
+ case WM_ERASEBKGND:
+ case WM_DESTROY:
+ case WM_NCDESTROY:
+ case WM_SHOWWINDOW:
+ case MM_SETMENUHANDLE:
+ case MM_GETMENUHANDLE:
+ case MN_GETHMENU:
+ return PopupMenuWndProcW(Wnd, Message, wParam, lParam);
+
+ default:
+ return DefWindowProcA(Wnd, Message, wParam, lParam);
+ }
+ return 0;
+}
+
+/**********************************************************************
+ * MENU_ParseResource
+ *
+ * Parse a standard menu resource and add items to the menu.
+ * Return a pointer to the end of the resource.
+ *
+ * NOTE: flags is equivalent to the mtOption field
+ */
+static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu)
+{
+ WORD flags, id = 0;
+ HMENU hSubMenu;
+ LPCWSTR str;
+ BOOL end = FALSE;
+
+ do
+ {
+ flags = GET_WORD(res);
+
+ /* remove MF_END flag before passing it to AppendMenu()! */
+ end = (flags & MF_END);
+ if(end) flags ^= MF_END;
+
+ res += sizeof(WORD);
+ if(!(flags & MF_POPUP))
+ {
+ id = GET_WORD(res);
+ res += sizeof(WORD);
+ }
+ str = (LPCWSTR)res;
+ res += (strlenW(str) + 1) * sizeof(WCHAR);
+
+ if (flags & MF_POPUP)
+ {
+ hSubMenu = CreatePopupMenu();
+ if(!hSubMenu) return NULL;
+ if(!(res = MENU_ParseResource(res, hSubMenu))) return NULL;
+ AppendMenuW(hMenu, flags, (UINT_PTR)hSubMenu, (LPCWSTR)str);
+ }
+ else /* Not a popup */
+ {
+ AppendMenuW(hMenu, flags, id, *(LPCWSTR)str ? (LPCWSTR)str : NULL);
+ }
+ } while(!end);
+ return res;
+}
+
- NTSTATUS WINAPI
- User32LoadSysMenuTemplateForKernel(PVOID Arguments, ULONG ArgumentLength)
- {
- HMENU hmenu = LoadMenuW(User32Instance, L"SYSMENU");
- LRESULT Result = (LRESULT)hmenu;
- MENUINFO menuinfo = {0};
- MENUITEMINFOW info = {0};
-
- // removing space for checkboxes from menu
- menuinfo.cbSize = sizeof(menuinfo);
- menuinfo.fMask = MIM_STYLE;
- GetMenuInfo(hmenu, &menuinfo);
- menuinfo.dwStyle |= MNS_CHECKORBMP; // test_menu_bmp_and_string MNS_CHECKORBMP
- SetMenuInfo(hmenu, &menuinfo);
-
- // adding bitmaps to menu items
- info.cbSize = sizeof(info);
- info.fMask |= MIIM_BITMAP;
- info.hbmpItem = HBMMENU_POPUP_MINIMIZE;
- SetMenuItemInfoW(hmenu, SC_MINIMIZE, FALSE, &info);
- info.hbmpItem = HBMMENU_POPUP_RESTORE;
- SetMenuItemInfoW(hmenu, SC_RESTORE, FALSE, &info);
- info.hbmpItem = HBMMENU_POPUP_MAXIMIZE;
- SetMenuItemInfoW(hmenu, SC_MAXIMIZE, FALSE, &info);
- info.hbmpItem = HBMMENU_POPUP_CLOSE;
- SetMenuItemInfoW(hmenu, SC_CLOSE, FALSE, &info);
-
- return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
- }
-
-
- BOOL
- MenuInit(VOID)
- {
- NONCLIENTMETRICSW ncm;
-
- /* get the menu font */
- if(!hMenuFont || !hMenuFontBold)
- {
- ncm.cbSize = sizeof(ncm);
- if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
- {
- ERR("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
- return FALSE;
- }
-
- hMenuFont = CreateFontIndirectW(&ncm.lfMenuFont);
- if(hMenuFont == NULL)
- {
- ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
- return FALSE;
- }
-
- ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
- hMenuFontBold = CreateFontIndirectW(&ncm.lfMenuFont);
- if(hMenuFontBold == NULL)
- {
- ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
- DeleteObject(hMenuFont);
- hMenuFont = NULL;
- return FALSE;
- }
- }
-
- return TRUE;
- }
-
- VOID
- MenuCleanup(VOID)
- {
- if (hMenuFont)
- {
- DeleteObject(hMenuFont);
- hMenuFont = NULL;
- }
-
- if (hMenuFontBold)
- {
- DeleteObject(hMenuFontBold);
- hMenuFontBold = NULL;
- }
- }
+/**********************************************************************
+ * MENUEX_ParseResource
+ *
+ * Parse an extended menu resource and add items to the menu.
+ * Return a pointer to the end of the resource.
+ */
+static LPCSTR MENUEX_ParseResource(LPCSTR res, HMENU hMenu)
+{
+ WORD resinfo;
+ do
+ {
+ MENUITEMINFOW mii;
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
+ mii.fType = GET_DWORD(res);
+ res += sizeof(DWORD);
+ mii.fState = GET_DWORD(res);
+ res += sizeof(DWORD);
+ mii.wID = GET_DWORD(res);
+ res += sizeof(DWORD);
+ resinfo = GET_WORD(res);
+ res += sizeof(WORD);
+ /* Align the text on a word boundary. */
+ res += (~((UINT_PTR)res - 1)) & 1;
+ mii.dwTypeData = (LPWSTR)res;
+ mii.cch = strlenW(mii.dwTypeData);
+ res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
+ /* Align the following fields on a dword boundary. */
+ res += (~((UINT_PTR)res - 1)) & 3;
+
+ TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
+ mii.fType, mii.fState, mii.wID, resinfo, mii.dwTypeData);
+
+ if (resinfo & 1) /* Pop-up? */
+ {
+ /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
+ res += sizeof(DWORD);
+ mii.hSubMenu = CreatePopupMenu();
+ if (!mii.hSubMenu)
+ {
+ ERR("CreatePopupMenu failed\n");
+ return NULL;
+ }
+
+ if (!(res = MENUEX_ParseResource(res, mii.hSubMenu)))
+ {
+ ERR("MENUEX_ParseResource failed\n");
+ DestroyMenu(mii.hSubMenu);
+ return NULL;
+ }
+ mii.fMask |= MIIM_SUBMENU;
+ }
+ else if (!mii.dwTypeData[0] && !(mii.fType & MF_SEPARATOR))
+ {
+ mii.fType |= MF_SEPARATOR;
+ }
+ InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
+ } while (!(resinfo & MF_END));
+ return res;
+}
+
- #if 0
- static BOOL MENU_InitPopup( HWND hwndOwner, HMENU hmenu, UINT flags )
- {
- POPUPMENU *menu;
- DWORD ex_style = 0;
-
- TRACE("owner=%p hmenu=%p\n", hwndOwner, hmenu);
+
+/***********************************************************************
+ * DrawMenuBarTemp (USER32.@)
+ *
+ * UNDOCUMENTED !!
+ *
+ * called by W98SE desk.cpl Control Panel Applet
+ *
+ * Not 100% sure about the param names, but close.
+ *
+ * @implemented
+ */
+DWORD WINAPI
+DrawMenuBarTemp(HWND Wnd, HDC DC, LPRECT Rect, HMENU Menu, HFONT Font)
+{
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+ UINT i;
+ HFONT FontOld = NULL;
+ BOOL flat_menu = FALSE;
+
+ SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
+
+ if (NULL == Menu)
+ {
+ Menu = GetMenu(Wnd);
+ }
+
+ if (NULL == Font)
+ {
+ Font = hMenuFont;
+ }
+
+ if (NULL == Rect || ! MenuGetRosMenuInfo(&MenuInfo, Menu))
+ {
+ return GetSystemMetrics(SM_CYMENU);
+ }
+
+ TRACE("(%x, %x, %p, %x, %x)\n", Wnd, DC, Rect, Menu, Font);
+
+ FontOld = SelectObject(DC, Font);
+
+ if (0 == MenuInfo.cyMenu)
+ {
+ MenuMenuBarCalcSize(DC, Rect, &MenuInfo, Wnd);
+ }
+
+ Rect->bottom = Rect->top + MenuInfo.cyMenu;
+
+ FillRect(DC, Rect, GetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU));
+
+ SelectObject(DC, GetStockObject(DC_PEN));
+ SetDCPenColor(DC, GetSysColor(COLOR_3DFACE));
+ MoveToEx(DC, Rect->left, Rect->bottom - 1, NULL);
+ LineTo(DC, Rect->right, Rect->bottom - 1);
+
+ if (0 == MenuInfo.cItems)
+ {
+ SelectObject(DC, FontOld);
+ return GetSystemMetrics(SM_CYMENU);
+ }
+
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ for (i = 0; i < MenuInfo.cItems; i++)
+ {
+ if (MenuGetRosMenuItemInfo(MenuInfo.Self, i, &ItemInfo))
+ {
+ MenuDrawMenuItem(Wnd, &MenuInfo, Wnd, DC, &ItemInfo,
+ MenuInfo.cyMenu, TRUE, ODA_DRAWENTIRE);
+ }
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+
+ SelectObject(DC, FontOld);
+
+ return MenuInfo.cyMenu;
+}
- if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
-
- /* store the owner for DrawItem */
- if (!IsWindow( hwndOwner ))
- {
- SetLastError( ERROR_INVALID_WINDOW_HANDLE );
- return FALSE;
- }
- menu->hwndOwner = hwndOwner;
-
- if (flags & TPM_LAYOUTRTL)
- ex_style = WS_EX_LAYOUTRTL;
+
- /* NOTE: In Windows, top menu popup is not owned. */
- menu->hWnd = CreateWindowExW( ex_style, (LPCWSTR)POPUPMENU_CLASS_ATOM, NULL,
- WS_POPUP, 0, 0, 0, 0,
- hwndOwner, 0, (HINSTANCE)GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE),
- (LPVOID)hmenu );
- if( !menu->hWnd ) return FALSE;
- return TRUE;
- }
- #endif
+
- extern void FASTCALL NcGetSysPopupPos(HWND Wnd, RECT *Rect);
+/***********************************************************************
+ * MenuShowSubPopup
+ *
+ * Display the sub-menu of the selected item of this menu.
+ * Return the handle of the submenu, or menu if no submenu to display.
+ */
+static HMENU FASTCALL
+MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Flags)
+{
- //MENU_InitPopup( WndOwner, ItemInfo.hSubMenu, Flags );
+ RECT Rect;
+ ROSMENUITEMINFO ItemInfo;
+ ROSMENUINFO SubMenuInfo;
+ HDC Dc;
+ HMENU Ret;
+
+ TRACE("owner=%x menu=%p 0x%04x\n", WndOwner, MenuInfo, SelectFirst);
+
+ if (NO_SELECTED_ITEM == MenuInfo->iItem)
+ {
+ return MenuInfo->Self;
+ }
+
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return MenuInfo->Self;
+ }
+ if (0 == (ItemInfo.hSubMenu) || 0 != (ItemInfo.fState & (MF_GRAYED | MF_DISABLED)))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return MenuInfo->Self;
+ }
+
+ /* message must be sent before using item,
+ because nearly everything may be changed by the application ! */
+
+ /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
+ if (0 == (Flags & TPM_NONOTIFY))
+ {
+ SendMessageW(WndOwner, WM_INITMENUPOPUP, (WPARAM) ItemInfo.hSubMenu,
+ MAKELPARAM(MenuInfo->iItem, IS_SYSTEM_MENU(MenuInfo)));
+ }
+
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return MenuInfo->Self;
+ }
+ Rect = ItemInfo.Rect;
+
+ /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
+ if (0 == (ItemInfo.fState & MF_HILITE))
+ {
+ if (0 != (MenuInfo->fFlags & MNF_POPUP))
+ {
+ Dc = GetDC(MenuInfo->Wnd);
+ }
+ else
+ {
+ Dc = GetDCEx(MenuInfo->Wnd, 0, DCX_CACHE | DCX_WINDOW);
+ }
+
+ SelectObject(Dc, hMenuFont);
+ ItemInfo.fMask |= MIIM_STATE;
+ ItemInfo.fState |= MF_HILITE;
+ MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo);
+ MenuDrawMenuItem(MenuInfo->Wnd, MenuInfo, WndOwner, Dc, &ItemInfo, MenuInfo->cyMenu,
+ !(MenuInfo->fFlags & MNF_POPUP), ODA_DRAWENTIRE);
+ ReleaseDC(MenuInfo->Wnd, Dc);
+ }
+
+ if (0 == ItemInfo.Rect.top && 0 == ItemInfo.Rect.left
+ && 0 == ItemInfo.Rect.bottom && 0 == ItemInfo.Rect.right)
+ {
+ ItemInfo.Rect = Rect;
+ }
+
+ ItemInfo.fMask |= MIIM_STATE;
+ ItemInfo.fState |= MF_MOUSESELECT;
+ MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo);
+
+ if (IS_SYSTEM_MENU(MenuInfo))
+ {
+ ERR("Right click on window bar and Draw system menu!\n");
+ MenuInitSysMenuPopup(ItemInfo.hSubMenu, GetWindowLongPtrW(MenuInfo->Wnd, GWL_STYLE),
+ GetClassLongPtrW(MenuInfo->Wnd, GCL_STYLE), HTSYSMENU);
+ if (Flags & TPM_LAYOUTRTL) Rect.left;
+ NcGetSysPopupPos(MenuInfo->Wnd, &Rect);
+ Rect.top = Rect.bottom;
+ Rect.right = GetSystemMetrics(SM_CXSIZE);
+ Rect.bottom = GetSystemMetrics(SM_CYSIZE);
+ }
+ else
+ {
+ GetWindowRect(MenuInfo->Wnd, &Rect);
+ if (0 != (MenuInfo->fFlags & MNF_POPUP))
+ {
+ RECT rc = ItemInfo.Rect;
+
+ MENU_AdjustMenuItemRect(MenuInfo, &rc);
+
+ if(Flags & TPM_LAYOUTRTL)
+ Rect.left += GetSystemMetrics(SM_CXBORDER);
+ else
+ Rect.left += ItemInfo.Rect.right- GetSystemMetrics(SM_CXBORDER);
+ Rect.top += rc.top - MENU_TOP_MARGIN;//3;
+ Rect.right = rc.left - rc.right + GetSystemMetrics(SM_CXBORDER);
+ Rect.bottom = rc.top - rc.bottom - MENU_TOP_MARGIN - MENU_BOTTOM_MARGIN/*2*/
+ - GetSystemMetrics(SM_CYBORDER);
+ }
+ else
+ {
+ if(Flags & TPM_LAYOUTRTL)
+ Rect.left += Rect.right - ItemInfo.Rect.left;
+ else
+ Rect.left += ItemInfo.Rect.left;
+ Rect.top += ItemInfo.Rect.bottom;
+ Rect.right = ItemInfo.Rect.right - ItemInfo.Rect.left;
+ Rect.bottom = ItemInfo.Rect.bottom - ItemInfo.Rect.top;
+ }
+ }
+
+ /* use default alignment for submenus */
+ Flags &= ~(TPM_CENTERALIGN | TPM_RIGHTALIGN | TPM_VCENTERALIGN | TPM_BOTTOMALIGN);
+
- ROSMENUINFO MenuInfo;
- BOOL Ret = FALSE;
- if (top_popup_hmenu)
- Ret = MenuGetRosMenuInfo(&MenuInfo, top_popup_hmenu);
- if (Ret && hwnd == (MenuInfo.spwndNotify ? MenuInfo.spwndNotify->head.h : NULL)) EndMenu();
++ MENU_InitPopup( WndOwner, ItemInfo.hSubMenu, Flags );
+
+ MenuShowPopup(WndOwner, ItemInfo.hSubMenu, MenuInfo->iItem, Flags,
+ Rect.left, Rect.top, Rect.right, Rect.bottom );
+ if (SelectFirst && MenuGetRosMenuInfo(&SubMenuInfo, ItemInfo.hSubMenu))
+ {
+ MenuMoveSelection(WndOwner, &SubMenuInfo, ITEM_NEXT);
+ }
+
+ Ret = ItemInfo.hSubMenu;
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+
+ return Ret;
+}
+
+/**********************************************************************
+ * MENU_EndMenu
+ *
+ * Calls EndMenu() if the hwnd parameter belongs to the menu owner
+ *
+ * Does the (menu stuff) of the default window handling of WM_CANCELMODE
+ */
+void MENU_EndMenu( HWND hwnd )
+{
- DestroyWindow(SubMenuInfo.Wnd);
- SubMenuInfo.Wnd = NULL;
- MenuSetRosMenuInfo(&SubMenuInfo);
++ MENU *menu;
++ menu = top_popup_hmenu ? MENU_GetMenu( top_popup_hmenu ) : NULL;
++ if (menu && ( hwnd == menu->hWnd || hwnd == (menu->spwndNotify ? menu->spwndNotify->head.h : NULL)) )
++ EndMenu();
+}
+
+/***********************************************************************
+ * MenuHideSubPopups
+ *
+ * Hide the sub-popup menus of this menu.
+ */
+static void FASTCALL
+MenuHideSubPopups(HWND WndOwner, PROSMENUINFO MenuInfo,
+ BOOL SendMenuSelect, UINT wFlags)
+{
+ ROSMENUINFO SubMenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+
+ TRACE("owner=%x menu=%x 0x%04x\n", WndOwner, MenuInfo, SendMenuSelect);
+
+ if (NULL != MenuInfo && NULL != top_popup && NO_SELECTED_ITEM != MenuInfo->iItem)
+ {
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ ItemInfo.fMask |= MIIM_FTYPE | MIIM_STATE;
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo)
+ || 0 == (ItemInfo.hSubMenu)
+ || 0 == (ItemInfo.fState & MF_MOUSESELECT))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ ItemInfo.fState &= ~MF_MOUSESELECT;
+ ItemInfo.fMask |= MIIM_STATE;
+ MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo);
+ if (MenuGetRosMenuInfo(&SubMenuInfo, ItemInfo.hSubMenu))
+ {
+ MenuHideSubPopups(WndOwner, &SubMenuInfo, FALSE, wFlags);
+ MenuSelectItem(WndOwner, &SubMenuInfo, NO_SELECTED_ITEM, SendMenuSelect, NULL);
- MenuButtonDown(MTRACKER* Mt, HMENU PtMenu, UINT Flags)
+
++ DestroyWindow(SubMenuInfo.Wnd);
++ /* Native returns handle to destroyed window */
+ if (!(wFlags & TPM_NONOTIFY))
+ SendMessageW( WndOwner, WM_UNINITMENUPOPUP, (WPARAM)ItemInfo.hSubMenu,
+ MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo)) );
++ ////
++ // Call WM_UNINITMENUPOPUP FIRST before destroy!!
++ // Fixes todo_wine User32 test menu.c line 2233 GetMenuBarInfo callback....
++ //
++ SubMenuInfo.Wnd = NULL;
++ MenuSetRosMenuInfo(&SubMenuInfo);
++ ////
+ }
+ }
+}
+
+/***********************************************************************
+ * MenuSwitchTracking
+ *
+ * Helper function for menu navigation routines.
+ */
+static void FASTCALL
+MenuSwitchTracking(MTRACKER* Mt, PROSMENUINFO PtMenuInfo, UINT Index, UINT wFlags)
+{
+ ROSMENUINFO TopMenuInfo;
+
+ TRACE("%x menu=%x 0x%04x\n", Mt, PtMenuInfo->Self, Index);
+
+ if (MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu) &&
+ Mt->TopMenu != PtMenuInfo->Self &&
+ 0 == ((PtMenuInfo->fFlags | TopMenuInfo.fFlags) & MNF_POPUP))
+ {
+ /* both are top level menus (system and menu-bar) */
+ MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE, wFlags);
+ MenuSelectItem(Mt->OwnerWnd, &TopMenuInfo, NO_SELECTED_ITEM, FALSE, NULL);
+ Mt->TopMenu = PtMenuInfo->Self;
+ }
+ else
+ {
+ MenuHideSubPopups(Mt->OwnerWnd, PtMenuInfo, FALSE, wFlags);
+ }
+
+ MenuSelectItem(Mt->OwnerWnd, PtMenuInfo, Index, TRUE, NULL);
+}
+
+/***********************************************************************
+ * MenuExecFocusedItem
+ *
+ * Execute a menu item (for instance when user pressed Enter).
+ * Return the wID of the executed item. Otherwise, -1 indicating
+ * that no menu item was executed, -2 if a popup is shown;
+ * Have to receive the flags for the TrackPopupMenu options to avoid
+ * sending unwanted message.
+ *
+ */
+static INT FASTCALL
+MenuExecFocusedItem(MTRACKER *Mt, PROSMENUINFO MenuInfo, UINT Flags)
+{
+ ROSMENUITEMINFO ItemInfo;
+ UINT wID;
+
+ TRACE("%p menu=%p\n", Mt, MenuInfo);
+
+ if (0 == MenuInfo->cItems || NO_SELECTED_ITEM == MenuInfo->iItem)
+ {
+ return -1;
+ }
+
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return -1;
+ }
+
+ TRACE("%p %08x %p\n", MenuInfo, ItemInfo.wID, ItemInfo.hSubMenu);
+
+ if (0 == (ItemInfo.hSubMenu))
+ {
+ if (0 == (ItemInfo.fState & (MF_GRAYED | MF_DISABLED))
+ && 0 == (ItemInfo.fType & MF_SEPARATOR))
+ {
+ /* If TPM_RETURNCMD is set you return the id, but
+ do not send a message to the owner */
+ if (0 == (Flags & TPM_RETURNCMD))
+ {
+ if (0 != (MenuInfo->fFlags & MNF_SYSDESKMN))
+ {
+ PostMessageW(Mt->OwnerWnd, WM_SYSCOMMAND, ItemInfo.wID,
+ MAKELPARAM((SHORT) Mt->Pt.x, (SHORT) Mt->Pt.y));
+ }
+ else
+ {
+ ROSMENUINFO topmenuI;
+ BOOL ret = MenuGetRosMenuInfo(&topmenuI, Mt->TopMenu);
+ DWORD dwStyle = MenuInfo->dwStyle | (ret ? topmenuI.dwStyle : 0);
+
+ if (dwStyle & MNS_NOTIFYBYPOS)
+ PostMessageW(Mt->OwnerWnd, WM_MENUCOMMAND, MenuInfo->iItem, (LPARAM)MenuInfo->Self);
+ else
+ PostMessageW(Mt->OwnerWnd, WM_COMMAND, ItemInfo.wID, 0);
+ }
+ }
+ wID = ItemInfo.wID;
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return wID;
+ }
+ }
+ else
+ {
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, MenuInfo, TRUE, Flags);
+ return -2;
+ }
+
+ return -1;
+}
+
+/***********************************************************************
+ * MenuButtonDown
+ *
+ * Return TRUE if we can go on with menu tracking.
+ */
+static BOOL FASTCALL
- MenuButtonUp(MTRACKER *Mt, HMENU PtMenu, UINT Flags)
++MENU_ButtonDown(MTRACKER* Mt, HMENU PtMenu, UINT Flags)
+{
+ int Index;
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO Item;
+
+ TRACE("%x PtMenu=%p\n", Mt, PtMenu);
+
+ if (NULL != PtMenu)
+ {
+ if (! MenuGetRosMenuInfo(&MenuInfo, PtMenu))
+ {
+ return FALSE;
+ }
+ if (IS_SYSTEM_MENU(&MenuInfo))
+ {
+ Index = 0;
+ }
+ else
+ {
+ Index = NtUserMenuItemFromPoint(Mt->OwnerWnd, PtMenu, Mt->Pt.x, Mt->Pt.y);
+ }
+ MenuInitRosMenuItemInfo(&Item);
+ if (NO_SELECTED_ITEM == Index || ! MenuGetRosMenuItemInfo(PtMenu, Index, &Item))
+ {
+ MenuCleanupRosMenuItemInfo(&Item);
+ return FALSE;
+ }
+
+ if (!(Item.fType & MF_SEPARATOR) &&
+ !(Item.fState & (MFS_DISABLED | MFS_GRAYED)) )
+ {
+ if (MenuInfo.iItem != Index)
+ {
+ MenuSwitchTracking(Mt, &MenuInfo, Index, Flags);
+ }
+
+ /* If the popup menu is not already "popped" */
+ if (0 == (Item.fState & MF_MOUSESELECT))
+ {
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
+ }
+ }
+
+ MenuCleanupRosMenuItemInfo(&Item);
+
+ return TRUE;
+ }
+
+ /* else the click was on the menu bar, finish the tracking */
+
+ return FALSE;
+}
+
+/***********************************************************************
+ * MenuButtonUp
+ *
+ * Return the value of MenuExecFocusedItem if
+ * the selected item was not a popup. Else open the popup.
+ * A -1 return value indicates that we go on with menu tracking.
+ *
+ */
+static INT FASTCALL
- MenuPtMenu(HMENU Menu, POINT Pt)
++MENU_ButtonUp(MTRACKER *Mt, HMENU PtMenu, UINT Flags)
+{
+ INT Id;
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+
+ TRACE("%p hmenu=%x\n", Mt, PtMenu);
+
+ if (NULL != PtMenu)
+ {
+ Id = 0;
+ if (! MenuGetRosMenuInfo(&MenuInfo, PtMenu))
+ {
+ return -1;
+ }
+
+ if (! IS_SYSTEM_MENU(&MenuInfo))
+ {
+ Id = NtUserMenuItemFromPoint(Mt->OwnerWnd, MenuInfo.Self, Mt->Pt.x, Mt->Pt.y);
+ }
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (0 <= Id && MenuGetRosMenuItemInfo(MenuInfo.Self, Id, &ItemInfo) &&
+ MenuInfo.iItem == Id)
+ {
+ if (0 == (ItemInfo.hSubMenu))
+ {
+ INT ExecutedMenuId = MenuExecFocusedItem(Mt, &MenuInfo, Flags);
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return (ExecutedMenuId < 0) ? -1 : ExecutedMenuId;
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+
+ /* If we are dealing with the top-level menu */
+ /* and this is a click on an already "popped" item: */
+ /* Stop the menu tracking and close the opened submenus */
+ if (Mt->TopMenu == MenuInfo.Self && MenuInfo.TimeToHide)
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return 0;
+ }
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ MenuInfo.TimeToHide = TRUE;
+ MenuSetRosMenuInfo(&MenuInfo);
+ }
+
+ return -1;
+}
+
+/***********************************************************************
+ * MenuPtMenu
+ *
+ * Walks menu chain trying to find a menu pt maps to.
+ */
+static HMENU FASTCALL
- extern LRESULT DefWndNCHitTest(HWND hWnd, POINT Point);
- ROSMENUINFO MenuInfo;
- ROSMENUITEMINFO ItemInfo;
- HMENU Ret = NULL;
- INT Ht;
++MENU_PtMenu(HMENU hMenu, POINT pt)
+{
- if (! MenuGetRosMenuInfo(&MenuInfo, Menu))
- {
- return NULL;
- }
++ MENU *menu;
++ PITEM pItem;
++ HMENU ret = NULL;
+
- if (NO_SELECTED_ITEM != MenuInfo.iItem)
- {
- MenuInitRosMenuItemInfo(&ItemInfo);
- if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.iItem, &ItemInfo) &&
- 0 != (ItemInfo.hSubMenu) &&
- 0 != (ItemInfo.fState & MF_MOUSESELECT))
- {
- Ret = MenuPtMenu(ItemInfo.hSubMenu, Pt);
- if (NULL != Ret)
- {
- MenuCleanupRosMenuItemInfo(&ItemInfo);
- return Ret;
- }
- }
- MenuCleanupRosMenuItemInfo(&ItemInfo);
- }
++ menu = MENU_GetMenu( hMenu );
++ if (!menu) return NULL;
+
+ /* try subpopup first (if any) */
- Ht = DefWndNCHitTest(MenuInfo.Wnd, Pt);
- if (0 != (MenuInfo.fFlags & MNF_POPUP))
- {
- if (HTNOWHERE != Ht && HTERROR != Ht)
- {
- Ret = Menu;
- }
- }
- else if (HTSYSMENU == Ht)
- {
- Ret = NtUserGetSystemMenu(MenuInfo.Wnd, FALSE);
- }
- else if (HTMENU == Ht)
- {
- Ret = GetMenu(MenuInfo.Wnd);
- }
-
- return Ret;
++ if (menu->iItem != NO_SELECTED_ITEM)
++ {
++ pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
++ if ( pItem ) pItem = &pItem[menu->iItem];
++ if ( pItem && pItem->spSubMenu && pItem->fState & MF_MOUSESELECT)
++ {
++ PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
++ ret = MENU_PtMenu( UserHMGetHandle(pSubMenu), pt);
++ }
++ }
+
+ /* check the current window (avoiding WM_HITTEST) */
- static HMENU FASTCALL
- MenuGetSubPopup(HMENU Menu)
++ if (!ret)
++ {
++ INT ht = DefWndNCHitTest(menu->hWnd, pt);
++ if ( menu->fFlags & MNF_POPUP )
++ {
++ if (ht != HTNOWHERE && ht != HTERROR) ret = hMenu;
++ }
++ else if (ht == HTSYSMENU)
++ ret = NtUserGetSystemMenu(menu->hWnd, FALSE);
++ else if (ht == HTMENU)
++ ret = GetMenu( menu->hWnd );
++ }
++ return ret;
+}
+
+/***********************************************************************
+ * MenuMouseMove
+ *
+ * Return TRUE if we can go on with menu tracking.
+ */
+static BOOL FASTCALL
+MenuMouseMove(MTRACKER *Mt, HMENU PtMenu, UINT Flags)
+{
+ INT Index;
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+
+ if (NULL != PtMenu)
+ {
+ if (! MenuGetRosMenuInfo(&MenuInfo, PtMenu))
+ {
+ return TRUE;
+ }
+ if (IS_SYSTEM_MENU(&MenuInfo))
+ {
+ Index = 0;
+ }
+ else
+ {
+ Index = NtUserMenuItemFromPoint(Mt->OwnerWnd, PtMenu, Mt->Pt.x, Mt->Pt.y);
+ }
+ }
+ else
+ {
+ Index = NO_SELECTED_ITEM;
+ }
+
+ if (NO_SELECTED_ITEM == Index)
+ {
+ if (Mt->CurrentMenu == MenuInfo.Self ||
+ MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu))
+ {
+ MenuSelectItem(Mt->OwnerWnd, &MenuInfo, NO_SELECTED_ITEM,
+ TRUE, Mt->TopMenu);
+ }
+ }
+ else if (MenuInfo.iItem != Index)
+ {
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (MenuGetRosMenuItemInfo(MenuInfo.Self, Index, &ItemInfo) &&
+ !(ItemInfo.fType & MF_SEPARATOR))
+ {
+ MenuSwitchTracking(Mt, &MenuInfo, Index, Flags);
+ if (!(ItemInfo.fState & (MFS_DISABLED | MFS_GRAYED)))
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ }
+
+ return TRUE;
+}
+
+/***********************************************************************
+ * MenuGetSubPopup
+ *
+ * Return the handle of the selected sub-popup menu (if any).
+ */
- ROSMENUINFO MenuInfo;
- ROSMENUITEMINFO ItemInfo;
++static
++HMENU MENU_GetSubPopup( HMENU hmenu )
+{
- if (! MenuGetRosMenuInfo(&MenuInfo, Menu)
- || NO_SELECTED_ITEM == MenuInfo.iItem)
- {
- return NULL;
- }
++ MENU *menu;
++ ITEM *item;
+
- MenuInitRosMenuItemInfo(&ItemInfo);
- if (! MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.iItem, &ItemInfo))
- {
- MenuCleanupRosMenuItemInfo(&ItemInfo);
- return NULL;
- }
- if (0 != (ItemInfo.hSubMenu) && 0 != (ItemInfo.fState & MF_MOUSESELECT))
++ menu = MENU_GetMenu( hmenu );
+
- MenuCleanupRosMenuItemInfo(&ItemInfo);
- return ItemInfo.hSubMenu;
++ if ((!menu) || (menu->iItem == NO_SELECTED_ITEM)) return 0;
++
++ //item = &menu->rgItems[menu->iItem];
++ item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
++ if (item) item = &item[menu->iItem];
++ if (item && (item->spSubMenu) && (item->fState & MF_MOUSESELECT))
+ {
-
- MenuCleanupRosMenuItemInfo(&ItemInfo);
- return NULL;
++ PMENU pSubMenu = DesktopPtrToUser(item->spSubMenu);
++ return UserHMGetHandle(pSubMenu);
+ }
- MenuTmp = MenuGetSubPopup(MenuPrev);
++ return 0;
+}
+
+/***********************************************************************
+ * MenuDoNextMenu
+ *
+ * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
+ */
+static LRESULT FASTCALL
+MenuDoNextMenu(MTRACKER* Mt, UINT Vk, UINT wFlags)
+{
+ ROSMENUINFO TopMenuInfo;
+ ROSMENUINFO MenuInfo;
+
+ if (! MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu))
+ {
+ return (LRESULT) FALSE;
+ }
+
+ if ((VK_LEFT == Vk && 0 == TopMenuInfo.iItem)
+ || (VK_RIGHT == Vk && TopMenuInfo.iItem == TopMenuInfo.cItems - 1))
+ {
+ MDINEXTMENU NextMenu;
+ HMENU NewMenu;
+ HWND NewWnd;
+ UINT Id = 0;
+
+ NextMenu.hmenuIn = (IS_SYSTEM_MENU(&TopMenuInfo)) ? GetSubMenu(Mt->TopMenu, 0) : Mt->TopMenu;
+ NextMenu.hmenuNext = NULL;
+ NextMenu.hwndNext = NULL;
+ SendMessageW(Mt->OwnerWnd, WM_NEXTMENU, Vk, (LPARAM) &NextMenu);
+
+ TRACE("%p [%p] -> %p [%p]\n",
+ Mt->CurrentMenu, Mt->OwnerWnd, NextMenu.hmenuNext, NextMenu.hwndNext );
+
+ if (NULL == NextMenu.hmenuNext || NULL == NextMenu.hwndNext)
+ {
+ DWORD Style = GetWindowLongPtrW(Mt->OwnerWnd, GWL_STYLE);
+ NewWnd = Mt->OwnerWnd;
+ if (IS_SYSTEM_MENU(&TopMenuInfo))
+ {
+ /* switch to the menu bar */
+
+ if (0 != (Style & WS_CHILD)
+ || NULL == (NewMenu = GetMenu(NewWnd)))
+ {
+ return FALSE;
+ }
+
+ if (VK_LEFT == Vk)
+ {
+ if (! MenuGetRosMenuInfo(&MenuInfo, NewMenu))
+ {
+ return FALSE;
+ }
+ Id = MenuInfo.cItems - 1;
+ }
+ }
+ else if (0 != (Style & WS_SYSMENU))
+ {
+ /* switch to the system menu */
+ NewMenu = NtUserGetSystemMenu(NewWnd, FALSE);
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ else /* application returned a new menu to switch to */
+ {
+ NewMenu = NextMenu.hmenuNext;
+ NewWnd = NextMenu.hwndNext;
+
+ if (IsMenu(NewMenu) && IsWindow(NewWnd))
+ {
+ DWORD Style = GetWindowLongPtrW(NewWnd, GWL_STYLE);
+
+ if (0 != (Style & WS_SYSMENU)
+ && GetSystemMenu(NewWnd, FALSE) == NewMenu)
+ {
+ /* get the real system menu */
+ NewMenu = NtUserGetSystemMenu(NewWnd, FALSE);
+ }
+ else if (0 != (Style & WS_CHILD) || GetMenu(NewWnd) != NewMenu)
+ {
+ /* FIXME: Not sure what to do here;
+ * perhaps try to track NewMenu as a popup? */
+
+ WARN(" -- got confused.\n");
+ return FALSE;
+ }
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+
+ if (NewMenu != Mt->TopMenu)
+ {
+ MenuSelectItem(Mt->OwnerWnd, &TopMenuInfo, NO_SELECTED_ITEM,
+ FALSE, 0 );
+ if (Mt->CurrentMenu != Mt->TopMenu)
+ {
+ MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE, wFlags);
+ }
+ }
+
+ if (NewWnd != Mt->OwnerWnd)
+ {
+ Mt->OwnerWnd = NewWnd;
+ NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER, Mt->OwnerWnd); // 1
+ SetCapture(Mt->OwnerWnd); // 2
+ }
+
+ Mt->TopMenu = Mt->CurrentMenu = NewMenu; /* all subpopups are hidden */
+ if (MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu))
+ {
+ MenuSelectItem(Mt->OwnerWnd, &TopMenuInfo, Id, TRUE, 0);
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/***********************************************************************
+ * MenuSuspendPopup
+ *
+ * The idea is not to show the popup if the next input message is
+ * going to hide it anyway.
+ */
+static BOOL FASTCALL
+MenuSuspendPopup(MTRACKER* Mt, UINT uMsg)
+{
+ MSG msg;
+
+ msg.hwnd = Mt->OwnerWnd;
+
+ PeekMessageW( &msg, 0, uMsg, uMsg, PM_NOYIELD | PM_REMOVE); // ported incorrectly since 8317 GvG
+// Mt->TrackFlags |= TF_SKIPREMOVE; // This sends TrackMenu into a loop with arrow keys!!!!
+
+ switch( uMsg )
+ {
+ case WM_KEYDOWN:
+ PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
+ if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
+ {
+ PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
+ PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
+ if( msg.message == WM_KEYDOWN &&
+ (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
+ {
+ Mt->TrackFlags |= TF_SUSPENDPOPUP;
+ return TRUE;
+ }
+ }
+ break;
+ }
+ /* failures go through this */
+ Mt->TrackFlags &= ~TF_SUSPENDPOPUP;
+ return FALSE;
+}
+
+/***********************************************************************
+ * MenuKeyEscape
+ *
+ * Handle a VK_ESCAPE key event in a menu.
+ */
+static BOOL FASTCALL
+MenuKeyEscape(MTRACKER *Mt, UINT Flags)
+{
+ BOOL EndMenu = TRUE;
+ ROSMENUINFO MenuInfo;
+ HMENU MenuTmp, MenuPrev;
+
+ if (Mt->CurrentMenu != Mt->TopMenu)
+ {
+ if (MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu)
+ && 0 != (MenuInfo.fFlags & MNF_POPUP))
+ {
+ MenuPrev = MenuTmp = Mt->TopMenu;
+
+ /* close topmost popup */
+ while (MenuTmp != Mt->CurrentMenu)
+ {
+ MenuPrev = MenuTmp;
- if (! MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu))
- {
- return;
- }
-
++ MenuTmp = MENU_GetSubPopup(MenuPrev);
+ }
+
+ if (MenuGetRosMenuInfo(&MenuInfo, MenuPrev))
+ {
+ MenuHideSubPopups(Mt->OwnerWnd, &MenuInfo, TRUE, Flags);
+ }
+ Mt->CurrentMenu = MenuPrev;
+ EndMenu = FALSE;
+ }
+ }
+
+ return EndMenu;
+}
+
+/***********************************************************************
+ * MenuKeyLeft
+ *
+ * Handle a VK_LEFT key event in a menu.
+ */
+static void FASTCALL
+MenuKeyLeft(MTRACKER* Mt, UINT Flags)
+{
+ ROSMENUINFO MenuInfo;
+ ROSMENUINFO TopMenuInfo;
+ ROSMENUINFO PrevMenuInfo;
+ HMENU MenuTmp, MenuPrev;
+ UINT PrevCol;
+
+ MenuPrev = MenuTmp = Mt->TopMenu;
+
- if ( (PrevCol = MenuGetStartOfPrevColumn(&MenuInfo)) != NO_SELECTED_ITEM)
+ /* Try to move 1 column left (if possible) */
- MenuTmp = MenuGetSubPopup(MenuPrev);
++ if ( (PrevCol = MENU_GetStartOfPrevColumn(Mt->CurrentMenu)) != NO_SELECTED_ITEM)
+ {
+ if (MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu))
+ {
+ MenuSelectItem(Mt->OwnerWnd, &MenuInfo, PrevCol, TRUE, 0);
+ }
+ return;
+ }
+
+ /* close topmost popup */
+ while (MenuTmp != Mt->CurrentMenu)
+ {
+ MenuPrev = MenuTmp;
- if (! MenuGetRosMenuInfo(&CurrentMenuInfo, Mt->CurrentMenu))
- {
- return;
- }
-
++ MenuTmp = MENU_GetSubPopup(MenuPrev);
+ }
+
+ if (! MenuGetRosMenuInfo(&PrevMenuInfo, MenuPrev))
+ {
+ return;
+ }
+ MenuHideSubPopups(Mt->OwnerWnd, &PrevMenuInfo, TRUE, Flags);
+ Mt->CurrentMenu = MenuPrev;
+
+ if (! MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu))
+ {
+ return;
+ }
+ if ((MenuPrev == Mt->TopMenu) && !(TopMenuInfo.fFlags & MNF_POPUP))
+ {
+ /* move menu bar selection if no more popups are left */
+
+ if (!MenuDoNextMenu(Mt, VK_LEFT, Flags))
+ {
+ MenuMoveSelection(Mt->OwnerWnd, &TopMenuInfo, ITEM_PREV);
+ }
+
+ if (MenuPrev != MenuTmp || Mt->TrackFlags & TF_SUSPENDPOPUP)
+ {
+ /* A sublevel menu was displayed - display the next one
+ * unless there is another displacement coming up */
+
+ if (! MenuSuspendPopup(Mt, WM_KEYDOWN)
+ && MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu))
+ {
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &TopMenuInfo,
+ TRUE, Flags);
+ }
+ }
+ }
+}
+
+/***********************************************************************
+ * MenuKeyRight
+ *
+ * Handle a VK_RIGHT key event in a menu.
+ */
+static void FASTCALL MenuKeyRight(MTRACKER *Mt, UINT Flags)
+{
+ HMENU hmenutmp;
+ ROSMENUINFO MenuInfo;
+ ROSMENUINFO CurrentMenuInfo;
+ UINT NextCol;
+
+ TRACE("MenuKeyRight called, cur %p, top %p.\n",
+ Mt->CurrentMenu, Mt->TopMenu);
+
+ if (! MenuGetRosMenuInfo(&MenuInfo, Mt->TopMenu)) return;
+ if ((MenuInfo.fFlags & MNF_POPUP) || (Mt->CurrentMenu != Mt->TopMenu))
+ {
+ /* If already displaying a popup, try to display sub-popup */
+
+ hmenutmp = Mt->CurrentMenu;
+ if (MenuGetRosMenuInfo(&CurrentMenuInfo, Mt->CurrentMenu))
+ {
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &CurrentMenuInfo, TRUE, Flags);
+ }
+
+ /* if subpopup was displayed then we are done */
+ if (hmenutmp != Mt->CurrentMenu) return;
+ }
+
- if ( (NextCol = MenuGetStartOfNextColumn(&CurrentMenuInfo)) != NO_SELECTED_ITEM)
+ /* Check to see if there's another column */
- WARN("Invalid menu handle %p\n", hmenu);
- SetLastError( ERROR_INVALID_MENU_HANDLE );
++ if ( (NextCol = MENU_GetStartOfNextColumn(Mt->CurrentMenu)) != NO_SELECTED_ITEM)
+ {
+ TRACE("Going to %d.\n", NextCol);
+ if (MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu))
+ {
+ MenuSelectItem(Mt->OwnerWnd, &MenuInfo, NextCol, TRUE, 0);
+ }
+ return;
+ }
+
+ if (!(MenuInfo.fFlags & MNF_POPUP)) /* menu bar tracking */
+ {
+ if (Mt->CurrentMenu != Mt->TopMenu)
+ {
+ MenuHideSubPopups(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
+ hmenutmp = Mt->CurrentMenu = Mt->TopMenu;
+ }
+ else
+ {
+ hmenutmp = NULL;
+ }
+
+ /* try to move to the next item */
+ if ( !MenuDoNextMenu(Mt, VK_RIGHT, Flags))
+ MenuMoveSelection(Mt->OwnerWnd, &MenuInfo, ITEM_NEXT);
+
+ if ( hmenutmp || Mt->TrackFlags & TF_SUSPENDPOPUP )
+ {
+ if (! MenuSuspendPopup(Mt, WM_KEYDOWN)
+ && MenuGetRosMenuInfo(&MenuInfo, Mt->TopMenu))
+ {
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo,
+ TRUE, Flags);
+ }
+ }
+ }
+}
+
+/***********************************************************************
+ * MenuTrackMenu
+ *
+ * Menu tracking code.
+ */
+static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y,
+ HWND hwnd, const RECT *lprect )
+{
+ MSG msg;
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
++ PMENU menu;
+ BOOL fRemove;
+ INT executedMenuId = -1;
+ MTRACKER mt;
+ HWND capture_win;
+ BOOL enterIdleSent = FALSE;
+
+ mt.TrackFlags = 0;
+ mt.CurrentMenu = hmenu;
+ mt.TopMenu = hmenu;
+ mt.OwnerWnd = hwnd;
+ mt.Pt.x = x;
+ mt.Pt.y = y;
+
+ TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
+ hmenu, wFlags, x, y, hwnd, lprect ? lprect->left : 0, lprect ? lprect->top : 0,
+ lprect ? lprect->right : 0, lprect ? lprect->bottom : 0);
+
+ if (!IsMenu(hmenu))
+ {
- fEndMenu = FALSE;
++ WARN("Invalid menu handle %p\n", hmenu); // Error already set in IsMenu.
+ return FALSE;
+ }
+
- fRemove = MenuButtonDown( &mt, hmenu, wFlags );
+ if (! MenuGetRosMenuInfo(&MenuInfo, hmenu))
+ {
+ return FALSE;
+ }
+
+ if (wFlags & TPM_BUTTONDOWN)
+ {
+ /* Get the result in order to start the tracking or not */
- while (! fEndMenu)
++ fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
+ fEndMenu = !fRemove;
+ }
+
+ if (wFlags & TF_ENDMENU) fEndMenu = TRUE;
+
+ /* owner may not be visible when tracking a popup, so use the menu itself */
+ capture_win = (wFlags & TPM_POPUPMENU) ? MenuInfo.Wnd : mt.OwnerWnd;
+ NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER, capture_win); // 1
+ SetCapture(capture_win); // 2
+
- PMENU menu = ValidateHandle(mt.CurrentMenu, TYPE_MENU);
++ while (!fEndMenu)
+ {
+ BOOL ErrorExit = FALSE;
- if (!ValidateHwnd(mt.OwnerWnd) || !ValidateHwnd(MenuInfo.Wnd))
++ menu = MENU_GetMenu( mt.CurrentMenu );
+ if (!menu) /* sometimes happens if I do a window manager close */
+ break;
+
+ /* we have to keep the message in the queue until it's
+ * clear that menu loop is not over yet. */
+
+ for (;;)
+ {
+ if (PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ))
+ {
+ if (!CallMsgFilterW( &msg, MSGF_MENU )) break;
+ /* remove the message from the queue */
+ PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
+ }
+ else
+ {
+ /* ReactOS Check */
- hmenu = MenuPtMenu(mt.TopMenu, mt.Pt);
++ if (!ValidateHwndNoErr(mt.OwnerWnd) || !ValidateHwndNoErr(MenuInfo.Wnd))
+ {
+ ErrorExit = TRUE; // Do not wait on dead windows, now test_capture_4 works.
+ break;
+ }
+ if (!enterIdleSent)
+ {
+ HWND win = MenuInfo.fFlags & MNF_POPUP ? MenuInfo.Wnd : NULL;
+ enterIdleSent = TRUE;
+ SendMessageW( mt.OwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM) win);
+ }
+ WaitMessage();
+ }
+ }
+
+ if (ErrorExit) break; // Gracefully dropout.
+
+ /* check if EndMenu() tried to cancel us, by posting this message */
+ if (msg.message == WM_CANCELMODE)
+ {
+ /* we are now out of the loop */
+ fEndMenu = TRUE;
+
+ /* remove the message from the queue */
+ PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
+
+ /* break out of internal loop, ala ESCAPE */
+ break;
+ }
+
+ TranslateMessage( &msg );
+ mt.Pt = msg.pt;
+
+ if ( (msg.hwnd == MenuInfo.Wnd) || (msg.message!=WM_TIMER) )
+ enterIdleSent=FALSE;
+
+ fRemove = FALSE;
+ if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
+ {
+ /*
+ * Use the mouse coordinates in lParam instead of those in the MSG
+ * struct to properly handle synthetic messages. They are already
+ * in screen coordinates.
+ */
+ mt.Pt.x = (short)LOWORD(msg.lParam);
+ mt.Pt.y = (short)HIWORD(msg.lParam);
+
+ /* Find a menu for this mouse event */
- ERR("WM_RBUTTONDBLCLK\n");
++ hmenu = MENU_PtMenu(mt.TopMenu, mt.Pt);
+
+ switch(msg.message)
+ {
+ /* no WM_NC... messages in captured state */
+
+ case WM_RBUTTONDBLCLK:
- fRemove = MenuButtonDown(&mt, hmenu, wFlags);
+ case WM_RBUTTONDOWN:
+ if (!(wFlags & TPM_RIGHTBUTTON)) break;
+ /* fall through */
+ case WM_LBUTTONDBLCLK:
+ case WM_LBUTTONDOWN:
+ /* If the message belongs to the menu, removes it from the queue */
+ /* Else, end menu tracking */
- executedMenuId = MenuButtonUp( &mt, hmenu, wFlags);
++ fRemove = MENU_ButtonDown(&mt, hmenu, wFlags);
+ fEndMenu = !fRemove;
+ break;
+
+ case WM_RBUTTONUP:
+ if (!(wFlags & TPM_RIGHTBUTTON)) break;
+ /* fall through */
+ case WM_LBUTTONUP:
+ /* Check if a menu was selected by the mouse */
+ if (hmenu)
+ {
- MenuSelectItem(mt.OwnerWnd, &MenuInfo,
- NO_SELECTED_ITEM, FALSE, 0 );
- MenuMoveSelection(mt.OwnerWnd, &MenuInfo,
- VK_HOME == msg.wParam ? ITEM_NEXT : ITEM_PREV);
++ executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
+ TRACE("executedMenuId %d\n", executedMenuId);
+
+ /* End the loop if executedMenuId is an item ID */
+ /* or if the job was done (executedMenuId = 0). */
+ fEndMenu = fRemove = (executedMenuId != -1);
+ }
+ /* No menu was selected by the mouse */
+ /* if the function was called by TrackPopupMenu, continue
+ with the menu tracking. If not, stop it */
+ else
+ fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
+
+ break;
+
+ case WM_MOUSEMOVE:
+ /* the selected menu item must be changed every time */
+ /* the mouse moves. */
+
+ if (hmenu)
+ fEndMenu |= !MenuMouseMove( &mt, hmenu, wFlags );
+
+ } /* switch(msg.message) - mouse */
+ }
+ else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
+ {
+ fRemove = TRUE; /* Keyboard messages are always removed */
+ switch(msg.message)
+ {
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ switch(msg.wParam)
+ {
+ case VK_MENU:
+ case VK_F10:
+ fEndMenu = TRUE;
+ break;
+
+ case VK_HOME:
+ case VK_END:
+ if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu))
+ {
- MenuMoveSelection(mt.OwnerWnd, &MenuInfo,
- (msg.wParam == VK_UP)? ITEM_PREV : ITEM_NEXT );
++ MenuSelectItem(mt.OwnerWnd, &MenuInfo, NO_SELECTED_ITEM, FALSE, 0 );
++ MenuMoveSelection(mt.OwnerWnd, &MenuInfo, VK_HOME == msg.wParam ? ITEM_NEXT : ITEM_PREV);
+ }
+ break;
+
+ case VK_UP:
+ case VK_DOWN: /* If on menu bar, pull-down the menu */
+ if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu))
+ {
+ if (!(MenuInfo.fFlags & MNF_POPUP))
+ {
+ if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu))
+ mt.CurrentMenu = MenuShowSubPopup(mt.OwnerWnd, &MenuInfo, TRUE, wFlags);
+ }
+ else /* otherwise try to move selection */
- pos = MenuFindItemByKey(mt.OwnerWnd, &MenuInfo,
- LOWORD(msg.wParam), FALSE);
++ MenuMoveSelection(mt.OwnerWnd, &MenuInfo, (msg.wParam == VK_UP)? ITEM_PREV : ITEM_NEXT );
+ }
+ break;
+
+ case VK_LEFT:
+ MenuKeyLeft( &mt, wFlags );
+ break;
+
+ case VK_RIGHT:
+ MenuKeyRight( &mt, wFlags );
+ break;
+
+ case VK_ESCAPE:
+ fEndMenu = MenuKeyEscape(&mt, wFlags);
+ break;
+
+ case VK_F1:
+ {
+ HELPINFO hi;
+ hi.cbSize = sizeof(HELPINFO);
+ hi.iContextType = HELPINFO_MENUITEM;
+ if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu))
+ {
+ if (MenuInfo.iItem == NO_SELECTED_ITEM)
+ hi.iCtrlId = 0;
+ else
+ {
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (MenuGetRosMenuItemInfo(MenuInfo.Self,
+ MenuInfo.iItem,
+ &ItemInfo))
+ {
+ hi.iCtrlId = ItemInfo.wID;
+ }
+ else
+ {
+ hi.iCtrlId = 0;
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ }
+ }
+ hi.hItemHandle = hmenu;
+ hi.dwContextId = MenuInfo.dwContextHelpID;
+ hi.MousePos = msg.pt;
+ SendMessageW(hwnd, WM_HELP, 0, (LPARAM)&hi);
+ break;
+ }
+
+ default:
+ break;
+ }
+ break; /* WM_KEYDOWN */
+
+ case WM_CHAR:
+ case WM_SYSCHAR:
+ {
+ UINT pos;
+
+ if (! MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) break;
+ if (msg.wParam == L'\r' || msg.wParam == L' ')
+ {
+ executedMenuId = MenuExecFocusedItem(&mt, &MenuInfo, wFlags);
+ fEndMenu = (executedMenuId != -2);
+ break;
+ }
+
+ /* Hack to avoid control chars. */
+ /* We will find a better way real soon... */
+ if (msg.wParam < 32) break;
+
- MenuSelectItem(mt.OwnerWnd, &MenuInfo, pos,
- TRUE, 0);
++ pos = MENU_FindItemByKey(mt.OwnerWnd, mt.CurrentMenu, LOWORD(msg.wParam), FALSE);
+ if (pos == (UINT)-2) fEndMenu = TRUE;
+ else if (pos == (UINT)-1) MessageBeep(0);
+ else
+ {
- if (MenuGetRosMenuInfo(&MenuInfo, hMenu))
++ MenuSelectItem(mt.OwnerWnd, &MenuInfo, pos, TRUE, 0);
+ executedMenuId = MenuExecFocusedItem(&mt, &MenuInfo, wFlags);
+ fEndMenu = (executedMenuId != -2);
+ }
+ }
+ break;
+ } /* switch(msg.message) - kbd */
+ }
+ else
+ {
+ PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
+ DispatchMessageW( &msg );
+ continue;
+ }
+
+ if (!fEndMenu) fRemove = TRUE;
+
+ /* finally remove message from the queue */
+
+ if (fRemove && !(mt.TrackFlags & TF_SKIPREMOVE) )
+ PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
+ else mt.TrackFlags &= ~TF_SKIPREMOVE;
+ }
+
+ NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER, NULL);
+ SetCapture(NULL); /* release the capture */
+
+ /* If dropdown is still painted and the close box is clicked on
+ then the menu will be destroyed as part of the DispatchMessage above.
+ This will then invalidate the menu handle in mt.hTopMenu. We should
+ check for this first. */
+ if( IsMenu( mt.TopMenu ) )
+ {
+ if (IsWindow(mt.OwnerWnd))
+ {
+ if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu))
+ {
+ MenuHideSubPopups(mt.OwnerWnd, &MenuInfo, FALSE, wFlags);
+
+ if (MenuInfo.fFlags & MNF_POPUP)
+ {
+ IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND, MenuInfo.Wnd, OBJID_CLIENT, CHILDID_SELF, 0);
+ DestroyWindow(MenuInfo.Wnd);
+ MenuInfo.Wnd = NULL;
++ MenuSetRosMenuInfo(&MenuInfo);
+
+ if (!(wFlags & TPM_NONOTIFY))
+ SendMessageW( mt.OwnerWnd, WM_UNINITMENUPOPUP, (WPARAM)mt.TopMenu,
+ MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo)) );
+ }
+ MenuSelectItem( mt.OwnerWnd, &MenuInfo, NO_SELECTED_ITEM, FALSE, 0 );
+ }
+
+ SendMessageW( mt.OwnerWnd, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0 );
+ }
+
+ /* Reset the variable for hiding menu */
+ if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu))
+ {
+ MenuInfo.TimeToHide = FALSE;
+ MenuSetRosMenuInfo(&MenuInfo);
+ }
+ }
+
+ /* The return value is only used by TrackPopupMenu */
+ if (!(wFlags & TPM_RETURNCMD)) return TRUE;
+ if (executedMenuId == -1) executedMenuId = 0;
+ return executedMenuId;
+}
+
+/***********************************************************************
+ * MenuInitTracking
+ */
+static BOOL FASTCALL MenuInitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
+{
+ ROSMENUINFO MenuInfo;
+
+ TRACE("hwnd=%p hmenu=%p\n", hWnd, hMenu);
+
+ HideCaret(0);
+
+ /* This makes the menus of applications built with Delphi work.
+ * It also enables menus to be displayed in more than one window,
+ * but there are some bugs left that need to be fixed in this case.
+ */
-
++ if (!bPopup && (MenuGetRosMenuInfo(&MenuInfo, hMenu)))
+ {
+ MenuInfo.Wnd = hWnd;
+ MenuSetRosMenuInfo(&MenuInfo);
+ }
++ //if (!bPopup) menu->hWnd = hWnd;
++ if (!top_popup)
++ {
++ top_popup = MenuInfo.Wnd;//menu->hWnd;
++ top_popup_hmenu = hMenu;
++ }
++
++ fEndMenu = FALSE;
+
+ /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
+ if (!(wFlags & TPM_NONOTIFY))
+ SendMessageW( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
+
+ SendMessageW( hWnd, WM_SETCURSOR, (WPARAM)hWnd, HTCAPTION );
+
+ if (!(wFlags & TPM_NONOTIFY))
+ {
+ SendMessageW( hWnd, WM_INITMENU, (WPARAM)hMenu, 0 );
+ /* If an app changed/recreated menu bar entries in WM_INITMENU
+ * menu sizes will be recalculated once the menu created/shown.
+ */
+
+ if (!MenuInfo.cyMenu)
+ {
+ /* app changed/recreated menu bar entries in WM_INITMENU
+ Recalculate menu sizes else clicks will not work */
+ SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
+
+ }
+ }
+
+ IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART,
+ hWnd,
+ MenuInfo.fFlags & MNF_SYSDESKMN ? OBJID_SYSMENU : OBJID_MENU,
+ CHILDID_SELF, 0);
+ return TRUE;
+}
++
+/***********************************************************************
+ * MenuExitTracking
+ */
+static BOOL FASTCALL MenuExitTracking(HWND hWnd, BOOL bPopup)
+{
+ TRACE("hwnd=%p\n", hWnd);
+
+ IntNotifyWinEvent( EVENT_SYSTEM_MENUEND, hWnd, OBJID_WINDOW, CHILDID_SELF, 0);
+ SendMessageW( hWnd, WM_EXITMENULOOP, bPopup, 0 );
+ ShowCaret(0);
+ top_popup = 0;
+ top_popup_hmenu = NULL;
+ return TRUE;
+}
+
+/***********************************************************************
+ * MenuTrackMouseMenuBar
+ *
+ * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
+ */
+VOID MenuTrackMouseMenuBar( HWND hWnd, ULONG ht, POINT pt)
+{
+ HMENU hMenu = (ht == HTSYSMENU) ? NtUserGetSystemMenu( hWnd, FALSE) : GetMenu(hWnd);
+ UINT wFlags = TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
+
+ TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd, ht, pt.x, pt.y);
+
+ if (GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL) wFlags |= TPM_LAYOUTRTL;
+ if (IsMenu(hMenu))
+ {
+ /* map point to parent client coordinates */
+ HWND Parent = GetAncestor(hWnd, GA_PARENT );
+ if (Parent != GetDesktopWindow())
+ {
+ ScreenToClient(Parent, &pt);
+ }
+
+ MenuInitTracking(hWnd, hMenu, FALSE, wFlags);
+ MenuTrackMenu(hMenu, wFlags, pt.x, pt.y, hWnd, NULL);
+ MenuExitTracking(hWnd, FALSE);
+ }
+}
+
- uItem = MenuFindItemByKey( hwnd, &MenuInfo, wChar, (wParam & HTSYSMENU) );
+/***********************************************************************
+ * MenuTrackKbdMenuBar
+ *
+ * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
+ */
+VOID MenuTrackKbdMenuBar(HWND hwnd, UINT wParam, WCHAR wChar)
+{
+ UINT uItem = NO_SELECTED_ITEM;
+ HMENU hTrackMenu;
+ ROSMENUINFO MenuInfo;
+ UINT wFlags = TPM_LEFTALIGN | TPM_LEFTBUTTON;
+
+ TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd, wParam, wChar);
+
+ /* find window that has a menu */
+
+ while (!((GetWindowLongPtrW( hwnd, GWL_STYLE ) &
+ (WS_CHILD | WS_POPUP)) != WS_CHILD))
+ if (!(hwnd = GetAncestor( hwnd, GA_PARENT ))) return;
+
+ /* check if we have to track a system menu */
+
+ hTrackMenu = GetMenu( hwnd );
+ if (!hTrackMenu || IsIconic(hwnd) || wChar == ' ' )
+ {
+ if (!(GetWindowLongPtrW( hwnd, GWL_STYLE ) & WS_SYSMENU)) return;
+ hTrackMenu = NtUserGetSystemMenu(hwnd, FALSE);
+ uItem = 0;
+ wParam |= HTSYSMENU; /* prevent item lookup */
+ }
+
+ if (!IsMenu( hTrackMenu )) return;
+
+ MenuInitTracking( hwnd, hTrackMenu, FALSE, wFlags );
+
++ /* fetch the window menu again, it may have changed */
++ hTrackMenu = (wParam & HTSYSMENU) ? get_win_sys_menu( hwnd ) : GetMenu( hwnd );
++
+ if (! MenuGetRosMenuInfo(&MenuInfo, hTrackMenu))
+ {
+ goto track_menu;
+ }
+
+ if( wChar && wChar != ' ' )
+ {
- BOOL WINAPI TrackPopupMenuEx( HMENU Menu, UINT Flags, int x, int y,
- HWND Wnd, LPTPMPARAMS Tpm)
++ uItem = MENU_FindItemByKey( hwnd, hTrackMenu, wChar, (wParam & HTSYSMENU) );
+ if ( uItem >= (UINT)(-2) )
+ {
+ if( uItem == (UINT)(-1) ) MessageBeep(0);
+ /* schedule end of menu tracking */
+ wFlags |= TF_ENDMENU;
+ goto track_menu;
+ }
+ }
+
+ MenuSelectItem( hwnd, &MenuInfo, uItem, TRUE, 0 );
+
+ if (!(wParam & HTSYSMENU) || wChar == ' ')
+ {
+ if( uItem == NO_SELECTED_ITEM )
+ MenuMoveSelection( hwnd, &MenuInfo, ITEM_NEXT );
+ else
+ PostMessageW( hwnd, WM_KEYDOWN, VK_RETURN, 0 );
+ }
+
+track_menu:
+ MenuTrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL );
+ MenuExitTracking( hwnd, FALSE );
+}
+
+/**********************************************************************
+ * TrackPopupMenuEx (USER32.@)
+ */
- ROSMENUINFO MenuInfo;
++BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, int x, int y,
++ HWND hWnd, LPTPMPARAMS lpTpm)
+{
+ BOOL ret = FALSE;
- if (!IsMenu(Menu))
++ MENU *menu;
++
++ TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p rect %s\n",
++ hMenu, wFlags, x, y, hWnd, lpTpm,
++ lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" );
+
- /* ReactOS Check */
- if (!ValidateHwnd(Wnd))
- {
- /* invalid window see wine menu.c test_menu_trackpopupmenu line 3146 */
- return FALSE;
- }
-
- MenuGetRosMenuInfo(&MenuInfo, Menu);
- if (IsWindow(MenuInfo.Wnd))
++ /* Parameter check */
++ /* FIXME: this check is performed several times, here and in the called
++ functions. That could be optimized */
++ if (!(menu = MENU_GetMenu( hMenu )))
+ {
+ SetLastError( ERROR_INVALID_MENU_HANDLE );
+ return FALSE;
+ }
+
- MenuInitTracking(Wnd, Menu, TRUE, Flags);
++ if (IsWindow(menu->hWnd))
+ {
+ SetLastError( ERROR_POPUP_ALREADY_ACTIVE );
+ return FALSE;
+ }
+
- /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
- if (!(Flags & TPM_NONOTIFY))
- SendMessageW(Wnd, WM_INITMENUPOPUP, (WPARAM) Menu, 0);
++ if (MENU_InitPopup( hWnd, hMenu, wFlags ))
++ {
++ MenuInitTracking(hWnd, hMenu, TRUE, wFlags);
++
++ /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
++ if (!(wFlags & TPM_NONOTIFY))
++ SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM) hMenu, 0);
+
- if (MenuShowPopup(Wnd, Menu, 0, Flags, x, y, 0, 0 ))
- ret = MenuTrackMenu(Menu, Flags | TPM_POPUPMENU, 0, 0, Wnd,
- Tpm ? &Tpm->rcExclude : NULL);
- MenuExitTracking(Wnd, TRUE);
++ if (MenuShowPopup(hWnd, hMenu, 0, wFlags, x, y, 0, 0 ))
++ ret = MenuTrackMenu(hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd,
++ lpTpm ? &lpTpm->rcExclude : NULL);
++ MenuExitTracking(hWnd, TRUE);
+
- /*
- * From MSDN:
- * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
- * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
- *
- * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
- *
- * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
- * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
- * MFT_STRING is replaced by MIIM_STRING.
- * (So, I guess we should use MIIM_STRING only for strings?)
- *
- * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
- *
- * Based on wine, SetMenuItemInfo_common:
- * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
- * it will result in a error.
- * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
- * These conditions are addressed in Win32k IntSetMenuItemInfo.
++ if (menu->hWnd)
++ {
++ ROSMENUINFO MenuInfo;
++ if (IsWindow( menu->hWnd )) // wine hack around this with their destroy function.
++ DestroyWindow( menu->hWnd ); // Fix wrong error return.
++ //menu->hWnd = 0;
++ MenuGetRosMenuInfo(&MenuInfo, menu->head.h);
++ MenuInfo.Wnd = 0;
++ MenuSetRosMenuInfo(&MenuInfo);
++
++ if (!(wFlags & TPM_NONOTIFY))
++ SendMessageW( hWnd, WM_UNINITMENUPOPUP, (WPARAM)hMenu,
++ MAKELPARAM(0, IS_SYSTEM_MENU(menu)) );
++ }
++ }
+ return ret;
+}
+
+/**********************************************************************
+ * TrackPopupMenu (USER32.@)
+ */
+BOOL WINAPI TrackPopupMenu( HMENU Menu, UINT Flags, int x, int y,
+ int Reserved, HWND Wnd, CONST RECT *Rect)
+{
+ return TrackPopupMenuEx( Menu, Flags, x, y, Wnd, NULL);
+}
+
- static
- BOOL
- FASTCALL
- MenuSetItemData(
- LPMENUITEMINFOW mii,
- UINT Flags,
- UINT_PTR IDNewItem,
- LPCWSTR NewItem,
- BOOL Unicode)
++/**********************************************************************
++ * MENU_mnu2mnuii
+ *
++ * Uses flags, id and text ptr, passed by InsertMenu() and
++ * ModifyMenu() to setup a MenuItemInfo structure.
+ */
- /*
- * Let us assume MIIM_FTYPE is set and building a new menu item structure.
- */
- if(Flags & MF_BITMAP)
- {
- mii->fMask |= MIIM_BITMAP; /* Use the new way of seting hbmpItem.*/
- mii->hbmpItem = (HBITMAP) NewItem;
-
- if (Flags & MF_HELP)
- {
- /* increase ident */
- mii->fType |= MF_HELP;
- }
- }
- else if(Flags & MF_OWNERDRAW)
- {
- mii->fType |= MFT_OWNERDRAW;
- mii->fMask |= MIIM_DATA;
- mii->dwItemData = (DWORD_PTR) NewItem;
- }
- else if (Flags & MF_SEPARATOR)
- {
- mii->fType |= MFT_SEPARATOR;
- if (!(Flags & (MF_GRAYED|MF_DISABLED)))
- Flags |= MF_GRAYED|MF_DISABLED;
- }
- else /* Default action MF_STRING. */
- {
- /* Item beginning with a backspace is a help item */
- if (NewItem != NULL)
- {
- if (Unicode)
- {
- if (*NewItem == '\b')
- {
- mii->fType |= MF_HELP;
- NewItem++;
- }
- }
- else
- {
- LPCSTR NewItemA = (LPCSTR) NewItem;
- if (*NewItemA == '\b')
- {
- mii->fType |= MF_HELP;
- NewItemA++;
- NewItem = (LPCWSTR) NewItemA;
- }
- }
-
- if (Flags & MF_HELP)
- mii->fType |= MF_HELP;
- mii->fMask |= MIIM_STRING;
- mii->fType |= MFT_STRING; /* Zero */
- mii->dwTypeData = (LPWSTR)NewItem;
- if (Unicode)
- mii->cch = (NULL == NewItem ? 0 : strlenW(NewItem));
- else
- mii->cch = (NULL == NewItem ? 0 : strlen((LPCSTR)NewItem));
- }
- else
- {
- mii->fType |= MFT_SEPARATOR;
- if (!(Flags & (MF_GRAYED|MF_DISABLED)))
- Flags |= MF_GRAYED|MF_DISABLED;
- }
- }
-
- if(Flags & MF_RIGHTJUSTIFY) /* Same as MF_HELP */
- {
- mii->fType |= MFT_RIGHTJUSTIFY;
- }
-
- if(Flags & MF_MENUBREAK)
- {
- mii->fType |= MFT_MENUBREAK;
- }
- else if(Flags & MF_MENUBARBREAK)
- {
- mii->fType |= MFT_MENUBARBREAK;
- }
-
- if(Flags & MF_GRAYED || Flags & MF_DISABLED)
- {
- if (Flags & MF_GRAYED)
- mii->fState |= MF_GRAYED;
-
- if (Flags & MF_DISABLED)
- mii->fState |= MF_DISABLED;
-
- mii->fMask |= MIIM_STATE;
- }
- else if (Flags & MF_HILITE)
- {
- mii->fState |= MF_HILITE;
- mii->fMask |= MIIM_STATE;
- }
- else /* default state */
- {
- mii->fState |= MFS_ENABLED;
- mii->fMask |= MIIM_STATE;
- }
-
- if(Flags & MF_POPUP && IsMenu((HMENU)IDNewItem))
- {
- mii->fMask |= MIIM_SUBMENU;
- mii->hSubMenu = (HMENU)IDNewItem;
- }
- mii->fMask |= MIIM_ID;
- mii->wID = (UINT)IDNewItem;
- return TRUE;
- }
-
- NTSTATUS WINAPI
- User32CallLoadMenuFromKernel(PVOID Arguments, ULONG ArgumentLength)
- {
- PLOADMENU_CALLBACK_ARGUMENTS Common;
- LRESULT Result;
-
- Common = (PLOADMENU_CALLBACK_ARGUMENTS) Arguments;
-
- Result = (LRESULT)LoadMenuW( Common->hModule,
- IS_INTRESOURCE(Common->MenuName[0]) ?
- MAKEINTRESOURCE(Common->MenuName[0]) :
- (LPCWSTR)&Common->MenuName);
-
- return ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS);
++static void MENU_mnu2mnuii( UINT flags, UINT_PTR id, LPCWSTR str, LPMENUITEMINFOW pmii, BOOL Unicode)
+{
- return(InsertMenuA(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem, lpNewItem));
++ RtlZeroMemory( pmii, sizeof( MENUITEMINFOW));
++ pmii->cbSize = sizeof( MENUITEMINFOW);
++ pmii->fMask = MIIM_STATE | MIIM_ID | MIIM_FTYPE;
++ /* setting bitmap clears text and vice versa */
++ if( IS_STRING_ITEM(flags)) {
++ pmii->fMask |= MIIM_STRING | MIIM_BITMAP;
++ if( !str)
++ flags |= MF_SEPARATOR;
++ /* Item beginning with a backspace is a help item */
++ /* FIXME: wrong place, this is only true in win16 */
++ else
++ {
++ if (Unicode)
++ {
++ if (*str == '\b')
++ {
++ flags |= MF_HELP;
++ str++;
++ }
++ }
++ else
++ {
++ LPCSTR NewItemA = (LPCSTR) str;
++ if (*NewItemA == '\b')
++ {
++ flags |= MF_HELP;
++ NewItemA++;
++ str = (LPCWSTR) NewItemA;
++ }
++ TRACE("A cch %d\n",strlen(NewItemA));
++ }
++ }
++ pmii->dwTypeData = (LPWSTR)str;
++ } else if( flags & MFT_BITMAP){
++ pmii->fMask |= MIIM_BITMAP | MIIM_STRING;
++ pmii->hbmpItem = (HBITMAP)str;
++ }
++ if( flags & MF_OWNERDRAW){
++ pmii->fMask |= MIIM_DATA;
++ pmii->dwItemData = (ULONG_PTR) str;
++ }
++ if( flags & MF_POPUP && MENU_GetMenu((HMENU)id)) {
++ pmii->fMask |= MIIM_SUBMENU;
++ pmii->hSubMenu = (HMENU)id;
++ }
++ if( flags & MF_SEPARATOR) flags |= MF_GRAYED | MF_DISABLED;
++ pmii->fState = flags & MENUITEMINFO_STATE_MASK & ~MFS_DEFAULT;
++ pmii->fType = flags & MENUITEMINFO_TYPE_MASK;
++ pmii->wID = (UINT)id;
+}
+
+/**********************************************************************
+ * MENU_NormalizeMenuItemInfoStruct
+ *
+ * Helper for SetMenuItemInfo and InsertMenuItemInfo:
+ * check, copy and extend the MENUITEMINFO struct from the version that the application
+ * supplied to the version used by wine source. */
+static BOOL MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW *pmii_in,
+ MENUITEMINFOW *pmii_out )
+{
+ /* do we recognize the size? */
+ if( !pmii_in || (pmii_in->cbSize != sizeof( MENUITEMINFOW) &&
+ pmii_in->cbSize != sizeof( MENUITEMINFOW) - sizeof( pmii_in->hbmpItem)) ) {
+ SetLastError( ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ /* copy the fields that we have */
+ memcpy( pmii_out, pmii_in, pmii_in->cbSize);
+ /* if the hbmpItem member is missing then extend */
+ if( pmii_in->cbSize != sizeof( MENUITEMINFOW)) {
+ pmii_out->cbSize = sizeof( MENUITEMINFOW);
+ pmii_out->hbmpItem = NULL;
+ }
+ /* test for invalid bit combinations */
+ if( (pmii_out->fMask & MIIM_TYPE &&
+ pmii_out->fMask & (MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) ||
+ (pmii_out->fMask & MIIM_FTYPE && pmii_out->fType & MFT_BITMAP)) {
+ ERR("invalid combination of fMask bits used\n");
+ /* this does not happen on Win9x/ME */
+ SetLastError( ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ /* convert old style (MIIM_TYPE) to the new and keep the old one too */
+ if( pmii_out->fMask & MIIM_TYPE){
+ pmii_out->fMask |= MIIM_FTYPE;
+ if( IS_STRING_ITEM(pmii_out->fType)){
+ pmii_out->fMask |= MIIM_STRING;
+ } else if( (pmii_out->fType) & MFT_BITMAP){
+ pmii_out->fMask |= MIIM_BITMAP;
+ pmii_out->hbmpItem = UlongToHandle(LOWORD(pmii_out->dwTypeData));
+ }
+ }
+ if (pmii_out->fMask & MIIM_FTYPE )
+ {
+ pmii_out->fType &= ~MENUITEMINFO_TYPE_MASK;
+ pmii_out->fType |= pmii_in->fType & MENUITEMINFO_TYPE_MASK;
+ }
+ if (pmii_out->fMask & MIIM_STATE)
+ /* Other menu items having MFS_DEFAULT are not converted
+ to normal items */
+ pmii_out->fState = pmii_in->fState & MENUITEMINFO_STATE_MASK;
+
+ return TRUE;
+}
+
++BOOL
++MenuInit(VOID)
++{
++ NONCLIENTMETRICSW ncm;
++
++ /* get the menu font */
++ if(!hMenuFont || !hMenuFontBold)
++ {
++ ncm.cbSize = sizeof(ncm);
++ if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
++ {
++ ERR("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
++ return FALSE;
++ }
++
++ hMenuFont = CreateFontIndirectW(&ncm.lfMenuFont);
++ if(hMenuFont == NULL)
++ {
++ ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
++ return FALSE;
++ }
++
++ ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
++ hMenuFontBold = CreateFontIndirectW(&ncm.lfMenuFont);
++ if(hMenuFontBold == NULL)
++ {
++ ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
++ DeleteObject(hMenuFont);
++ hMenuFont = NULL;
++ return FALSE;
++ }
++ }
++
++ return TRUE;
++}
++
++VOID
++MenuCleanup(VOID)
++{
++ if (hMenuFont)
++ {
++ DeleteObject(hMenuFont);
++ hMenuFont = NULL;
++ }
++
++ if (hMenuFontBold)
++ {
++ DeleteObject(hMenuFontBold);
++ hMenuFontBold = NULL;
++ }
++}
++
++NTSTATUS WINAPI
++User32LoadSysMenuTemplateForKernel(PVOID Arguments, ULONG ArgumentLength)
++{
++ HMENU hmenu = LoadMenuW(User32Instance, L"SYSMENU");
++ LRESULT Result = (LRESULT)hmenu;
++ MENUINFO menuinfo = {0};
++ MENUITEMINFOW info = {0};
++
++ // removing space for checkboxes from menu
++ menuinfo.cbSize = sizeof(menuinfo);
++ menuinfo.fMask = MIM_STYLE;
++ GetMenuInfo(hmenu, &menuinfo);
++ menuinfo.dwStyle |= MNS_CHECKORBMP; // test_menu_bmp_and_string MNS_CHECKORBMP
++ SetMenuInfo(hmenu, &menuinfo);
++
++ // adding bitmaps to menu items
++ info.cbSize = sizeof(info);
++ info.fMask |= MIIM_BITMAP;
++ info.hbmpItem = HBMMENU_POPUP_MINIMIZE;
++ SetMenuItemInfoW(hmenu, SC_MINIMIZE, FALSE, &info);
++ info.hbmpItem = HBMMENU_POPUP_RESTORE;
++ SetMenuItemInfoW(hmenu, SC_RESTORE, FALSE, &info);
++ info.hbmpItem = HBMMENU_POPUP_MAXIMIZE;
++ SetMenuItemInfoW(hmenu, SC_MAXIMIZE, FALSE, &info);
++ info.hbmpItem = HBMMENU_POPUP_CLOSE;
++ SetMenuItemInfoW(hmenu, SC_CLOSE, FALSE, &info);
++
++ return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
++}
++
++NTSTATUS WINAPI
++User32CallLoadMenuFromKernel(PVOID Arguments, ULONG ArgumentLength)
++{
++ PLOADMENU_CALLBACK_ARGUMENTS Common;
++ LRESULT Result;
++
++ Common = (PLOADMENU_CALLBACK_ARGUMENTS) Arguments;
++
++ Result = (LRESULT)LoadMenuW( Common->hModule,
++ IS_INTRESOURCE(Common->MenuName[0]) ?
++ MAKEINTRESOURCE(Common->MenuName[0]) :
++ (LPCWSTR)&Common->MenuName);
++
++ return ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS);
++}
++
+
+/* FUNCTIONS *****************************************************************/
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+AppendMenuA(HMENU hMenu,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCSTR lpNewItem)
+{
- return(InsertMenuW(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem, lpNewItem));
++ MENUITEMINFOW mii;
++ UNICODE_STRING UnicodeString;
++ BOOL res;
++
++ RtlInitUnicodeString(&UnicodeString, 0);
++
++ MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE);
++
++ /* copy the text string, it wll be one or the other */
++ if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
++ {
++ if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
++ {
++ SetLastError (ERROR_NOT_ENOUGH_MEMORY);
++ return FALSE;
++ }
++ mii.dwTypeData = UnicodeString.Buffer;
++ mii.cch = UnicodeString.Length / sizeof(WCHAR);
++ }
++ else
++ {
++ TRACE("AMA Handle bitmaps\n");
++ }
++ ////// Answer a question, why a -1? To hunt for the end of the item list. Get it, to Append?
++ res = NtUserThunkedMenuItemInfo(hMenu, -1, TRUE, TRUE, &mii, &UnicodeString);
++ if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
++ return res;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+AppendMenuW(HMENU hMenu,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCWSTR lpNewItem)
+{
-
++ MENUITEMINFOW mii;
++ UNICODE_STRING MenuText;
++ BOOL res;
++
++ RtlInitUnicodeString(&MenuText, 0);
++
++ MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE);
++
++ /* copy the text string, it wll be one or the other */
++ if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
++ {
++ RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData);
++ mii.dwTypeData = MenuText.Buffer;
++ mii.cch = MenuText.Length / sizeof(WCHAR);
++ }
++ res = NtUserThunkedMenuItemInfo(hMenu, -1, TRUE, TRUE, &mii, &MenuText);
++ return res;
+}
+
+/*
+ * @implemented
+ */
+DWORD WINAPI
+CheckMenuItem(HMENU hmenu,
+ UINT uIDCheckItem,
+ UINT uCheck)
+{
+ PMENU pMenu;
+ PITEM item;
+ DWORD Ret;
+
+ if (!(pMenu = ValidateHandle(hmenu, TYPE_MENU)))
+ return -1;
+
+ if (!(item = MENU_FindItem( &hmenu, &uIDCheckItem, uCheck ))) return -1;
+
+ Ret = item->fState & MFS_CHECKED;
+ if ( Ret == (uCheck & MFS_CHECKED)) return Ret; // Already Checked...
+
+ return NtUserCheckMenuItem(hmenu, uIDCheckItem, uCheck);
+}
+
- return TRUE;
+/*
+ * @implemented
+ */
+BOOL WINAPI
+CheckMenuRadioItem(HMENU hMenu,
+ UINT first,
+ UINT last,
+ UINT check,
+ UINT bypos)
+{
+ BOOL done = FALSE;
+ UINT i;
+ PITEM mi_first = NULL, mi_check;
+ HMENU m_first, m_check;
+ MENUITEMINFOW mii;
+ mii.cbSize = sizeof( mii);
+
+ for (i = first; i <= last; i++)
+ {
+ UINT pos = i;
+
+ if (!mi_first)
+ {
+ m_first = hMenu;
+ mi_first = MENU_FindItem(&m_first, &pos, bypos);
+ if (!mi_first) continue;
+ mi_check = mi_first;
+ m_check = m_first;
+ }
+ else
+ {
+ m_check = hMenu;
+ mi_check = MENU_FindItem(&m_check, &pos, bypos);
+ if (!mi_check) continue;
+ }
+
+ if (m_first != m_check) continue;
+ if (mi_check->fType == MFT_SEPARATOR) continue;
+
+ if (i == check)
+ {
+ if (!(mi_check->fType & MFT_RADIOCHECK) || !(mi_check->fState & MFS_CHECKED))
+ {
+ mii.fMask = MIIM_FTYPE | MIIM_STATE;
+ mii.fType = (mi_check->fType & MENUITEMINFO_TYPE_MASK) | MFT_RADIOCHECK;
+ mii.fState = (mi_check->fState & MII_STATE_MASK) | MFS_CHECKED;
+ NtUserThunkedMenuItemInfo(m_check, i, bypos, FALSE, &mii, NULL);
+ }
+ done = TRUE;
+ }
+ else
+ {
+ /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
+ if (mi_check->fState & MFS_CHECKED)
+ {
+ mii.fMask = MIIM_STATE;
+ mii.fState = (mi_check->fState & MII_STATE_MASK) & ~MFS_CHECKED;
+ NtUserThunkedMenuItemInfo(m_check, i, bypos, FALSE, &mii, NULL);
+ }
+ }
+ }
+ return done;
+}
+
+/*
+ * @implemented
+ */
+HMENU WINAPI
+CreateMenu(VOID)
+{
+ MenuLoadBitmaps();
+ return NtUserxCreateMenu();
+}
+
+/*
+ * @implemented
+ */
+HMENU WINAPI
+CreatePopupMenu(VOID)
+{
+ MenuLoadBitmaps();
+ return NtUserxCreatePopupMenu();
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+DrawMenuBar(HWND hWnd)
+{
+ return NtUserxDrawMenuBar(hWnd);
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+EnableMenuItem(HMENU hMenu,
+ UINT uIDEnableItem,
+ UINT uEnable)
+{
+ return NtUserEnableMenuItem(hMenu, uIDEnableItem, uEnable);
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+EndMenu(VOID)
+{
+ GUITHREADINFO guii;
+ guii.cbSize = sizeof(GUITHREADINFO);
+ if(GetGUIThreadInfo(GetCurrentThreadId(), &guii) && guii.hwndMenuOwner)
+ {
+ if (!fEndMenu &&
+ top_popup &&
+ guii.hwndMenuOwner != top_popup )
+ {
+ ERR("Capture GUI pti hWnd does not match top_popup!\n");
+ }
+ }
+
+ /* if we are in the menu code, and it is active */
+ if (!fEndMenu && top_popup)
+ {
+ /* terminate the menu handling code */
+ fEndMenu = TRUE;
+
+ /* needs to be posted to wakeup the internal menu handler */
+ /* which will now terminate the menu, in the event that */
+ /* the main window was minimized, or lost focus, so we */
+ /* don't end up with an orphaned menu */
+ PostMessageW( top_popup, WM_CANCELMODE, 0, 0);
+ }
-
++ return fEndMenu;
+}
+
+BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
+ UINT wHilite )
+{
+ ROSMENUINFO MenuInfo;
+ TRACE("(%p, %p, %04x, %04x);\n", hWnd, hMenu, wItemID, wHilite);
+ // Force bits to be set call server side....
+ // This alone works and passes all the menu test_menu_hilitemenuitem tests.
+ if (!NtUserHiliteMenuItem(hWnd, hMenu, wItemID, wHilite)) return FALSE;
+ // Without the above call we fail 3 out of the wine failed todo tests, see CORE-7967
+ // Now redraw menu.
+ if (MenuGetRosMenuInfo(&MenuInfo, hMenu))
+ {
+ if (MenuInfo.iItem == wItemID) return TRUE;
+ MenuHideSubPopups( hWnd, &MenuInfo, FALSE, 0 );
+ MenuSelectItem( hWnd, &MenuInfo, wItemID, TRUE, 0 );
+ }
+ return TRUE; // Always returns TRUE!
+}
+
+/*
+ * @implemented
+ */
+HMENU WINAPI
+GetMenu(HWND hWnd)
+{
+ PWND Wnd = ValidateHwnd(hWnd);
+
+ if (!Wnd)
+ return NULL;
+
+ return UlongToHandle(Wnd->IDMenu);
+}
+
- PMENU pMenu;
- PITEM pItem;
- INT i = 0;
-
- if (!(pMenu = ValidateHandle(hMenu, TYPE_MENU)))
- return -1;
-
- pItem = pMenu->rgItems ? DesktopPtrToUser(pMenu->rgItems) : NULL;
- if ( nPos >= 0 )
- {
- //pItem = &menu->rgItems[nPos]; or pItem[nPos]; after dptu.
- while(pItem) // Do this for now.
- {
- if (i < (INT)pMenu->cItems)
- {
- if ( nPos == i && !pItem->spSubMenu) return pItem->wID;
- }
- pItem = pItem->Next ? DesktopPtrToUser(pItem->Next) : NULL;
- i++;
- }
- }
- return -1;
+/*
+ * @implemented
+ */
+BOOL WINAPI GetMenuBarInfo( HWND hwnd, LONG idObject, LONG idItem, PMENUBARINFO pmbi )
+{
+ BOOL Ret;
+ Ret = NtUserGetMenuBarInfo( hwnd, idObject, idItem, pmbi);
+ // Reason to move to server side!!!!!
+ if (!Ret) return Ret;
+ // EL HAXZO!!!
+ pmbi->fBarFocused = top_popup_hmenu == pmbi->hMenu;
+ if (!idItem)
+ {
+ pmbi->fFocused = pmbi->fBarFocused;
+ }
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+LONG WINAPI
+GetMenuCheckMarkDimensions(VOID)
+{
+ return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK),
+ GetSystemMetrics(SM_CYMENUCHECK)));
+}
+
+/*
+ * @implemented
+ */
+DWORD
+WINAPI
+GetMenuContextHelpId(HMENU hmenu)
+{
+ PMENU pMenu;
+ if ((pMenu = ValidateHandle(hmenu, TYPE_MENU)))
+ return pMenu->dwContextHelpId;
+ return 0;
+}
+
+/*
+ * @implemented
+ */
+UINT WINAPI
+GetMenuDefaultItem(HMENU hMenu,
+ UINT fByPos,
+ UINT gmdiFlags)
+{
+ PMENU pMenu;
+ DWORD gismc = 0;
+ if (!(pMenu = ValidateHandle(hMenu, TYPE_MENU)))
+ return (UINT)-1;
+
+ return IntGetMenuDefaultItem( pMenu, (BOOL)fByPos, gmdiFlags, &gismc);
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+GetMenuInfo(HMENU hmenu,
+ LPMENUINFO lpcmi)
+{
+ PMENU pMenu;
+
+ if (!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO)))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ if (!(pMenu = ValidateHandle(hmenu, TYPE_MENU)))
+ return FALSE;
+
+ if (lpcmi->fMask & MIM_BACKGROUND)
+ lpcmi->hbrBack = pMenu->hbrBack;
+
+ if (lpcmi->fMask & MIM_HELPID)
+ lpcmi->dwContextHelpID = pMenu->dwContextHelpId;
+
+ if (lpcmi->fMask & MIM_MAXHEIGHT)
+ lpcmi->cyMax = pMenu->cyMax;
+
+ if (lpcmi->fMask & MIM_MENUDATA)
+ lpcmi->dwMenuData = pMenu->dwMenuData;
+
+ if (lpcmi->fMask & MIM_STYLE)
+ lpcmi->dwStyle = pMenu->fFlags & MNS_STYLE_MASK;
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+int WINAPI
+GetMenuItemCount(HMENU hmenu)
+{
+ PMENU pMenu;
+ if ((pMenu = ValidateHandle(hmenu, TYPE_MENU)))
+ return pMenu->cItems;
+ return -1;
+}
+
+/*
+ * @implemented
+ */
+UINT WINAPI
+GetMenuItemID(HMENU hMenu,
+ int nPos)
+{
- else return (pSubMenu->cItems << 8) | ((pItem->fState|pItem->fType) & 0xff);
++ ITEM * lpmi;
++ if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) return -1;
++ if (lpmi->spSubMenu) return -1;
++ return lpmi->wID;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+GetMenuItemInfoA(
+ HMENU hmenu,
+ UINT item,
+ BOOL bypos,
+ LPMENUITEMINFOA lpmii)
+{
+ BOOL ret;
+ MENUITEMINFOA mii;
+
+ if( lpmii->cbSize != sizeof( mii) &&
+ lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem))
+ {
+ SetLastError( ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ memcpy( &mii, lpmii, lpmii->cbSize);
+ mii.cbSize = sizeof( mii);
+ ret = GetMenuItemInfo_common (hmenu,
+ item,
+ bypos,
+ (LPMENUITEMINFOW)&mii,
+ FALSE);
+ mii.cbSize = lpmii->cbSize;
+ memcpy( lpmii, &mii, mii.cbSize);
+ return ret;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+GetMenuItemInfoW(
+ HMENU hMenu,
+ UINT Item,
+ BOOL bypos,
+ LPMENUITEMINFOW lpmii)
+{
+ BOOL ret;
+ MENUITEMINFOW mii;
+ if( lpmii->cbSize != sizeof( mii) && lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem))
+ {
+ SetLastError( ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ memcpy( &mii, lpmii, lpmii->cbSize);
+ mii.cbSize = sizeof( mii);
+ ret = GetMenuItemInfo_common (hMenu, Item, bypos, &mii, TRUE);
+ mii.cbSize = lpmii->cbSize;
+ memcpy( lpmii, &mii, mii.cbSize);
+ return ret;
+}
+
+/*
+ * @implemented
+ */
+UINT
+WINAPI
+GetMenuState(
+ HMENU hMenu,
+ UINT uId,
+ UINT uFlags)
+{
+ PITEM pItem;
++ UINT Type = 0;
+ TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu, uId, uFlags);
+ if (!(pItem = MENU_FindItem( &hMenu, &uId, uFlags ))) return -1;
+
++ if (!pItem->Xlpstr && pItem->hbmp) Type = MFT_BITMAP;
++
+ if (pItem->spSubMenu)
+ {
+ PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
+ HMENU hsubmenu = UserHMGetHandle(pSubMenu);
+ if (!IsMenu(hsubmenu)) return (UINT)-1;
- return (pItem->fType | pItem->fState);
++ else return (pSubMenu->cItems << 8) | ((pItem->fState|pItem->fType|Type) & 0xff);
+ }
+ else
- /* MENUITEMINFOA mii;
- memset( &mii, 0, sizeof(mii) );
- mii.dwTypeData = lpString;
- mii.fMask = MIIM_STRING;
- mii.cbSize = sizeof(MENUITEMINFOA);
- mii.cch = nMaxCount;
-
- if(!(GetMenuItemInfoA( hMenu, uIDItem, (BOOL)(MF_BYPOSITION & uFlag),&mii)))
- return 0;
- else
- return mii.cch;
- */
++ return (pItem->fType | pItem->fState | Type);
+}
+
+/*
+ * @implemented
+ */
+int
+WINAPI
+GetMenuStringA(
+ HMENU hMenu,
+ UINT uIDItem,
+ LPSTR lpString,
+ int nMaxCount,
+ UINT uFlag)
+{
- ERR("returning %s\n", lpString);
+ ITEM *item;
+ LPWSTR text;
+ ////// wine Code, seems to be faster.
+ TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, uIDItem, lpString, nMaxCount, uFlag );
+
+ if (lpString && nMaxCount) lpString[0] = '\0';
+
+ if (!(item = MENU_FindItem( &hMenu, &uIDItem, uFlag )))
+ {
+ SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
+ return 0;
+ }
+
+ text = item->Xlpstr ? DesktopPtrToUser(item->Xlpstr) : NULL;
+
+ if (!text) return 0;
+ if (!lpString || !nMaxCount) return WideCharToMultiByte( CP_ACP, 0, text, -1, NULL, 0, NULL, NULL );
+ if (!WideCharToMultiByte( CP_ACP, 0, text, -1, lpString, nMaxCount, NULL, NULL ))
+ lpString[nMaxCount-1] = 0;
- /* MENUITEMINFOW miiW;
- memset( &miiW, 0, sizeof(miiW) );
- miiW.dwTypeData = lpString;
- miiW.fMask = MIIM_STRING | MIIM_FTYPE;
- miiW.fType = MFT_STRING;
- miiW.cbSize = sizeof(MENUITEMINFOW);
- miiW.cch = nMaxCount;
-
- if(!(GetMenuItemInfoW( hMenu, uIDItem, (BOOL)(MF_BYPOSITION & uFlag),&miiW)))
- return 0;
- else
- return miiW.cch;
- */
++ TRACE("A returning %s\n", lpString);
+ return strlen(lpString);
+}
+
+/*
+ * @implemented
+ */
+int
+WINAPI
+GetMenuStringW(
+ HMENU hMenu,
+ UINT uIDItem,
+ LPWSTR lpString,
+ int nMaxCount,
+ UINT uFlag)
+{
- ERR("returning %S\n", lpString);
+ ITEM *item;
+ LPWSTR text;
+
+ TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, uIDItem, lpString, nMaxCount, uFlag );
+
+ if (lpString && nMaxCount) lpString[0] = '\0';
+
+ if (!(item = MENU_FindItem( &hMenu, &uIDItem, uFlag )))
+ {
+ SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
+ return 0;
+ }
+
+ text = item->Xlpstr ? DesktopPtrToUser(item->Xlpstr) : NULL;
+
+ if (!lpString || !nMaxCount) return text ? strlenW(text) : 0;
+ if( !(text))
+ {
+ lpString[0] = 0;
+ return 0;
+ }
+ lstrcpynW( lpString, text, nMaxCount );
- MENUITEMINFOA mii;
- memset( &mii, 0, sizeof(mii) );
- mii.cbSize = sizeof(MENUITEMINFOA);
- mii.fMask = MIIM_FTYPE;
-
- MenuSetItemData((LPMENUITEMINFOW) &mii,
- uFlags,
- uIDNewItem,
- (LPCWSTR) lpNewItem,
- FALSE);
-
- return InsertMenuItemA(hMenu, uPosition, (BOOL)((MF_BYPOSITION & uFlags) > 0), &mii);
++ TRACE("W returning %S\n", lpString);
+ return strlenW(lpString);
+}
+
+/*
+ * @implemented
+ */
+HMENU
+WINAPI
+GetSubMenu(
+ HMENU hMenu,
+ int nPos)
+{
+ PITEM pItem;
+ if (!(pItem = MENU_FindItem( &hMenu, (UINT*)&nPos, MF_BYPOSITION ))) return NULL;
+
+ if (pItem->spSubMenu)
+ {
+ PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
+ HMENU hsubmenu = UserHMGetHandle(pSubMenu);
+ if (IsMenu(hsubmenu)) return hsubmenu;
+ }
+ return NULL;
+}
+
+/*
+ * @implemented
+ */
+HMENU
+WINAPI
+GetSystemMenu(
+ HWND hWnd,
+ BOOL bRevert)
+{
+ HMENU TopMenu;
+
+ TopMenu = NtUserGetSystemMenu(hWnd, bRevert);
+
+ return NULL == TopMenu ? NULL : GetSubMenu(TopMenu, 0);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+InsertMenuA(
+ HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCSTR lpNewItem)
+{
- UnicodeString.Buffer = NULL;
++ MENUITEMINFOW mii;
++ UNICODE_STRING UnicodeString;
++ BOOL res;
++
++ RtlInitUnicodeString(&UnicodeString, 0);
++
++ MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE);
++
++ /* copy the text string, it wll be one or the other */
++ if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
++ {
++ if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
++ {
++ SetLastError (ERROR_NOT_ENOUGH_MEMORY);
++ return FALSE;
++ }
++ mii.dwTypeData = UnicodeString.Buffer;
++ mii.cch = UnicodeString.Length / sizeof(WCHAR);
++ }
++ else
++ {
++ TRACE("Handle bitmaps\n");
++ }
++ res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), TRUE, &mii, &UnicodeString);
++ if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
++ return res;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+InsertMenuItemA(
+ HMENU hMenu,
+ UINT uItem,
+ BOOL fByPosition,
+ LPCMENUITEMINFOA lpmii)
+{
+ MENUITEMINFOW mii;
+ UNICODE_STRING UnicodeString;
+ BOOL res;
+
+ TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii);
+
+ RtlInitUnicodeString(&UnicodeString, 0);
+
+ if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
+
+ /* copy the text string */
+ if (((mii.fMask & MIIM_STRING) ||
+ ((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING)))
+ && mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) )
+ {
+ if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
+ {
+ SetLastError (ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ mii.dwTypeData = UnicodeString.Buffer;
+ mii.cch = UnicodeString.Length / sizeof(WCHAR);
+ }
+ else
+ {
- memset( &mii, 0, sizeof(mii) );
- mii.cbSize = sizeof(MENUITEMINFOW);
- mii.fMask = MIIM_FTYPE;
++ TRACE("Handle bitmaps\n");
+ }
+ res = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, TRUE, &mii, &UnicodeString);
+ if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
+ return res;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+InsertMenuItemW(
+ HMENU hMenu,
+ UINT uItem,
+ BOOL fByPosition,
+ LPCMENUITEMINFOW lpmii)
+{
+ MENUITEMINFOW mii;
+ UNICODE_STRING MenuText;
+ BOOL res = FALSE;
+
+ /* while we could just pass 'lpmii' to win32k, we make a copy so that
+ if a bad user passes bad data, we crash his process instead of the
+ entire kernel */
+
+ TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii);
+
+ RtlInitUnicodeString(&MenuText, 0);
+
+ if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
+
+ /* copy the text string */
+ if (((mii.fMask & MIIM_STRING) ||
+ ((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING)))
+ && mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) )
+ {
+ RtlInitUnicodeString(&MenuText, (PWSTR)lpmii->dwTypeData);
+ mii.dwTypeData = MenuText.Buffer;
+ mii.cch = MenuText.Length / sizeof(WCHAR);
+ }
+ res = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, TRUE, &mii, &MenuText);
+ return res;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+InsertMenuW(
+ HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCWSTR lpNewItem)
+{
+ MENUITEMINFOW mii;
- MenuSetItemData( &mii,
- uFlags,
- uIDNewItem,
- lpNewItem,
- TRUE);
++ UNICODE_STRING MenuText;
++ BOOL res;
+
- return InsertMenuItemW(hMenu, uPosition, (BOOL)((MF_BYPOSITION & uFlags) > 0), &mii);
++ RtlInitUnicodeString(&MenuText, 0);
++
++ MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE);
+
- HMENU hMnu,
++ /* copy the text string, it wll be one or the other */
++ if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
++ {
++ RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData);
++ mii.dwTypeData = MenuText.Buffer;
++ mii.cch = MenuText.Length / sizeof(WCHAR);
++ }
++ res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), TRUE, &mii, &MenuText);
++ return res;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+IsMenu(
+ HMENU Menu)
+{
+ if (ValidateHandle(Menu, TYPE_MENU)) return TRUE;
+ return FALSE;
+}
+
+/*
+ * @implemented
+ */
+HMENU WINAPI
+LoadMenuA(HINSTANCE hInstance,
+ LPCSTR lpMenuName)
+{
+ HANDLE Resource = FindResourceA(hInstance, lpMenuName, MAKEINTRESOURCEA(4));
+ if (Resource == NULL)
+ {
+ return(NULL);
+ }
+ return(LoadMenuIndirectA((PVOID)LoadResource(hInstance, Resource)));
+}
+
+/*
+ * @implemented
+ */
+HMENU WINAPI
+LoadMenuIndirectA(CONST MENUTEMPLATE *lpMenuTemplate)
+{
+ return(LoadMenuIndirectW(lpMenuTemplate));
+}
+
+/*
+ * @implemented
+ */
+HMENU WINAPI
+LoadMenuIndirectW(CONST MENUTEMPLATE *lpMenuTemplate)
+{
+ HMENU hMenu;
+ WORD version, offset;
+ LPCSTR p = (LPCSTR)lpMenuTemplate;
+
+ version = GET_WORD(p);
+ p += sizeof(WORD);
+
+ switch (version)
+ {
+ case 0: /* standard format is version of 0 */
+ offset = GET_WORD(p);
+ p += sizeof(WORD) + offset;
+ if (!(hMenu = CreateMenu())) return 0;
+ if (!MENU_ParseResource(p, hMenu))
+ {
+ DestroyMenu(hMenu);
+ return 0;
+ }
+ return hMenu;
+ case 1: /* extended format is version of 1 */
+ offset = GET_WORD(p);
+ p += sizeof(WORD) + offset;
+ if (!(hMenu = CreateMenu())) return 0;
+ if (!MENUEX_ParseResource(p, hMenu))
+ {
+ DestroyMenu( hMenu );
+ return 0;
+ }
+ return hMenu;
+ default:
+ ERR("Menu template version %d not supported.\n", version);
+ return 0;
+ }
+}
+
+/*
+ * @implemented
+ */
+HMENU WINAPI
+LoadMenuW(HINSTANCE hInstance,
+ LPCWSTR lpMenuName)
+{
+ HANDLE Resource = FindResourceW(hInstance, lpMenuName, RT_MENU);
+ if (Resource == NULL)
+ {
+ return(NULL);
+ }
+ return(LoadMenuIndirectW((PVOID)LoadResource(hInstance, Resource)));
+}
+
+/*
+ * @implemented
+ */
+int
+WINAPI
+MenuItemFromPoint(
+ HWND hWnd,
+ HMENU hMenu,
+ POINT ptScreen)
+{
+ return NtUserMenuItemFromPoint(hWnd, hMenu, ptScreen.x, ptScreen.y);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+ModifyMenuA(
- MENUITEMINFOA mii;
- memset( &mii, 0, sizeof(mii) );
- mii.cbSize = sizeof(MENUITEMINFOA);
- mii.fMask = MIIM_FTYPE;
-
- MenuSetItemData((LPMENUITEMINFOW) &mii,
- uFlags,
- uIDNewItem,
- (LPCWSTR) lpNewItem,
- FALSE);
-
- //if (mii.hSubMenu && (uFlags & MF_POPUP) && (mii.hSubMenu != (HMENU)uIDNewItem))
- // NtUserDestroyMenu( mii.hSubMenu ); /* ModifyMenu() spec */
-
- return SetMenuItemInfoA( hMnu,
- uPosition,
- (BOOL)(MF_BYPOSITION & uFlags),
- &mii);
++ HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCSTR lpNewItem)
+{
- HMENU hMnu,
++ MENUITEMINFOW mii;
++ UNICODE_STRING UnicodeString;
++ BOOL res;
++
++ RtlInitUnicodeString(&UnicodeString, 0);
++
++ MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE);
++
++ /* copy the text string, it wll be one or the other */
++ if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
++ {
++ if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
++ {
++ SetLastError (ERROR_NOT_ENOUGH_MEMORY);
++ return FALSE;
++ }
++ mii.dwTypeData = UnicodeString.Buffer;
++ mii.cch = UnicodeString.Length / sizeof(WCHAR);
++ }
++ else
++ {
++ TRACE("Handle bitmaps\n");
++ }
++ res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), FALSE, &mii, &UnicodeString);
++ if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
++ return res;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+ModifyMenuW(
- memset ( &mii, 0, sizeof(mii) );
- mii.cbSize = sizeof(MENUITEMINFOW);
- mii.fMask = MIIM_FTYPE;
-
- /* Init new data for this menu item */
- MenuSetItemData( &mii,
- uFlags,
- uIDNewItem,
- lpNewItem,
- TRUE);
-
- //if (mii.hSubMenu && (uFlags & MF_POPUP) && (mii.hSubMenu != (HMENU)uIDNewItem))
- // NtUserDestroyMenu( mii.hSubMenu ); /* ModifyMenu() spec */
-
- return SetMenuItemInfoW( hMnu,
- uPosition,
- (BOOL)(MF_BYPOSITION & uFlags),
- &mii);
++ HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCWSTR lpNewItem)
+{
+ MENUITEMINFOW mii;
-
-
++ UNICODE_STRING MenuText;
++ BOOL res;
++
++ RtlInitUnicodeString(&MenuText, 0);
++
++ MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE);
++
++ /* copy the text string, it wll be one or the other */
++ if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
++ {
++ RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData);
++ mii.dwTypeData = MenuText.Buffer;
++ mii.cch = MenuText.Length / sizeof(WCHAR);
++ }
++ else
++ {
++ TRACE("Handle bitmaps\n");
++ }
++ res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), FALSE, &mii, &MenuText);
++ return res;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+SetMenu(HWND hWnd,
+ HMENU hMenu)
+{
+ return NtUserSetMenu(hWnd, hMenu, TRUE);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetMenuInfo(
+ HMENU hmenu,
+ LPCMENUINFO lpcmi)
+{
+ ROSMENUINFO mi;
+ BOOL res = FALSE;
+
+ if (!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO)))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return res;
+ }
+
+ memcpy(&mi, lpcmi, sizeof(MENUINFO));
+ return NtUserThunkedMenuInfo(hmenu, (LPCMENUINFO)&mi);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetMenuItemBitmaps(
+ HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags,
+ HBITMAP hBitmapUnchecked,
+ HBITMAP hBitmapChecked)
+{
+ MENUITEMINFOW uItem;
+ memset ( &uItem, 0, sizeof(uItem) );
+ uItem.cbSize = sizeof(MENUITEMINFOW);
+ uItem.fMask = MIIM_CHECKMARKS;
+ uItem.hbmpUnchecked = hBitmapUnchecked;
+ uItem.hbmpChecked = hBitmapChecked;
+ return SetMenuItemInfoW(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), &uItem);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetMenuItemInfoA(
+ HMENU hmenu,
+ UINT item,
+ BOOL bypos,
+ LPCMENUITEMINFOA lpmii)
+{
+ MENUITEMINFOW mii;
+ UNICODE_STRING UnicodeString;
+ BOOL Ret;
+
+ TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu, item, bypos, lpmii);
+
+ RtlInitUnicodeString(&UnicodeString, 0);
+
+ if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
+/*
+ * MIIM_STRING == good
+ * MIIM_TYPE & MFT_STRING == good
+ * MIIM_STRING & MFT_STRING == good
+ * MIIM_STRING & MFT_OWNERDRAW == good
+ */
+ if (((mii.fMask & MIIM_STRING) ||
+ ((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING)))
+ && mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) )
+ {
+ /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
+ if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
+ {
+ SetLastError (ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ mii.dwTypeData = UnicodeString.Buffer;
+ mii.cch = UnicodeString.Length / sizeof(WCHAR);
+ }
+ else
+ {
+ UnicodeString.Buffer = NULL;
+ }
+ Ret = NtUserThunkedMenuItemInfo(hmenu, item, bypos, FALSE, &mii, &UnicodeString);
+ if (UnicodeString.Buffer != NULL) RtlFreeUnicodeString(&UnicodeString);
+ return Ret;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetMenuItemInfoW(
+ HMENU hMenu,
+ UINT uItem,
+ BOOL fByPosition,
+ LPCMENUITEMINFOW lpmii)
+{
+ MENUITEMINFOW MenuItemInfoW;
+ UNICODE_STRING UnicodeString;
+ BOOL Ret;
+
+ TRACE("hmenu %p, item %u, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii);
+
+ RtlInitUnicodeString(&UnicodeString, 0);
+
+ if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &MenuItemInfoW )) return FALSE;
+
+ if (((MenuItemInfoW.fMask & MIIM_STRING) ||
+ ((MenuItemInfoW.fMask & MIIM_TYPE) &&
+ (MENU_ITEM_TYPE(MenuItemInfoW.fType) == MF_STRING)))
+ && MenuItemInfoW.dwTypeData && !(GdiValidateHandle((HGDIOBJ)MenuItemInfoW.dwTypeData)) )
+ {
+ RtlInitUnicodeString(&UnicodeString, (PCWSTR)MenuItemInfoW.dwTypeData);
+ MenuItemInfoW.cch = strlenW(MenuItemInfoW.dwTypeData);
+ }
+ Ret = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, FALSE, &MenuItemInfoW, &UnicodeString);
+
+ return Ret;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetSystemMenu (
+ HWND hwnd,
+ HMENU hMenu)
+{
+ if(!hwnd)
+ {
+ SetLastError(ERROR_INVALID_WINDOW_HANDLE);
+ return FALSE;
+ }
+ if(!hMenu)
+ {
+ SetLastError(ERROR_INVALID_MENU_HANDLE);
+ return FALSE;
+ }
+ return NtUserSetSystemMenu(hwnd, hMenu);
+}
+
+//
+// Example for the Win32/User32 rewrite.
+// Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
+//
+//
+BOOL
+WINAPI
+NEWTrackPopupMenu(
+ HMENU Menu,
+ UINT Flags,
+ int x,
+ int y,
+ int Reserved,
+ HWND Wnd,
+ CONST RECT *Rect)
+{
+ return NtUserTrackPopupMenuEx( Menu,
+ Flags,
+ x,
+ y,
+ Wnd,
+ NULL); // LPTPMPARAMS is null
+}
+
-
+/*
+ * @unimplemented
+ */
+BOOL
+WINAPI
+MenuWindowProcA(
+ HWND hWnd,
+ ULONG_PTR Result,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ if ( Msg < WM_USER)
+ {
+ LRESULT lResult;
+ lResult = PopupMenuWndProcA(hWnd, Msg, wParam, lParam );
+ if (Result)
+ {
+ Result = (ULONG_PTR)lResult;
+ return TRUE;
+ }
+ return FALSE;
+ }
+ return NtUserMessageCall(hWnd, Msg, wParam, lParam, Result, FNID_MENU, TRUE);
+}
+
+/*
+ * @unimplemented
+ */
+BOOL
+WINAPI
+MenuWindowProcW(
+ HWND hWnd,
+ ULONG_PTR Result,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ if ( Msg < WM_USER)
+ {
+ LRESULT lResult;
+ lResult = PopupMenuWndProcW(hWnd, Msg, wParam, lParam );
+ if (Result)
+ {
+ Result = (ULONG_PTR)lResult;
+ return TRUE;
+ }
+ return FALSE;
+ }
+ return NtUserMessageCall(hWnd, Msg, wParam, lParam, Result, FNID_MENU, FALSE);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+ChangeMenuW(
+ HMENU hMenu,
+ UINT cmd,
+ LPCWSTR lpszNewItem,
+ UINT cmdInsert,
+ UINT flags)
+{
+ /*
+ FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
+ for MF_DELETE. We should check the parameters for all others
+ MF_* actions also (anybody got a doc on ChangeMenu?).
+ */
+
+ switch(flags & (MF_APPEND | MF_DELETE | MF_CHANGE | MF_REMOVE | MF_INSERT))
+ {
+ case MF_APPEND :
+ return AppendMenuW(hMenu, flags &~ MF_APPEND, cmdInsert, lpszNewItem);
+
+ case MF_DELETE :
+ return DeleteMenu(hMenu, cmd, flags &~ MF_DELETE);
+
+ case MF_CHANGE :
+ return ModifyMenuW(hMenu, cmd, flags &~ MF_CHANGE, cmdInsert, lpszNewItem);
+
+ case MF_REMOVE :
+ return RemoveMenu(hMenu, flags & MF_BYPOSITION ? cmd : cmdInsert,
+ flags &~ MF_REMOVE);
+
+ default : /* MF_INSERT */
+ return InsertMenuW(hMenu, cmd, flags, cmdInsert, lpszNewItem);
+ };
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+ChangeMenuA(
+ HMENU hMenu,
+ UINT cmd,
+ LPCSTR lpszNewItem,
+ UINT cmdInsert,
+ UINT flags)
+{
+ /*
+ FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
+ for MF_DELETE. We should check the parameters for all others
+ MF_* actions also (anybody got a doc on ChangeMenu?).
+ */
+
+ switch(flags & (MF_APPEND | MF_DELETE | MF_CHANGE | MF_REMOVE | MF_INSERT))
+ {
+ case MF_APPEND :
+ return AppendMenuA(hMenu, flags &~ MF_APPEND, cmdInsert, lpszNewItem);
+
+ case MF_DELETE :
+ return DeleteMenu(hMenu, cmd, flags &~ MF_DELETE);
+
+ case MF_CHANGE :
+ return ModifyMenuA(hMenu, cmd, flags &~ MF_CHANGE, cmdInsert, lpszNewItem);
+
+ case MF_REMOVE :
+ return RemoveMenu(hMenu, flags & MF_BYPOSITION ? cmd : cmdInsert,
+ flags &~ MF_REMOVE);
+
+ default : /* MF_INSERT */
+ return InsertMenuA(hMenu, cmd, flags, cmdInsert, lpszNewItem);
+ };
+}
+