- Implement DoesUserHavePrivilege, EnablePrivilege, IsUserAdmin,
  MultiByteToUnicode and UnicodeToMultiByte.
- Sort prototypes in setupapi.h and a few function in spec.

diff --git a/dlls/setupapi/misc.c b/dlls/setupapi/misc.c
index dfbe49b..bb7eda1 100644
--- a/dlls/setupapi/misc.c
+++ b/dlls/setupapi/misc.c
@@ -28,6 +28,9 @@
 #include "setupapi.h"
 
 #include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
 
 
 /**************************************************************************
@@ -41,9 +44,9 @@
  * RETURNS
  *     None
  */
-
 VOID WINAPI MyFree(LPVOID lpMem)
 {
+    TRACE("%p\n", lpMem);
     HeapFree(GetProcessHeap(), 0, lpMem);
 }
 
@@ -60,9 +63,9 @@
  *     Success: pointer to allocated memory block
  *     Failure: NULL
  */
-
 LPVOID WINAPI MyMalloc(DWORD dwSize)
 {
+    TRACE("%lu\n", dwSize);
     return HeapAlloc(GetProcessHeap(), 0, dwSize);
 }
 
@@ -85,9 +88,10 @@
  *     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);
 
@@ -110,11 +114,12 @@
  * 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;
@@ -145,7 +150,6 @@
  * NOTES
  *     Use MyFree to release the lpData buffer.
  */
-
 LONG WINAPI QueryRegistryValue(HKEY hKey,
                                LPCWSTR lpValueName,
                                LPBYTE  *lpData,
@@ -154,6 +158,9 @@
 {
     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);
@@ -172,3 +179,282 @@
 
     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)
+        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;
+}