[APPHELP] Implement SdbRegisterDatabase[Ex]
[reactos.git] / dll / appcompat / apphelp / apphelp.c
index ceb71a8..e05c1fd 100644 (file)
 #define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
-#include "winver.h"
+#include "winreg.h"
 #include "strsafe.h"
 #include "apphelp.h"
-#include "ndk/rtlfuncs.h"
-#include "ndk/kdtypes.h"
+#include <ndk/rtlfuncs.h>
+#include <ndk/cmfuncs.h>
+#include <ndk/obfuncs.h>
+#include <ndk/kdtypes.h>
 
 
+ACCESS_MASK Wow64QueryFlag(void);
+
+const UNICODE_STRING InstalledSDBKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\InstalledSDB");
+
 /* from dpfilter.h */
 #define DPFLTR_APPCOMPAT_ID 123
 
+#define MAX_GUID_STRING_LEN     sizeof("{12345678-1234-1234-0123-456789abcdef}")
+
 #ifndef NT_SUCCESS
 #define NT_SUCCESS(StatCode)  ((NTSTATUS)(StatCode) >= 0)
 #endif
 
-ULONG g_ShimDebugLevel = 0xffffffff;
+ULONG g_ShimDebugLevel = ~0;
 HMODULE g_hInstance;
 
 void ApphelppInitDebugLevel(void)
@@ -52,14 +60,14 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
 {
     switch (reason)
     {
-        case DLL_PROCESS_ATTACH:
-            g_hInstance = hinst;
-            DisableThreadLibraryCalls( hinst );
-            SdbpHeapInit();
-            break;
-        case DLL_PROCESS_DETACH:
-            SdbpHeapDeinit();
-            break;
+    case DLL_PROCESS_ATTACH:
+        g_hInstance = hinst;
+        DisableThreadLibraryCalls(hinst);
+        SdbpHeapInit();
+        break;
+    case DLL_PROCESS_DETACH:
+        SdbpHeapDeinit();
+        break;
     }
     return TRUE;
 }
