Implement SetupDiGetClassImageIndex, SetupDiGetClassImageList, SetupDiGetClassImageLi...
[reactos.git] / reactos / lib / setupapi / misc.c
index a74ef6f..2d30300 100644 (file)
-/*\r
- * Setupapi miscellaneous functions\r
- *\r
- * Copyright 2005 Eric Kohl\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
- */\r
-\r
-#include <stdarg.h>\r
-\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "wingdi.h"\r
-#include "winuser.h"\r
-#include "winreg.h"\r
-#include "setupapi.h"\r
-\r
-#include "wine/unicode.h"\r
-#include "wine/debug.h"\r
-\r
-#include "setupapi_private.h"\r
-\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(setupapi);\r
-\r
-\r
-/**************************************************************************\r
- * MyFree [SETUPAPI.@]\r
- *\r
- * Frees an allocated memory block from the process heap.\r
- *\r
- * PARAMS\r
- *     lpMem [I] pointer to memory block which will be freed\r
- *\r
- * RETURNS\r
- *     None\r
- */\r
-VOID WINAPI MyFree(LPVOID lpMem)\r
-{\r
-    TRACE("%p\n", lpMem);\r
-    HeapFree(GetProcessHeap(), 0, lpMem);\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * MyMalloc [SETUPAPI.@]\r
- *\r
- * Allocates memory block from the process heap.\r
- *\r
- * PARAMS\r
- *     dwSize [I] size of the allocated memory block\r
- *\r
- * RETURNS\r
- *     Success: pointer to allocated memory block\r
- *     Failure: NULL\r
- */\r
-LPVOID WINAPI MyMalloc(DWORD dwSize)\r
-{\r
-    TRACE("%lu\n", dwSize);\r
-    return HeapAlloc(GetProcessHeap(), 0, dwSize);\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * MyRealloc [SETUPAPI.@]\r
- *\r
- * Changes the size of an allocated memory block or allocates a memory\r
- * block from the process heap.\r
- *\r
- * PARAMS\r
- *     lpSrc  [I] pointer to memory block which will be resized\r
- *     dwSize [I] new size of the memory block\r
- *\r
- * RETURNS\r
- *     Success: pointer to the resized memory block\r
- *     Failure: NULL\r
- *\r
- * NOTES\r
- *     If lpSrc is a NULL-pointer, then MyRealloc allocates a memory\r
- *     block like MyMalloc.\r
- */\r
-LPVOID WINAPI MyRealloc(LPVOID lpSrc, DWORD dwSize)\r
-{\r
-    TRACE("%p %lu\n", lpSrc, dwSize);\r
-\r
-    if (lpSrc == NULL)\r
-        return HeapAlloc(GetProcessHeap(), 0, dwSize);\r
-\r
-    return HeapReAlloc(GetProcessHeap(), 0, lpSrc, dwSize);\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * DuplicateString [SETUPAPI.@]\r
- *\r
- * Duplicates a unicode string.\r
- *\r
- * PARAMS\r
- *     lpSrc  [I] pointer to the unicode string that will be duplicated\r
- *\r
- * RETURNS\r
- *     Success: pointer to the duplicated unicode string\r
- *     Failure: NULL\r
- *\r
- * NOTES\r
- *     Call MyFree() to release the duplicated string.\r
- */\r
-LPWSTR WINAPI DuplicateString(LPCWSTR lpSrc)\r
-{\r
-    LPWSTR lpDst;\r
-\r
-    TRACE("%s\n", debugstr_w(lpSrc));\r
-\r
-    lpDst = MyMalloc((lstrlenW(lpSrc) + 1) * sizeof(WCHAR));\r
-    if (lpDst == NULL)\r
-        return NULL;\r
-\r
-    strcpyW(lpDst, lpSrc);\r
-\r
-    return lpDst;\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * QueryRegistryValue [SETUPAPI.@]\r
- *\r
- * Retrieves value data from the registry and allocates memory for the\r
- * value data.\r
- *\r
- * PARAMS\r
- *     hKey        [I] Handle of the key to query\r
- *     lpValueName [I] Name of value under hkey to query\r
- *     lpData      [O] Destination for the values contents,\r
- *     lpType      [O] Destination for the value type\r
- *     lpcbData    [O] Destination for the size of data\r
- *\r
- * RETURNS\r
- *     Success: ERROR_SUCCESS\r
- *     Failure: Otherwise\r
- *\r
- * NOTES\r
- *     Use MyFree to release the lpData buffer.\r
- */\r
-LONG WINAPI QueryRegistryValue(HKEY hKey,\r
-                               LPCWSTR lpValueName,\r
-                               LPBYTE  *lpData,\r
-                               LPDWORD lpType,\r
-                               LPDWORD lpcbData)\r
-{\r
-    LONG lError;\r
-\r
-    TRACE("%lx %s %p %p %p\n",\r
-          hKey, debugstr_w(lpValueName), lpData, lpType, lpcbData);\r
-\r
-    /* Get required buffer size */\r
-    *lpcbData = 0;\r
-    lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, NULL, lpcbData);\r
-    if (lError != ERROR_SUCCESS)\r
-        return lError;\r
-\r
-    /* Allocate buffer */\r
-    *lpData = MyMalloc(*lpcbData);\r
-    if (*lpData == NULL)\r
-        return ERROR_NOT_ENOUGH_MEMORY;\r
-\r
-    /* Query registry value */\r
-    lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, *lpData, lpcbData);\r
-    if (lError != ERROR_SUCCESS)\r
-        MyFree(*lpData);\r
-\r
-    return lError;\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * IsUserAdmin [SETUPAPI.@]\r
- *\r
- * Checks whether the current user is a member of the Administrators group.\r
- *\r
- * PARAMS\r
- *     None\r
- *\r
- * RETURNS\r
- *     Success: TRUE\r
- *     Failure: FALSE\r
- */\r
-BOOL WINAPI IsUserAdmin(VOID)\r
-{\r
-    SID_IDENTIFIER_AUTHORITY Authority = {SECURITY_NT_AUTHORITY};\r
-    HANDLE hToken;\r
-    DWORD dwSize;\r
-    PTOKEN_GROUPS lpGroups;\r
-    PSID lpSid;\r
-    DWORD i;\r
-    BOOL bResult = FALSE;\r
-\r
-    TRACE("\n");\r
-\r
-    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))\r
-    {\r
-        return FALSE;\r
-    }\r
-\r
-    if (!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize))\r
-    {\r
-        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)\r
-        {\r
-            CloseHandle(hToken);\r
-            return FALSE;\r
-        }\r
-    }\r
-\r
-    lpGroups = MyMalloc(dwSize);\r
-    if (lpGroups == NULL)\r
-    {\r
-        CloseHandle(hToken);\r
-        return FALSE;\r
-    }\r
-\r
-    if (!GetTokenInformation(hToken, TokenGroups, lpGroups, dwSize, &dwSize))\r
-    {\r
-        MyFree(lpGroups);\r
-        CloseHandle(hToken);\r
-        return FALSE;\r
-    }\r
-\r
-    CloseHandle(hToken);\r
-\r
-    if (!AllocateAndInitializeSid(&Authority, 2, SECURITY_BUILTIN_DOMAIN_RID,\r
-                                  DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,\r
-                                  &lpSid))\r
-    {\r
-        MyFree(lpGroups);\r
-        return FALSE;\r
-    }\r
-\r
-    for (i = 0; i < lpGroups->GroupCount; i++)\r
-    {\r
-        if (EqualSid(lpSid, &lpGroups->Groups[i].Sid))\r
-        {\r
-            bResult = TRUE;\r
-            break;\r
-        }\r
-    }\r
-\r
-    FreeSid(lpSid);\r
-    MyFree(lpGroups);\r
-\r
-    return bResult;\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * MultiByteToUnicode [SETUPAPI.@]\r
- *\r
- * Converts a multi-byte string to a Unicode string.\r
- *\r
- * PARAMS\r
- *     lpMultiByteStr  [I] Multi-byte string to be converted\r
- *     uCodePage       [I] Code page\r
- *\r
- * RETURNS\r
- *     Success: pointer to the converted Unicode string\r
- *     Failure: NULL\r
- *\r
- * NOTE\r
- *     Use MyFree to release the returned Unicode string.\r
- */\r
-LPWSTR WINAPI MultiByteToUnicode(LPCSTR lpMultiByteStr, UINT uCodePage)\r
-{\r
-    LPWSTR lpUnicodeStr;\r
-    int nLength;\r
-\r
-    TRACE("%s %lu\n", debugstr_a(lpMultiByteStr), uCodePage);\r
-\r
-    nLength = MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,\r
-                                  -1, NULL, 0);\r
-    if (nLength == 0)\r
-        return NULL;\r
-\r
-    lpUnicodeStr = MyMalloc(nLength * sizeof(WCHAR));\r
-    if (lpUnicodeStr == NULL)\r
-        return NULL;\r
-\r
-    if (!MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,\r
-                             nLength, lpUnicodeStr, nLength))\r
-    {\r
-        MyFree(lpUnicodeStr);\r
-        return NULL;\r
-    }\r
-\r
-    return lpUnicodeStr;\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * UnicodeToMultiByte [SETUPAPI.@]\r
- *\r
- * Converts a Unicode string to a multi-byte string.\r
- *\r
- * PARAMS\r
- *     lpUnicodeStr  [I] Unicode string to be converted\r
- *     uCodePage     [I] Code page\r
- *\r
- * RETURNS\r
- *     Success: pointer to the converted multi-byte string\r
- *     Failure: NULL\r
- *\r
- * NOTE\r
- *     Use MyFree to release the returned multi-byte string.\r
- */\r
-LPSTR WINAPI UnicodeToMultiByte(LPCWSTR lpUnicodeStr, UINT uCodePage)\r
-{\r
-    LPSTR lpMultiByteStr;\r
-    int nLength;\r
-\r
-    TRACE("%s %lu\n", debugstr_w(lpUnicodeStr), uCodePage);\r
-\r
-    nLength = WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,\r
-                                  NULL, 0, NULL, NULL);\r
-    if (nLength == 0)\r
-        return NULL;\r
-\r
-    lpMultiByteStr = MyMalloc(nLength);\r
-    if (lpMultiByteStr == NULL)\r
-        return NULL;\r
-\r
-    if (!WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,\r
-                             lpMultiByteStr, nLength, NULL, NULL))\r
-    {\r
-        MyFree(lpMultiByteStr);\r
-        return NULL;\r
-    }\r
-\r
-    return lpMultiByteStr;\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * DoesUserHavePrivilege [SETUPAPI.@]\r
- *\r
- * Check whether the current user has got a given privilege.\r
- *\r
- * PARAMS\r
- *     lpPrivilegeName  [I] Name of the privilege to be checked\r
- *\r
- * RETURNS\r
- *     Success: TRUE\r
- *     Failure: FALSE\r
- */\r
-BOOL WINAPI DoesUserHavePrivilege(LPCWSTR lpPrivilegeName)\r
-{\r
-    HANDLE hToken;\r
-    DWORD dwSize;\r
-    PTOKEN_PRIVILEGES lpPrivileges;\r
-    LUID PrivilegeLuid;\r
-    DWORD i;\r
-    BOOL bResult = FALSE;\r
-\r
-    TRACE("%s\n", debugstr_w(lpPrivilegeName));\r
-\r
-    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))\r
-        return FALSE;\r
-\r
-    if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize))\r
-    {\r
-        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)\r
-        {\r
-            CloseHandle(hToken);\r
-            return FALSE;\r
-        }\r
-    }\r
-\r
-    lpPrivileges = MyMalloc(dwSize);\r
-    if (lpPrivileges == NULL)\r
-    {\r
-        CloseHandle(hToken);\r
-        return FALSE;\r
-    }\r
-\r
-    if (!GetTokenInformation(hToken, TokenPrivileges, lpPrivileges, dwSize, &dwSize))\r
-    {\r
-        MyFree(lpPrivileges);\r
-        CloseHandle(hToken);\r
-        return FALSE;\r
-    }\r
-\r
-    CloseHandle(hToken);\r
-\r
-    if (!LookupPrivilegeValueW(NULL, lpPrivilegeName, &PrivilegeLuid))\r
-    {\r
-        MyFree(lpPrivileges);\r
-        return FALSE;\r
-    }\r
-\r
-    for (i = 0; i < lpPrivileges->PrivilegeCount; i++)\r
-    {\r
-        if (lpPrivileges->Privileges[i].Luid.HighPart == PrivilegeLuid.HighPart &&\r
-            lpPrivileges->Privileges[i].Luid.LowPart == PrivilegeLuid.LowPart)\r
-        {\r
-            bResult = TRUE;\r
-        }\r
-    }\r
-\r
-    MyFree(lpPrivileges);\r
-\r
-    return bResult;\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * EnablePrivilege [SETUPAPI.@]\r
- *\r
- * Enables or disables one of the current users privileges.\r
- *\r
- * PARAMS\r
- *     lpPrivilegeName  [I] Name of the privilege to be changed\r
- *     bEnable          [I] TRUE: Enables the privilege\r
- *                          FALSE: Disables the privilege\r
- *\r
- * RETURNS\r
- *     Success: TRUE\r
- *     Failure: FALSE\r
- */\r
-BOOL WINAPI EnablePrivilege(LPCWSTR lpPrivilegeName, BOOL bEnable)\r
-{\r
-    TOKEN_PRIVILEGES Privileges;\r
-    HANDLE hToken;\r
-    BOOL bResult;\r
-\r
-    TRACE("%s %s\n", debugstr_w(lpPrivilegeName), bEnable ? "TRUE" : "FALSE");\r
-\r
-    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))\r
-        return FALSE;\r
-\r
-    Privileges.PrivilegeCount = 1;\r
-    Privileges.Privileges[0].Attributes = (bEnable) ? SE_PRIVILEGE_ENABLED : 0;\r
-\r
-    if (!LookupPrivilegeValueW(NULL, lpPrivilegeName,\r
-                               &Privileges.Privileges[0].Luid))\r
-    {\r
-        CloseHandle(hToken);\r
-        return FALSE;\r
-    }\r
-\r
-    bResult = AdjustTokenPrivileges(hToken, FALSE, &Privileges, 0, NULL, NULL);\r
-\r
-    CloseHandle(hToken);\r
-\r
-    return bResult;\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * DelayedMove [SETUPAPI.@]\r
- *\r
- * Moves a file upon the next reboot.\r
- *\r
- * PARAMS\r
- *     lpExistingFileName  [I] Current file name\r
- *     lpNewFileName       [I] New file name\r
- *\r
- * RETURNS\r
- *     Success: TRUE\r
- *     Failure: FALSE\r
- */\r
-BOOL WINAPI DelayedMove(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName)\r
-{\r
-    if (OsVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)\r
-    {\r
-        SetLastError(ERROR_CALL_NOT_IMPLEMENTED);\r
-        return FALSE;\r
-    }\r
-\r
-    return MoveFileExW(lpExistingFileName, lpNewFileName,\r
-                       MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT);\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * FileExists [SETUPAPI.@]\r
- *\r
- * Checks whether a file exists.\r
- *\r
- * PARAMS\r
- *     lpFileName     [I] Name of the file to check\r
- *     lpNewFileName  [O] Optional information about the existing file\r
- *\r
- * RETURNS\r
- *     Success: TRUE\r
- *     Failure: FALSE\r
- */\r
-BOOL WINAPI FileExists(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFileFindData)\r
-{\r
-    WIN32_FIND_DATAW FindData;\r
-    HANDLE hFind;\r
-    UINT uErrorMode;\r
-    DWORD dwError;\r
-\r
-    uErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);\r
-\r
-    hFind = FindFirstFileW(lpFileName, &FindData);\r
-    if (hFind == INVALID_HANDLE_VALUE)\r
-    {\r
-        dwError = GetLastError();\r
-        SetErrorMode(uErrorMode);\r
-        SetLastError(dwError);\r
-        return FALSE;\r
-    }\r
-\r
-    FindClose(hFind);\r
-\r
-    if (lpFileFindData)\r
-        memcpy(lpFileFindData, &FindData, sizeof(WIN32_FIND_DATAW));\r
-\r
-    SetErrorMode(uErrorMode);\r
-\r
-    return TRUE;\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * CaptureStringArg [SETUPAPI.@]\r
- *\r
- * Captures a UNICODE string.\r
- *\r
- * PARAMS\r
- *     lpSrc  [I] UNICODE string to be captured\r
- *     lpDst  [O] Pointer to the captured UNICODE string\r
- *\r
- * RETURNS\r
- *     Success: ERROR_SUCCESS\r
- *     Failure: ERROR_INVALID_PARAMETER\r
- *\r
- * NOTE\r
- *     Call MyFree to release the captured UNICODE string.\r
- */\r
-DWORD WINAPI CaptureStringArg(LPCWSTR pSrc, LPWSTR *pDst)\r
-{\r
-    if (pDst == NULL)\r
-        return ERROR_INVALID_PARAMETER;\r
-\r
-    *pDst = DuplicateString(pSrc);\r
-\r
-    return ERROR_SUCCESS;\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * CaptureAndConvertAnsiArg [SETUPAPI.@]\r
- *\r
- * Captures an ANSI string and converts it to a UNICODE string.\r
- *\r
- * PARAMS\r
- *     lpSrc  [I] ANSI string to be captured\r
- *     lpDst  [O] Pointer to the captured UNICODE string\r
- *\r
- * RETURNS\r
- *     Success: ERROR_SUCCESS\r
- *     Failure: ERROR_INVALID_PARAMETER\r
- *\r
- * NOTE\r
- *     Call MyFree to release the captured UNICODE string.\r
- */\r
-DWORD WINAPI CaptureAndConvertAnsiArg(LPCSTR pSrc, LPWSTR *pDst)\r
-{\r
-    if (pDst == NULL)\r
-        return ERROR_INVALID_PARAMETER;\r
-\r
-    *pDst = MultiByteToUnicode(pSrc, CP_ACP);\r
-\r
-    return ERROR_SUCCESS;\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * OpenAndMapFileForRead [SETUPAPI.@]\r
- *\r
- * Open and map a file to a buffer.\r
- *\r
- * PARAMS\r
- *     lpFileName [I] Name of the file to be opened\r
- *     lpSize     [O] Pointer to the file size\r
- *     lpFile     [0] Pointer to the file handle\r
- *     lpMapping  [0] Pointer to the mapping handle\r
- *     lpBuffer   [0] Pointer to the file buffer\r
- *\r
- * RETURNS\r
- *     Success: ERROR_SUCCESS\r
- *     Failure: Other\r
- *\r
- * NOTE\r
- *     Call UnmapAndCloseFile to release the file.\r
- */\r
-DWORD WINAPI OpenAndMapFileForRead(LPCWSTR lpFileName,\r
-                                   LPDWORD lpSize,\r
-                                   LPHANDLE lpFile,\r
-                                   LPHANDLE lpMapping,\r
-                                   LPVOID *lpBuffer)\r
-{\r
-    DWORD dwError;\r
-\r
-    TRACE("%s %p %p %p %p\n",\r
-          debugstr_w(lpFileName), lpSize, lpFile, lpMapping, lpBuffer);\r
-\r
-    *lpFile = CreateFileW(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL,\r
-                          OPEN_EXISTING, 0, NULL);\r
-    if (*lpFile == INVALID_HANDLE_VALUE)\r
-        return GetLastError();\r
-\r
-    *lpSize = GetFileSize(*lpFile, NULL);\r
-    if (*lpSize == INVALID_FILE_SIZE)\r
-    {\r
-        dwError = GetLastError();\r
-        CloseHandle(*lpFile);\r
-        return dwError;\r
-    }\r
-\r
-    *lpMapping = CreateFileMappingW(*lpFile, NULL, PAGE_READONLY, 0,\r
-                                    *lpSize, NULL);\r
-    if (*lpMapping == NULL)\r
-    {\r
-        dwError = GetLastError();\r
-        CloseHandle(*lpFile);\r
-        return dwError;\r
-    }\r
-\r
-    *lpBuffer = MapViewOfFile(*lpMapping, FILE_MAP_READ, 0, 0, *lpSize);\r
-    if (*lpBuffer == NULL)\r
-    {\r
-        dwError = GetLastError();\r
-        CloseHandle(*lpMapping);\r
-        CloseHandle(*lpFile);\r
-        return dwError;\r
-    }\r
-\r
-    return ERROR_SUCCESS;\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * UnmapAndCloseFile [SETUPAPI.@]\r
- *\r
- * Unmap and close a mapped file.\r
- *\r
- * PARAMS\r
- *     hFile    [I] Handle to the file\r
- *     hMapping [I] Handle to the file mapping\r
- *     lpBuffer [I] Pointer to the file buffer\r
- *\r
- * RETURNS\r
- *     Success: TRUE\r
- *     Failure: FALSE\r
- */\r
-BOOL WINAPI UnmapAndCloseFile(HANDLE hFile, HANDLE hMapping, LPVOID lpBuffer)\r
-{\r
-    TRACE("%x %x %p\n",\r
-          hFile, hMapping, lpBuffer);\r
-\r
-    if (!UnmapViewOfFile(lpBuffer))\r
-        return FALSE;\r
-\r
-    if (!CloseHandle(hMapping))\r
-        return FALSE;\r
-\r
-    if (!CloseHandle(hFile))\r
-        return FALSE;\r
-\r
-    return TRUE;\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * StampFileSecurity [SETUPAPI.@]\r
- *\r
- * Assign a new security descriptor to the given file.\r
- *\r
- * PARAMS\r
- *     lpFileName          [I] Name of the file\r
- *     pSecurityDescriptor [I] New security descriptor\r
- *\r
- * RETURNS\r
- *     Success: ERROR_SUCCESS\r
- *     Failure: other\r
- */\r
-DWORD WINAPI StampFileSecurity(LPCWSTR lpFileName, PSECURITY_DESCRIPTOR pSecurityDescriptor)\r
-{\r
-    TRACE("%s %p\n", debugstr_w(lpFileName), pSecurityDescriptor);\r
-\r
-    if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |\r
-                          GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,\r
-                          pSecurityDescriptor))\r
-        return GetLastError();\r
-\r
-    return ERROR_SUCCESS;\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * TakeOwnershipOfFile [SETUPAPI.@]\r
- *\r
- * Takes the ownership of the given file.\r
- *\r
- * PARAMS\r
- *     lpFileName [I] Name of the file\r
- *\r
- * RETURNS\r
- *     Success: ERROR_SUCCESS\r
- *     Failure: other\r
- */\r
-DWORD WINAPI TakeOwnershipOfFile(LPCWSTR lpFileName)\r
-{\r
-    SECURITY_DESCRIPTOR SecDesc;\r
-    HANDLE hToken = NULL;\r
-    PTOKEN_OWNER pOwner = NULL;\r
-    DWORD dwError;\r
-    DWORD dwSize;\r
-\r
-    TRACE("%s\n", debugstr_w(lpFileName));\r
-\r
-    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))\r
-        return GetLastError();\r
-\r
-    if (!GetTokenInformation(hToken, TokenOwner, NULL, 0, &dwSize))\r
-    {\r
-        goto fail;\r
-    }\r
-\r
-    pOwner = (PTOKEN_OWNER)MyMalloc(dwSize);\r
-    if (pOwner == NULL)\r
-    {\r
-        CloseHandle(hToken);\r
-        return ERROR_NOT_ENOUGH_MEMORY;\r
-    }\r
-\r
-    if (!GetTokenInformation(hToken, TokenOwner, pOwner, dwSize, &dwSize))\r
-    {\r
-        goto fail;\r
-    }\r
-\r
-    if (!InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION))\r
-    {\r
-        goto fail;\r
-    }\r
-\r
-    if (!SetSecurityDescriptorOwner(&SecDesc, pOwner->Owner, FALSE))\r
-    {\r
-        goto fail;\r
-    }\r
-\r
-    if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION, &SecDesc))\r
-    {\r
-        goto fail;\r
-    }\r
-\r
-    MyFree(pOwner);\r
-    CloseHandle(hToken);\r
-\r
-    return ERROR_SUCCESS;\r
-\r
-fail:;\r
-    dwError = GetLastError();\r
-\r
-    if (pOwner != NULL)\r
-        MyFree(pOwner);\r
-\r
-    if (hToken != NULL)\r
-        CloseHandle(hToken);\r
-\r
-    return dwError;\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * RetreiveFileSecurity [SETUPAPI.@]\r
- *\r
- * Retrieve the security descriptor that is associated with the given file.\r
- *\r
- * PARAMS\r
- *     lpFileName [I] Name of the file\r
- *\r
- * RETURNS\r
- *     Success: ERROR_SUCCESS\r
- *     Failure: other\r
- */\r
-DWORD WINAPI RetreiveFileSecurity(LPCWSTR lpFileName,\r
-                                  PSECURITY_DESCRIPTOR *pSecurityDescriptor)\r
-{\r
-    PSECURITY_DESCRIPTOR SecDesc;\r
-    DWORD dwSize = 0x100;\r
-    DWORD dwError;\r
-\r
-    TRACE("%s %p\n", debugstr_w(lpFileName), pSecurityDescriptor);\r
-\r
-    SecDesc = (PSECURITY_DESCRIPTOR)MyMalloc(dwSize);\r
-    if (SecDesc == NULL)\r
-        return ERROR_NOT_ENOUGH_MEMORY;\r
-\r
-    if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |\r
-                         GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,\r
-                         SecDesc, dwSize, &dwSize))\r
-    {\r
-      *pSecurityDescriptor = SecDesc;\r
-      return ERROR_SUCCESS;\r
-    }\r
-\r
-    dwError = GetLastError();\r
-    if (dwError != ERROR_INSUFFICIENT_BUFFER)\r
-    {\r
-        MyFree(SecDesc);\r
-        return dwError;\r
-    }\r
-\r
-    SecDesc = (PSECURITY_DESCRIPTOR)MyRealloc(SecDesc, dwSize);\r
-    if (SecDesc == NULL)\r
-        return ERROR_NOT_ENOUGH_MEMORY;\r
-\r
-    if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |\r
-                         GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,\r
-                         SecDesc, dwSize, &dwSize))\r
-    {\r
-      *pSecurityDescriptor = SecDesc;\r
-      return ERROR_SUCCESS;\r
-    }\r
-\r
-    dwError = GetLastError();\r
-    MyFree(SecDesc);\r
-\r
-    return dwError;\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * AssertFail [SETUPAPI.@]\r
- *\r
- * Display an assertion message.\r
- *\r
- * PARAMS\r
- *     lpFile    [I] File name\r
- *     uLine     [I] Line number\r
- *     lpMessage [I] Assertion message\r
- *\r
- * RETURNS\r
- *     Nothing\r
- */\r
-VOID WINAPI AssertFail(LPSTR lpFile, UINT uLine, LPSTR lpMessage)\r
-{\r
-    CHAR szModule[MAX_PATH];\r
-    CHAR szBuffer[2048];\r
-    LPSTR lpName;\r
-    LPSTR lpBuffer;\r
-\r
-    TRACE("%s %u %s\n", lpFile, uLine, lpMessage);\r
-\r
-    GetModuleFileNameA(hInstance, szModule, MAX_PATH);\r
-    lpName = strrchr(szModule, '\\');\r
-    if (lpName != NULL)\r
-        lpName++;\r
-    else\r
-        lpName = szModule;\r
-\r
-    wsprintfA(szBuffer,\r
-              "Assertion failure at line %u in file %s: %s\n\nCall DebugBreak()?",\r
-              uLine, lpFile, lpMessage);\r
-\r
-    if (MessageBoxA(NULL, szBuffer, lpName, MB_SETFOREGROUND |\r
-                    MB_TASKMODAL | MB_ICONERROR | MB_YESNO) == IDYES)\r
-        DebugBreak();\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * GetSetFileTimestamp [SETUPAPI.@]\r
- *\r
- * Gets or sets a files timestamp.\r
- *\r
- * PARAMS\r
- *     lpFileName       [I]   File name\r
- *     lpCreationTime   [I/O] Creation time\r
- *     lpLastAccessTime [I/O] Last access time\r
- *     lpLastWriteTime  [I/O] Last write time\r
- *     bSetFileTime     [I]   TRUE: Set file times\r
- *                            FALSE: Get file times\r
- *\r
- * RETURNS\r
- *     Success: ERROR_SUCCESS\r
- *     Failure: other\r
- */\r
-DWORD WINAPI GetSetFileTimestamp(LPCWSTR lpFileName,\r
-                                 LPFILETIME lpCreationTime,\r
-                                 LPFILETIME lpLastAccessTime,\r
-                                 LPFILETIME lpLastWriteTime,\r
-                                 BOOLEAN bSetFileTime)\r
-{\r
-    HANDLE hFile;\r
-    BOOLEAN bRet;\r
-    DWORD dwError = ERROR_SUCCESS;\r
-\r
-    TRACE("%s %p %p %p %x\n", debugstr_w(lpFileName), lpCreationTime,\r
-          lpLastAccessTime, lpLastWriteTime, bSetFileTime);\r
-\r
-    hFile = CreateFileW(lpFileName,\r
-                        bSetFileTime ? GENERIC_WRITE : GENERIC_READ,\r
-                        FILE_SHARE_READ | FILE_SHARE_WRITE,\r
-                        NULL,\r
-                        OPEN_EXISTING,\r
-                        0,\r
-                        NULL);\r
-\r
-    if (hFile == INVALID_HANDLE_VALUE)\r
-        return GetLastError();\r
-\r
-    if (bSetFileTime)\r
-        bRet = SetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);\r
-    else\r
-        bRet = GetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);\r
-\r
-    if (bRet == FALSE)\r
-        dwError = GetLastError();\r
-\r
-     CloseHandle(hFile);\r
-\r
-     return dwError;\r
-}\r
+/*
+ * Setupapi miscellaneous functions
+ *
+ * Copyright 2005 Eric Kohl
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "setupapi_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
+
+/**************************************************************************
+ * MyFree [SETUPAPI.@]
+ *
+ * Frees an allocated memory block from the process heap.
+ *
+ * PARAMS
+ *     lpMem [I] pointer to memory block which will be freed
+ *
+ * RETURNS
+ *     None
+ */
+VOID WINAPI MyFree(LPVOID lpMem)
+{
+    TRACE("%p\n", lpMem);
+    HeapFree(GetProcessHeap(), 0, lpMem);
+}
+
+
+/**************************************************************************
+ * MyMalloc [SETUPAPI.@]
+ *
+ * Allocates memory block from the process heap.
+ *
+ * PARAMS
+ *     dwSize [I] size of the allocated memory block
+ *
+ * RETURNS
+ *     Success: pointer to allocated memory block
+ *     Failure: NULL
+ */
+LPVOID WINAPI MyMalloc(DWORD dwSize)
+{
+    TRACE("%lu\n", dwSize);
+    return HeapAlloc(GetProcessHeap(), 0, dwSize);
+}
+
+
+/**************************************************************************
+ * MyRealloc [SETUPAPI.@]
+ *
+ * Changes the size of an allocated memory block or allocates a memory
+ * block from the process heap.
+ *
+ * PARAMS
+ *     lpSrc  [I] pointer to memory block which will be resized
+ *     dwSize [I] new size of the memory block
+ *
+ * RETURNS
+ *     Success: pointer to the resized memory block
+ *     Failure: NULL
+ *
+ * NOTES
+ *     If lpSrc is a NULL-pointer, then MyRealloc allocates a memory
+ *     block like MyMalloc.
+ */
+LPVOID WINAPI MyRealloc(LPVOID lpSrc, DWORD dwSize)
+{
+    TRACE("%p %lu\n", lpSrc, dwSize);
+
+    if (lpSrc == NULL)
+        return HeapAlloc(GetProcessHeap(), 0, dwSize);
+
+    return HeapReAlloc(GetProcessHeap(), 0, lpSrc, dwSize);
+}
+
+
+/**************************************************************************
+ * DuplicateString [SETUPAPI.@]
+ *
+ * Duplicates a unicode string.
+ *
+ * PARAMS
+ *     lpSrc  [I] pointer to the unicode string that will be duplicated
+ *
+ * RETURNS
+ *     Success: pointer to the duplicated unicode string
+ *     Failure: NULL
+ *
+ * NOTES
+ *     Call MyFree() to release the duplicated string.
+ */
+LPWSTR WINAPI DuplicateString(LPCWSTR lpSrc)
+{
+    LPWSTR lpDst;
+
+    TRACE("%s\n", debugstr_w(lpSrc));
+
+    lpDst = MyMalloc((lstrlenW(lpSrc) + 1) * sizeof(WCHAR));
+    if (lpDst == NULL)
+        return NULL;
+
+    strcpyW(lpDst, lpSrc);
+
+    return lpDst;
+}
+
+
+/**************************************************************************
+ * QueryRegistryValue [SETUPAPI.@]
+ *
+ * Retrieves value data from the registry and allocates memory for the
+ * value data.
+ *
+ * PARAMS
+ *     hKey        [I] Handle of the key to query
+ *     lpValueName [I] Name of value under hkey to query
+ *     lpData      [O] Destination for the values contents,
+ *     lpType      [O] Destination for the value type
+ *     lpcbData    [O] Destination for the size of data
+ *
+ * RETURNS
+ *     Success: ERROR_SUCCESS
+ *     Failure: Otherwise
+ *
+ * NOTES
+ *     Use MyFree to release the lpData buffer.
+ */
+LONG WINAPI QueryRegistryValue(HKEY hKey,
+                               LPCWSTR lpValueName,
+                               LPBYTE  *lpData,
+                               LPDWORD lpType,
+                               LPDWORD lpcbData)
+{
+    LONG lError;
+
+    TRACE("%p %s %p %p %p\n",
+          hKey, debugstr_w(lpValueName), lpData, lpType, lpcbData);
+
+    /* Get required buffer size */
+    *lpcbData = 0;
+    lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, NULL, lpcbData);
+    if (lError != ERROR_SUCCESS)
+        return lError;
+
+    /* Allocate buffer */
+    *lpData = MyMalloc(*lpcbData);
+    if (*lpData == NULL)
+        return ERROR_NOT_ENOUGH_MEMORY;
+
+    /* Query registry value */
+    lError = RegQueryValueExW(hKey, lpValueName, 0, lpType, *lpData, lpcbData);
+    if (lError != ERROR_SUCCESS)
+        MyFree(*lpData);
+
+    return lError;
+}
+
+
+/**************************************************************************
+ * IsUserAdmin [SETUPAPI.@]
+ *
+ * Checks whether the current user is a member of the Administrators group.
+ *
+ * PARAMS
+ *     None
+ *
+ * RETURNS
+ *     Success: TRUE
+ *     Failure: FALSE
+ */
+BOOL WINAPI IsUserAdmin(VOID)
+{
+    SID_IDENTIFIER_AUTHORITY Authority = {SECURITY_NT_AUTHORITY};
+    HANDLE hToken;
+    DWORD dwSize;
+    PTOKEN_GROUPS lpGroups;
+    PSID lpSid;
+    DWORD i;
+    BOOL bResult = FALSE;
+
+    TRACE("\n");
+
+    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
+    {
+        return FALSE;
+    }
+
+    if (!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize))
+    {
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+        {
+            CloseHandle(hToken);
+            return FALSE;
+        }
+    }
+
+    lpGroups = MyMalloc(dwSize);
+    if (lpGroups == NULL)
+    {
+        CloseHandle(hToken);
+        return FALSE;
+    }
+
+    if (!GetTokenInformation(hToken, TokenGroups, lpGroups, dwSize, &dwSize))
+    {
+        MyFree(lpGroups);
+        CloseHandle(hToken);
+        return FALSE;
+    }
+
+    CloseHandle(hToken);
+
+    if (!AllocateAndInitializeSid(&Authority, 2, SECURITY_BUILTIN_DOMAIN_RID,
+                                  DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
+                                  &lpSid))
+    {
+        MyFree(lpGroups);
+        return FALSE;
+    }
+
+    for (i = 0; i < lpGroups->GroupCount; i++)
+    {
+        if (EqualSid(lpSid, &lpGroups->Groups[i].Sid))
+        {
+            bResult = TRUE;
+            break;
+        }
+    }
+
+    FreeSid(lpSid);
+    MyFree(lpGroups);
+
+    return bResult;
+}
+
+
+/**************************************************************************
+ * MultiByteToUnicode [SETUPAPI.@]
+ *
+ * Converts a multi-byte string to a Unicode string.
+ *
+ * PARAMS
+ *     lpMultiByteStr  [I] Multi-byte string to be converted
+ *     uCodePage       [I] Code page
+ *
+ * RETURNS
+ *     Success: pointer to the converted Unicode string
+ *     Failure: NULL
+ *
+ * NOTE
+ *     Use MyFree to release the returned Unicode string.
+ */
+LPWSTR WINAPI MultiByteToUnicode(LPCSTR lpMultiByteStr, UINT uCodePage)
+{
+    LPWSTR lpUnicodeStr;
+    int nLength;
+
+    TRACE("%s %d\n", debugstr_a(lpMultiByteStr), uCodePage);
+
+    nLength = MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,
+                                  -1, NULL, 0);
+    if (nLength == 0)
+        return NULL;
+
+    lpUnicodeStr = MyMalloc(nLength * sizeof(WCHAR));
+    if (lpUnicodeStr == NULL)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return NULL;
+    }
+
+    if (!MultiByteToWideChar(uCodePage, 0, lpMultiByteStr,
+                             nLength, lpUnicodeStr, nLength))
+    {
+        MyFree(lpUnicodeStr);
+        return NULL;
+    }
+
+    return lpUnicodeStr;
+}
+
+
+/**************************************************************************
+ * UnicodeToMultiByte [SETUPAPI.@]
+ *
+ * Converts a Unicode string to a multi-byte string.
+ *
+ * PARAMS
+ *     lpUnicodeStr  [I] Unicode string to be converted
+ *     uCodePage     [I] Code page
+ *
+ * RETURNS
+ *     Success: pointer to the converted multi-byte string
+ *     Failure: NULL
+ *
+ * NOTE
+ *     Use MyFree to release the returned multi-byte string.
+ */
+LPSTR WINAPI UnicodeToMultiByte(LPCWSTR lpUnicodeStr, UINT uCodePage)
+{
+    LPSTR lpMultiByteStr;
+    int nLength;
+
+    TRACE("%s %d\n", debugstr_w(lpUnicodeStr), uCodePage);
+
+    nLength = WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,
+                                  NULL, 0, NULL, NULL);
+    if (nLength == 0)
+        return NULL;
+
+    lpMultiByteStr = MyMalloc(nLength);
+    if (lpMultiByteStr == NULL)
+        return NULL;
+
+    if (!WideCharToMultiByte(uCodePage, 0, lpUnicodeStr, -1,
+                             lpMultiByteStr, nLength, NULL, NULL))
+    {
+        MyFree(lpMultiByteStr);
+        return NULL;
+    }
+
+    return lpMultiByteStr;
+}
+
+
+/**************************************************************************
+ * DoesUserHavePrivilege [SETUPAPI.@]
+ *
+ * Check whether the current user has got a given privilege.
+ *
+ * PARAMS
+ *     lpPrivilegeName  [I] Name of the privilege to be checked
+ *
+ * RETURNS
+ *     Success: TRUE
+ *     Failure: FALSE
+ */
+BOOL WINAPI DoesUserHavePrivilege(LPCWSTR lpPrivilegeName)
+{
+    HANDLE hToken;
+    DWORD dwSize;
+    PTOKEN_PRIVILEGES lpPrivileges;
+    LUID PrivilegeLuid;
+    DWORD i;
+    BOOL bResult = FALSE;
+
+    TRACE("%s\n", debugstr_w(lpPrivilegeName));
+
+    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
+        return FALSE;
+
+    if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize))
+    {
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+        {
+            CloseHandle(hToken);
+            return FALSE;
+        }
+    }
+
+    lpPrivileges = MyMalloc(dwSize);
+    if (lpPrivileges == NULL)
+    {
+        CloseHandle(hToken);
+        return FALSE;
+    }
+
+    if (!GetTokenInformation(hToken, TokenPrivileges, lpPrivileges, dwSize, &dwSize))
+    {
+        MyFree(lpPrivileges);
+        CloseHandle(hToken);
+        return FALSE;
+    }
+
+    CloseHandle(hToken);
+
+    if (!LookupPrivilegeValueW(NULL, lpPrivilegeName, &PrivilegeLuid))
+    {
+        MyFree(lpPrivileges);
+        return FALSE;
+    }
+
+    for (i = 0; i < lpPrivileges->PrivilegeCount; i++)
+    {
+        if (lpPrivileges->Privileges[i].Luid.HighPart == PrivilegeLuid.HighPart &&
+            lpPrivileges->Privileges[i].Luid.LowPart == PrivilegeLuid.LowPart)
+        {
+            bResult = TRUE;
+        }
+    }
+
+    MyFree(lpPrivileges);
+
+    return bResult;
+}
+
+
+/**************************************************************************
+ * EnablePrivilege [SETUPAPI.@]
+ *
+ * Enables or disables one of the current users privileges.
+ *
+ * PARAMS
+ *     lpPrivilegeName  [I] Name of the privilege to be changed
+ *     bEnable          [I] TRUE: Enables the privilege
+ *                          FALSE: Disables the privilege
+ *
+ * RETURNS
+ *     Success: TRUE
+ *     Failure: FALSE
+ */
+BOOL WINAPI EnablePrivilege(LPCWSTR lpPrivilegeName, BOOL bEnable)
+{
+    TOKEN_PRIVILEGES Privileges;
+    HANDLE hToken;
+    BOOL bResult;
+
+    TRACE("%s %s\n", debugstr_w(lpPrivilegeName), bEnable ? "TRUE" : "FALSE");
+
+    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
+        return FALSE;
+
+    Privileges.PrivilegeCount = 1;
+    Privileges.Privileges[0].Attributes = (bEnable) ? SE_PRIVILEGE_ENABLED : 0;
+
+    if (!LookupPrivilegeValueW(NULL, lpPrivilegeName,
+                               &Privileges.Privileges[0].Luid))
+    {
+        CloseHandle(hToken);
+        return FALSE;
+    }
+
+    bResult = AdjustTokenPrivileges(hToken, FALSE, &Privileges, 0, NULL, NULL);
+
+    CloseHandle(hToken);
+
+    return bResult;
+}
+
+
+/**************************************************************************
+ * DelayedMove [SETUPAPI.@]
+ *
+ * Moves a file upon the next reboot.
+ *
+ * PARAMS
+ *     lpExistingFileName  [I] Current file name
+ *     lpNewFileName       [I] New file name
+ *
+ * RETURNS
+ *     Success: TRUE
+ *     Failure: FALSE
+ */
+BOOL WINAPI DelayedMove(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName)
+{
+    if (OsVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)
+    {
+        SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+        return FALSE;
+    }
+
+    return MoveFileExW(lpExistingFileName, lpNewFileName,
+                       MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT);
+}
+
+
+/**************************************************************************
+ * FileExists [SETUPAPI.@]
+ *
+ * Checks whether a file exists.
+ *
+ * PARAMS
+ *     lpFileName     [I] Name of the file to check
+ *     lpNewFileName  [O] Optional information about the existing file
+ *
+ * RETURNS
+ *     Success: TRUE
+ *     Failure: FALSE
+ */
+BOOL WINAPI FileExists(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFileFindData)
+{
+    WIN32_FIND_DATAW FindData;
+    HANDLE hFind;
+    UINT uErrorMode;
+    DWORD dwError;
+
+    uErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+
+    hFind = FindFirstFileW(lpFileName, &FindData);
+    if (hFind == INVALID_HANDLE_VALUE)
+    {
+        dwError = GetLastError();
+        SetErrorMode(uErrorMode);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    FindClose(hFind);
+
+    if (lpFileFindData)
+        memcpy(lpFileFindData, &FindData, sizeof(WIN32_FIND_DATAW));
+
+    SetErrorMode(uErrorMode);
+
+    return TRUE;
+}
+
+
+/**************************************************************************
+ * CaptureStringArg [SETUPAPI.@]
+ *
+ * Captures a UNICODE string.
+ *
+ * PARAMS
+ *     lpSrc  [I] UNICODE string to be captured
+ *     lpDst  [O] Pointer to the captured UNICODE string
+ *
+ * RETURNS
+ *     Success: ERROR_SUCCESS
+ *     Failure: ERROR_INVALID_PARAMETER
+ *
+ * NOTE
+ *     Call MyFree to release the captured UNICODE string.
+ */
+DWORD WINAPI CaptureStringArg(LPCWSTR pSrc, LPWSTR *pDst)
+{
+    if (pDst == NULL)
+        return ERROR_INVALID_PARAMETER;
+
+    *pDst = DuplicateString(pSrc);
+
+    return ERROR_SUCCESS;
+}
+
+
+/**************************************************************************
+ * CaptureAndConvertAnsiArg [SETUPAPI.@]
+ *
+ * Captures an ANSI string and converts it to a UNICODE string.
+ *
+ * PARAMS
+ *     lpSrc  [I] ANSI string to be captured
+ *     lpDst  [O] Pointer to the captured UNICODE string
+ *
+ * RETURNS
+ *     Success: ERROR_SUCCESS
+ *     Failure: ERROR_INVALID_PARAMETER
+ *
+ * NOTE
+ *     Call MyFree to release the captured UNICODE string.
+ */
+DWORD WINAPI CaptureAndConvertAnsiArg(LPCSTR pSrc, LPWSTR *pDst)
+{
+    if (pDst == NULL)
+        return ERROR_INVALID_PARAMETER;
+
+    *pDst = MultiByteToUnicode(pSrc, CP_ACP);
+
+    return ERROR_SUCCESS;
+}
+
+
+/**************************************************************************
+ * OpenAndMapFileForRead [SETUPAPI.@]
+ *
+ * Open and map a file to a buffer.
+ *
+ * PARAMS
+ *     lpFileName [I] Name of the file to be opened
+ *     lpSize     [O] Pointer to the file size
+ *     lpFile     [0] Pointer to the file handle
+ *     lpMapping  [0] Pointer to the mapping handle
+ *     lpBuffer   [0] Pointer to the file buffer
+ *
+ * RETURNS
+ *     Success: ERROR_SUCCESS
+ *     Failure: Other
+ *
+ * NOTE
+ *     Call UnmapAndCloseFile to release the file.
+ */
+DWORD WINAPI OpenAndMapFileForRead(LPCWSTR lpFileName,
+                                   LPDWORD lpSize,
+                                   LPHANDLE lpFile,
+                                   LPHANDLE lpMapping,
+                                   LPVOID *lpBuffer)
+{
+    DWORD dwError;
+
+    TRACE("%s %p %p %p %p\n",
+          debugstr_w(lpFileName), lpSize, lpFile, lpMapping, lpBuffer);
+
+    *lpFile = CreateFileW(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
+                          OPEN_EXISTING, 0, NULL);
+    if (*lpFile == INVALID_HANDLE_VALUE)
+        return GetLastError();
+
+    *lpSize = GetFileSize(*lpFile, NULL);
+    if (*lpSize == INVALID_FILE_SIZE)
+    {
+        dwError = GetLastError();
+        CloseHandle(*lpFile);
+        return dwError;
+    }
+
+    *lpMapping = CreateFileMappingW(*lpFile, NULL, PAGE_READONLY, 0,
+                                    *lpSize, NULL);
+    if (*lpMapping == NULL)
+    {
+        dwError = GetLastError();
+        CloseHandle(*lpFile);
+        return dwError;
+    }
+
+    *lpBuffer = MapViewOfFile(*lpMapping, FILE_MAP_READ, 0, 0, *lpSize);
+    if (*lpBuffer == NULL)
+    {
+        dwError = GetLastError();
+        CloseHandle(*lpMapping);
+        CloseHandle(*lpFile);
+        return dwError;
+    }
+
+    return ERROR_SUCCESS;
+}
+
+
+/**************************************************************************
+ * UnmapAndCloseFile [SETUPAPI.@]
+ *
+ * Unmap and close a mapped file.
+ *
+ * PARAMS
+ *     hFile    [I] Handle to the file
+ *     hMapping [I] Handle to the file mapping
+ *     lpBuffer [I] Pointer to the file buffer
+ *
+ * RETURNS
+ *     Success: TRUE
+ *     Failure: FALSE
+ */
+BOOL WINAPI UnmapAndCloseFile(HANDLE hFile, HANDLE hMapping, LPVOID lpBuffer)
+{
+    TRACE("%p %p %p\n",
+          hFile, hMapping, lpBuffer);
+
+    if (!UnmapViewOfFile(lpBuffer))
+        return FALSE;
+
+    if (!CloseHandle(hMapping))
+        return FALSE;
+
+    if (!CloseHandle(hFile))
+        return FALSE;
+
+    return TRUE;
+}
+
+
+/**************************************************************************
+ * StampFileSecurity [SETUPAPI.@]
+ *
+ * Assign a new security descriptor to the given file.
+ *
+ * PARAMS
+ *     lpFileName          [I] Name of the file
+ *     pSecurityDescriptor [I] New security descriptor
+ *
+ * RETURNS
+ *     Success: ERROR_SUCCESS
+ *     Failure: other
+ */
+DWORD WINAPI StampFileSecurity(LPCWSTR lpFileName, PSECURITY_DESCRIPTOR pSecurityDescriptor)
+{
+    TRACE("%s %p\n", debugstr_w(lpFileName), pSecurityDescriptor);
+
+    if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
+                          GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
+                          pSecurityDescriptor))
+        return GetLastError();
+
+    return ERROR_SUCCESS;
+}
+
+
+/**************************************************************************
+ * TakeOwnershipOfFile [SETUPAPI.@]
+ *
+ * Takes the ownership of the given file.
+ *
+ * PARAMS
+ *     lpFileName [I] Name of the file
+ *
+ * RETURNS
+ *     Success: ERROR_SUCCESS
+ *     Failure: other
+ */
+DWORD WINAPI TakeOwnershipOfFile(LPCWSTR lpFileName)
+{
+    SECURITY_DESCRIPTOR SecDesc;
+    HANDLE hToken = NULL;
+    PTOKEN_OWNER pOwner = NULL;
+    DWORD dwError;
+    DWORD dwSize;
+
+    TRACE("%s\n", debugstr_w(lpFileName));
+
+    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
+        return GetLastError();
+
+    if (!GetTokenInformation(hToken, TokenOwner, NULL, 0, &dwSize))
+    {
+        goto fail;
+    }
+
+    pOwner = (PTOKEN_OWNER)MyMalloc(dwSize);
+    if (pOwner == NULL)
+    {
+        CloseHandle(hToken);
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
+
+    if (!GetTokenInformation(hToken, TokenOwner, pOwner, dwSize, &dwSize))
+    {
+        goto fail;
+    }
+
+    if (!InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION))
+    {
+        goto fail;
+    }
+
+    if (!SetSecurityDescriptorOwner(&SecDesc, pOwner->Owner, FALSE))
+    {
+        goto fail;
+    }
+
+    if (!SetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION, &SecDesc))
+    {
+        goto fail;
+    }
+
+    MyFree(pOwner);
+    CloseHandle(hToken);
+
+    return ERROR_SUCCESS;
+
+fail:;
+    dwError = GetLastError();
+
+    if (pOwner != NULL)
+        MyFree(pOwner);
+
+    if (hToken != NULL)
+        CloseHandle(hToken);
+
+    return dwError;
+}
+
+
+/**************************************************************************
+ * RetreiveFileSecurity [SETUPAPI.@]
+ *
+ * Retrieve the security descriptor that is associated with the given file.
+ *
+ * PARAMS
+ *     lpFileName [I] Name of the file
+ *
+ * RETURNS
+ *     Success: ERROR_SUCCESS
+ *     Failure: other
+ */
+DWORD WINAPI RetreiveFileSecurity(LPCWSTR lpFileName,
+                                  PSECURITY_DESCRIPTOR *pSecurityDescriptor)
+{
+    PSECURITY_DESCRIPTOR SecDesc;
+    DWORD dwSize = 0x100;
+    DWORD dwError;
+
+    TRACE("%s %p\n", debugstr_w(lpFileName), pSecurityDescriptor);
+
+    SecDesc = (PSECURITY_DESCRIPTOR)MyMalloc(dwSize);
+    if (SecDesc == NULL)
+        return ERROR_NOT_ENOUGH_MEMORY;
+
+    if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
+                         GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
+                         SecDesc, dwSize, &dwSize))
+    {
+      *pSecurityDescriptor = SecDesc;
+      return ERROR_SUCCESS;
+    }
+
+    dwError = GetLastError();
+    if (dwError != ERROR_INSUFFICIENT_BUFFER)
+    {
+        MyFree(SecDesc);
+        return dwError;
+    }
+
+    SecDesc = (PSECURITY_DESCRIPTOR)MyRealloc(SecDesc, dwSize);
+    if (SecDesc == NULL)
+        return ERROR_NOT_ENOUGH_MEMORY;
+
+    if (GetFileSecurityW(lpFileName, OWNER_SECURITY_INFORMATION |
+                         GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
+                         SecDesc, dwSize, &dwSize))
+    {
+      *pSecurityDescriptor = SecDesc;
+      return ERROR_SUCCESS;
+    }
+
+    dwError = GetLastError();
+    MyFree(SecDesc);
+
+    return dwError;
+}
+
+
+/**************************************************************************
+ * AssertFail [SETUPAPI.@]
+ *
+ * Display an assertion message.
+ *
+ * PARAMS
+ *     lpFile    [I] File name
+ *     uLine     [I] Line number
+ *     lpMessage [I] Assertion message
+ *
+ * RETURNS
+ *     Nothing
+ */
+VOID WINAPI AssertFail(LPSTR lpFile, UINT uLine, LPSTR lpMessage)
+{
+    CHAR szModule[MAX_PATH];
+    CHAR szBuffer[2048];
+    LPSTR lpName;
+//    LPSTR lpBuffer;
+
+    TRACE("%s %u %s\n", lpFile, uLine, lpMessage);
+
+    GetModuleFileNameA(hInstance, szModule, MAX_PATH);
+    lpName = strrchr(szModule, '\\');
+    if (lpName != NULL)
+        lpName++;
+    else
+        lpName = szModule;
+
+    wsprintfA(szBuffer,
+              "Assertion failure at line %u in file %s: %s\n\nCall DebugBreak()?",
+              uLine, lpFile, lpMessage);
+
+    if (MessageBoxA(NULL, szBuffer, lpName, MB_SETFOREGROUND |
+                    MB_TASKMODAL | MB_ICONERROR | MB_YESNO) == IDYES)
+        DebugBreak();
+}
+
+
+/**************************************************************************
+ * GetSetFileTimestamp [SETUPAPI.@]
+ *
+ * Gets or sets a files timestamp.
+ *
+ * PARAMS
+ *     lpFileName       [I]   File name
+ *     lpCreationTime   [I/O] Creation time
+ *     lpLastAccessTime [I/O] Last access time
+ *     lpLastWriteTime  [I/O] Last write time
+ *     bSetFileTime     [I]   TRUE: Set file times
+ *                            FALSE: Get file times
+ *
+ * RETURNS
+ *     Success: ERROR_SUCCESS
+ *     Failure: other
+ */
+DWORD WINAPI GetSetFileTimestamp(LPCWSTR lpFileName,
+                                 LPFILETIME lpCreationTime,
+                                 LPFILETIME lpLastAccessTime,
+                                 LPFILETIME lpLastWriteTime,
+                                 BOOLEAN bSetFileTime)
+{
+    HANDLE hFile;
+    BOOLEAN bRet;
+    DWORD dwError = ERROR_SUCCESS;
+
+    TRACE("%s %p %p %p %x\n", debugstr_w(lpFileName), lpCreationTime,
+          lpLastAccessTime, lpLastWriteTime, bSetFileTime);
+
+    hFile = CreateFileW(lpFileName,
+                        bSetFileTime ? GENERIC_WRITE : GENERIC_READ,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE,
+                        NULL,
+                        OPEN_EXISTING,
+                        0,
+                        NULL);
+
+    if (hFile == INVALID_HANDLE_VALUE)
+        return GetLastError();
+
+    if (bSetFileTime)
+        bRet = SetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
+    else
+        bRet = GetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
+
+    if (bRet == FALSE)
+        dwError = GetLastError();
+
+     CloseHandle(hFile);
+
+     return dwError;
+}
+
+
+/**************************************************************************
+ * MyGetFileTitle [SETUPAPI.@]
+ *
+ * Returns a pointer to the last part of a fully qualified file name.
+ *
+ * PARAMS
+ *     lpFileName [I] File name
+ *
+ * RETURNS
+ *     Pointer to a files name.
+ */
+LPWSTR WINAPI
+MyGetFileTitle(LPCWSTR lpFileName)
+{
+    LPWSTR ptr;
+    LPWSTR ret;
+    WCHAR c;
+
+    TRACE("%s\n", debugstr_w(lpFileName));
+
+    ptr = (LPWSTR)lpFileName;
+    ret = ptr;
+    while (TRUE)
+    {
+        c = *ptr;
+
+        if (c == 0)
+            break;
+
+        ptr++;
+        if (c == (WCHAR)'\\' || c == (WCHAR)'/' || c == (WCHAR)':')
+            ret = ptr;
+    }
+
+    return ret;
+}
+
+
+/**************************************************************************
+ * ConcatenatePaths [SETUPAPI.@]
+ *
+ * Concatenates two paths.
+ *
+ * PARAMS
+ *     lpPath         [I/O] Path to append path to
+ *     lpAppend       [I]   Path to append
+ *     dwBufferSize   [I]   Size of the path buffer
+ *     lpRequiredSize [O]   Required size for the concatenated path. Optional
+ *
+ * RETURNS
+ *     Success: TRUE
+ *     Failure: FALSE
+ */
+BOOL WINAPI
+ConcatenatePaths(LPWSTR lpPath,
+                 LPCWSTR lpAppend,
+                 DWORD dwBufferSize,
+                 LPDWORD lpRequiredSize)
+{
+    DWORD dwPathSize;
+    DWORD dwAppendSize;
+    DWORD dwTotalSize;
+    BOOL bBackslash = FALSE;
+
+    TRACE("%s %s %lu %p\n", debugstr_w(lpPath), debugstr_w(lpAppend),
+          dwBufferSize, lpRequiredSize);
+
+    dwPathSize = lstrlenW(lpPath);
+
+    /* Ignore trailing backslash */
+    if (lpPath[dwPathSize - 1] == (WCHAR)'\\')
+        dwPathSize--;
+
+    dwAppendSize = lstrlenW(lpAppend);
+
+    /* Does the source string have a leading backslash? */
+    if (lpAppend[0] == (WCHAR)'\\')
+    {
+        bBackslash = TRUE;
+        dwAppendSize--;
+    }
+
+    dwTotalSize = dwPathSize + dwAppendSize + 2;
+    if (lpRequiredSize != NULL)
+        *lpRequiredSize = dwTotalSize;
+
+    /* Append a backslash to the destination string */
+    if (bBackslash == FALSE)
+    {
+        if (dwPathSize < dwBufferSize)
+        {
+            lpPath[dwPathSize - 1] = (WCHAR)'\\';
+            dwPathSize++;
+        }
+    }
+
+    if (dwPathSize + dwAppendSize < dwBufferSize)
+    {
+        lstrcpynW(&lpPath[dwPathSize],
+                  lpAppend,
+                  dwAppendSize);
+    }
+
+    if (dwBufferSize >= dwTotalSize)
+        lpPath[dwTotalSize - 1] = 0;
+
+    return (dwBufferSize >= dwTotalSize);
+}
+
+
+/**************************************************************************
+ * CenterWindowRelativeToParent [SETUPAPI.@]
+ *
+ * Centers a window relative to its parent.
+ *
+ * PARAMS
+ *     hwnd [I] Window to center.
+ *
+ * RETURNS
+ *     None
+ */
+VOID WINAPI
+CenterWindowRelativeToParent(HWND hwnd)
+{
+    HWND hwndOwner;
+    POINT ptOrigin;
+    RECT rcWindow;
+    RECT rcOwner;
+    INT nWindowWidth, nWindowHeight;
+    INT nOwnerWidth, nOwnerHeight;
+    INT posX, posY;
+
+    hwndOwner = GetWindow(hwnd, GW_OWNER);
+    if (hwndOwner == NULL)
+        return;
+
+    ptOrigin.x = 0;
+    ptOrigin.y = 0;
+    ClientToScreen(hwndOwner, &ptOrigin);
+
+    GetWindowRect(hwnd, &rcWindow);
+    GetClientRect(hwndOwner, &rcOwner);
+
+    nWindowWidth = rcWindow.right - rcWindow.left;
+    nWindowHeight = rcWindow.bottom - rcWindow.top;
+
+    nOwnerWidth = rcOwner.right - rcOwner.left;
+    nOwnerHeight = rcOwner.bottom - rcOwner.top;
+
+    posX = ((nOwnerWidth - nWindowWidth) / 2) + ptOrigin.x;
+    posY = ((nOwnerHeight - nWindowHeight) / 2) + ptOrigin.y;
+
+    MoveWindow(hwnd, posX, posY, nWindowHeight, nWindowWidth, 0);
+}
+
+
+/**************************************************************************
+ * GetVersionInfoFromImage [SETUPAPI.@]
+ *
+ * Retrieves version information for a given file.
+ *
+ * PARAMS
+ *     lpFileName       [I] File name
+ *     lpFileVersion    [O] Pointer to the full file version
+ *     lpVersionVarSize [O] Pointer to the size of the variable version
+ *                          information
+ *
+ * RETURNS
+ *     Success: TRUE
+ *     Failure: FALSE
+ */
+BOOL WINAPI
+GetVersionInfoFromImage(LPWSTR lpFileName,
+                        PULARGE_INTEGER lpFileVersion,
+                        LPWORD lpVersionVarSize)
+{
+    DWORD dwHandle;
+    DWORD dwSize;
+    LPVOID lpInfo;
+    UINT uSize;
+    VS_FIXEDFILEINFO *lpFixedInfo;
+    LPWORD lpVarSize;
+
+    dwSize = GetFileVersionInfoSizeW(lpFileName, &dwHandle);
+    if (dwSize == 0)
+        return FALSE;
+
+    lpInfo = MyMalloc(dwSize);
+    if (lpInfo == NULL)
+        return FALSE;
+
+    if (!GetFileVersionInfoW(lpFileName, 0, dwSize, lpInfo))
+    {
+        MyFree(lpInfo);
+        return FALSE;
+    }
+
+    if (!VerQueryValueW(lpInfo, L"\\",
+                        (LPVOID*)&lpFixedInfo, &uSize))
+    {
+        MyFree(lpInfo);
+        return FALSE;
+    }
+
+    lpFileVersion->LowPart = lpFixedInfo->dwFileVersionLS;
+    lpFileVersion->HighPart = lpFixedInfo->dwFileVersionMS;
+
+    *lpVersionVarSize = 0;
+    if (!VerQueryValueW(lpInfo, L"\\VerFileInfo\\Translation",
+                        (LPVOID*)&lpVarSize, &uSize))
+    {
+        MyFree(lpInfo);
+        return TRUE;
+    }
+
+    if (uSize >= 4)
+    {
+        *lpVersionVarSize = *lpVarSize;
+    }
+
+    MyFree(lpInfo);
+
+    return TRUE;
+}