@@ -73,8 +81,8 @@ BOOL WINAPI ApphelpCheckInstallShieldPackage(void* ptr, LPCWSTR path)
 
 BOOL WINAPI ApphelpCheckShellObject(REFCLSID ObjectCLSID, BOOL bShimIfNecessary, ULONGLONG *pullFlags)
 {
-    WCHAR GuidString[100];
-    if (!ObjectCLSID || !SdbGUIDToString(ObjectCLSID, GuidString, 100))
+    WCHAR GuidString[MAX_GUID_STRING_LEN];
+    if (!ObjectCLSID || !SdbGUIDToString(ObjectCLSID, GuidString, RTL_NUMBER_OF(GuidString)))
         GuidString[0] = L'\0';
     SHIM_WARN("stub: ObjectCLSID='%S', bShimIfNecessary=%d, pullFlags=%p)\n", GuidString, bShimIfNecessary, pullFlags);
 
@@ -103,7 +111,7 @@ BOOL WINAPIV ShimDbgPrint(SHIM_LOG_LEVEL Level, PCSTR FunctionName, PCSTR Format
     const char* LevelStr;
     size_t Length = sizeof(Buffer);
 
-    if (g_ShimDebugLevel == 0xffffffff)
+    if (g_ShimDebugLevel == ~0)
         ApphelppInitDebugLevel();
 
     if (Level > g_ShimDebugLevel)
@@ -251,14 +259,124 @@ ApphelpCheckRunAppEx(
  * @return                  TRUE on success, or FALSE on failure.
  */
 BOOL WINAPI SdbRegisterDatabaseEx(
-    _In_ LPCTSTR pszDatabasePath,
+    _In_ LPCWSTR pszDatabasePath,
     _In_ DWORD dwDatabaseType,
-    _In_opt_ PULONGLONG pTimeStamp)
+    _In_opt_ const PULONGLONG pTimeStamp)
 {
-    SHIM_ERR("UNIMPLEMENTED, pszDatabasePath=%ws, dwDatabaseType=0x%x, pTimeStamp=%p\n",
-             pszDatabasePath, dwDatabaseType, pTimeStamp);
+    PDB pdb;
+    DB_INFORMATION Information;
+    WCHAR GuidBuffer[MAX_GUID_STRING_LEN];
+    UNICODE_STRING KeyName;
+    ACCESS_MASK KeyAccess;
+    OBJECT_ATTRIBUTES ObjectKey = RTL_INIT_OBJECT_ATTRIBUTES(&KeyName, OBJ_CASE_INSENSITIVE);
+    NTSTATUS Status;
+    HANDLE InstalledSDBKey;
+
+    pdb = SdbOpenDatabase(pszDatabasePath, DOS_PATH);
+    if (!pdb)
+    {
+        SHIM_ERR("Unable to open DB %S\n", pszDatabasePath);
+        return FALSE;
+    }
+
+    if (!SdbGetDatabaseInformation(pdb, &Information) ||
+        !(Information.dwFlags & DB_INFO_FLAGS_VALID_GUID))
+    {
+        SHIM_ERR("Unable to retrieve DB info\n");
+        SdbCloseDatabase(pdb);
+        return FALSE;
+    }
+
+    if (!SdbGUIDToString(&Information.Id, GuidBuffer, RTL_NUMBER_OF(GuidBuffer)))
+    {
+        SHIM_ERR("Unable to Convert GUID to string\n");
+        SdbFreeDatabaseInformation(&Information);
+        SdbCloseDatabase(pdb);
+        return FALSE;
+    }
+
+    KeyName = InstalledSDBKeyName;
+    KeyAccess = Wow64QueryFlag() | KEY_WRITE | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS;
+    Status = NtCreateKey(&InstalledSDBKey, KeyAccess, &ObjectKey, 0, NULL, 0, NULL);
+    if (NT_SUCCESS(Status))
+    {
+        HANDLE DbKey;
+
+        RtlInitUnicodeString(&KeyName, GuidBuffer);
+        ObjectKey.RootDirectory = InstalledSDBKey;
 
-    return FALSE;
+        Status = NtCreateKey(&DbKey, KeyAccess, &ObjectKey, 0, NULL, 0, NULL);
+        if (NT_SUCCESS(Status))
+        {
+            UNICODE_STRING DatabasePathKey = RTL_CONSTANT_STRING(L"DatabasePath");
+            UNICODE_STRING DatabaseInstallTimeStampKey = RTL_CONSTANT_STRING(L"DatabaseInstallTimeStamp");
+            UNICODE_STRING DatabaseTypeKey = RTL_CONSTANT_STRING(L"DatabaseType");
+            UNICODE_STRING DatabaseDescriptionKey = RTL_CONSTANT_STRING(L"DatabaseDescription");
+
+            Status = NtSetValueKey(DbKey, &DatabasePathKey, 0, REG_SZ,
+                                   (PVOID)pszDatabasePath, (wcslen(pszDatabasePath) + 1) * sizeof(WCHAR));
+            if (!NT_SUCCESS(Status))
+                SHIM_ERR("Unable to write %wZ\n", &DatabasePathKey);
+
+            if (NT_SUCCESS(Status))
+            {
+                ULARGE_INTEGER ulTimeStamp;
+                if (pTimeStamp)
+                {
+                    ulTimeStamp.QuadPart = *pTimeStamp;
+                }
+                else
+                {
+                    FILETIME fi;
+                    GetSystemTimeAsFileTime(&fi);
+                    ulTimeStamp.LowPart = fi.dwLowDateTime;
+                    ulTimeStamp.HighPart = fi.dwHighDateTime;
+                }
+                Status = NtSetValueKey(DbKey, &DatabaseInstallTimeStampKey, 0, REG_QWORD,
+                                       &ulTimeStamp.QuadPart, sizeof(ulTimeStamp));
+                if (!NT_SUCCESS(Status))
+                    SHIM_ERR("Unable to write %wZ\n", &DatabaseInstallTimeStampKey);
+            }
+
+            if (NT_SUCCESS(Status))
+            {
+                Status = NtSetValueKey(DbKey, &DatabaseTypeKey, 0, REG_DWORD,
+                                       &dwDatabaseType, sizeof(dwDatabaseType));
+                if (!NT_SUCCESS(Status))
+                    SHIM_ERR("Unable to write %wZ\n", &DatabaseTypeKey);
+            }
+
+            if (NT_SUCCESS(Status) && Information.Description)
+            {
+                Status = NtSetValueKey(DbKey, &DatabaseDescriptionKey, 0, REG_SZ,
+                                       (PVOID)Information.Description, (wcslen(Information.Description) + 1) * sizeof(WCHAR));
+                if (!NT_SUCCESS(Status))
+                    SHIM_ERR("Unable to write %wZ\n", &DatabaseDescriptionKey);
+            }
+
+            NtClose(DbKey);
+
+            if (NT_SUCCESS(Status))
+            {
+                SHIM_INFO("Installed %wS as %wZ\n", pszDatabasePath, &KeyName);
+            }
+        }
+        else
+        {
+            SHIM_ERR("Unable to create key %wZ\n", &KeyName);
+        }
+
+        NtClose(InstalledSDBKey);
+    }
+    else
+    {
+        SHIM_ERR("Unable to create key %wZ\n", &KeyName);
+    }
+
+    SdbFreeDatabaseInformation(&Information);
+    SdbCloseDatabase(pdb);
+
+    return NT_SUCCESS(Status);
 }
 
 
@@ -271,7 +389,7 @@ BOOL WINAPI SdbRegisterDatabaseEx(
  * @return                  TRUE on success, or FALSE on failure.
  */
 BOOL WINAPI SdbRegisterDatabase(
-    _In_ LPCTSTR pszDatabasePath,
+    _In_ LPCWSTR pszDatabasePath,
     _In_ DWORD dwDatabaseType)
 {
     return SdbRegisterDatabaseEx(pszDatabasePath, dwDatabaseType, NULL);
@@ -285,11 +403,40 @@ BOOL WINAPI SdbRegisterDatabase(
  * @param pguidDB
  * @return 
  */
-BOOL WINAPI SdbUnregisterDatabase(_In_ GUID *pguidDB)
+BOOL WINAPI SdbUnregisterDatabase(_In_ const GUID *pguidDB)
 {
-    SHIM_ERR("UNIMPLEMENTED, pguidDB = %p\n", pguidDB);
+    WCHAR KeyBuffer[MAX_PATH], GuidBuffer[50];
+    UNICODE_STRING KeyName;
+    ACCESS_MASK KeyAccess;
+    OBJECT_ATTRIBUTES ObjectKey = RTL_INIT_OBJECT_ATTRIBUTES(&KeyName, OBJ_CASE_INSENSITIVE);
+    NTSTATUS Status;
+    HANDLE DbKey;
+
+    if (!SdbGUIDToString(pguidDB, GuidBuffer, RTL_NUMBER_OF(GuidBuffer)))
+    {
+        SHIM_ERR("Unable to Convert GUID to string\n");
+        return FALSE;
+    }
+
+    RtlInitEmptyUnicodeString(&KeyName, KeyBuffer, sizeof(KeyBuffer));
+    RtlAppendUnicodeStringToString(&KeyName, &InstalledSDBKeyName);
+    RtlAppendUnicodeToString(&KeyName, L"\\");
+    RtlAppendUnicodeToString(&KeyName, GuidBuffer);
+
+    KeyAccess = Wow64QueryFlag() | DELETE;
+    Status = NtCreateKey(&DbKey, KeyAccess, &ObjectKey, 0, NULL, 0, NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        SHIM_ERR("Unable to open %wZ\n", &KeyName);
+        return FALSE;
+    }
+
+    Status = NtDeleteKey(DbKey);
+    if (!NT_SUCCESS(Status))
+        SHIM_ERR("Unable to delete %wZ\n", &KeyName);
 
-    return FALSE;
+    NtClose(DbKey);
+    return NT_SUCCESS(Status);
 }