MSI: Implement Registering Classes and ProdID
Mike McCormack
mike at codeweavers.com
Sat Jul 3 20:29:30 CDT 2004
ChangeLog:
<aric at codeweavers.com>
* Implement Registering Classes and ProdID
-------------- next part --------------
diff -ur dlls/msi.old/action.c dlls/msi/action.c
--- dlls/msi.old/action.c 2004-07-03 20:26:38.000000000 -0500
+++ dlls/msi/action.c 2004-07-03 20:27:16.000000000 -0500
@@ -143,6 +143,8 @@
static UINT ACTION_InstallValidate(MSIHANDLE hPackage);
static UINT ACTION_ProcessComponents(MSIHANDLE hPackage);
static UINT ACTION_RegisterTypeLibraries(MSIHANDLE hPackage);
+static UINT ACTION_RegisterClassInfo(MSIHANDLE hPackage);
+static UINT ACTION_RegisterProgIdInfo(MSIHANDLE hPackage);
static UINT HANDLE_CustomType1(MSIHANDLE hPackage, const LPWSTR source,
const LPWSTR target, const INT type);
@@ -193,6 +195,10 @@
const static WCHAR szRegisterTypeLibraries[] =
{'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r',
'i','e','s',0};
+const static WCHAR szRegisterClassInfo[] =
+{'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
+const static WCHAR szRegisterProgIdInfo[] =
+{'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
/********************************************************
* helper functions to get around current HACKS and such
@@ -842,14 +848,16 @@
rc = ACTION_WriteRegistryValues(hPackage);
else if (strcmpW(action,szRegisterTypeLibraries)==0)
rc = ACTION_RegisterTypeLibraries(hPackage);
+ else if (strcmpW(action,szRegisterClassInfo)==0)
+ rc = ACTION_RegisterClassInfo(hPackage);
+ else if (strcmpW(action,szRegisterProgIdInfo)==0)
+ rc = ACTION_RegisterProgIdInfo(hPackage);
/*
Current called during itunes but unimplemented and seem important
ResolveSource (sets SourceDir)
CreateShortcuts (would be nice to have soon)
- RegisterClassInfo
- RegisterProgIdInfo (Lots to do)
RegisterProduct
InstallFinalize
*/
@@ -3245,6 +3253,473 @@
}
+static UINT register_appid(MSIHANDLE hPackage, LPCWSTR clsid, LPCWSTR app )
+{
+ static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
+ UINT rc;
+ MSIHANDLE view;
+ MSIHANDLE row = 0;
+ static const WCHAR ExecSeqQuery[] =
+{'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'
+,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};
+ WCHAR Query[0x1000];
+ MSIPACKAGE* package;
+ HKEY hkey2,hkey3;
+ LPWSTR buffer=0;
+ DWORD sz;
+
+ package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+
+ sprintfW(Query,ExecSeqQuery,clsid);
+
+ rc = MsiDatabaseOpenViewW(package->db, Query, &view);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MsiViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
+ RegCreateKeyW(hkey2,clsid,&hkey3);
+ RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
+ (strlenW(app)+1)*sizeof(WCHAR));
+
+ MsiViewFetch(view,&row);
+
+ if (!MsiRecordIsNull(row,2))
+ {
+ LPWSTR deformated=0;
+ UINT size;
+ static const WCHAR szRemoteServerName[] =
+{'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
+ sz = 0;
+ MsiRecordGetStringW(row,2,NULL,&sz);
+ sz++;
+ buffer = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));
+ MsiRecordGetStringW(row,2,buffer,&sz);
+ size = deformat_string(hPackage,buffer,&deformated);
+ RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated,
+ size);
+ HeapFree(GetProcessHeap(),0,deformated);
+ HeapFree(GetProcessHeap(),0,buffer);
+ }
+
+ if (!MsiRecordIsNull(row,3))
+ {
+ static const WCHAR szLocalService[] =
+{'L','o','c','a','l','S','e','r','v','i','c','e',0};
+ UINT size;
+ sz = 0;
+ MsiRecordGetStringW(row,3,NULL,&sz);
+ sz++;
+ size = sz * sizeof(WCHAR);
+ buffer = HeapAlloc(GetProcessHeap(),0,size);
+ MsiRecordGetStringW(row,3,buffer,&sz);
+ RegSetValueExW(hkey3,szLocalService,0,REG_SZ,(LPVOID)buffer,size);
+ HeapFree(GetProcessHeap(),0,buffer);
+ }
+
+ if (!MsiRecordIsNull(row,4))
+ {
+ static const WCHAR szService[] =
+{'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
+ UINT size;
+ sz = 0;
+ MsiRecordGetStringW(row,4,NULL,&sz);
+ sz++;
+ size = sz * sizeof(WCHAR);
+ buffer = HeapAlloc(GetProcessHeap(),0,size);
+ MsiRecordGetStringW(row,4,buffer,&sz);
+ RegSetValueExW(hkey3,szService,0,REG_SZ,(LPVOID)buffer,size);
+ HeapFree(GetProcessHeap(),0,buffer);
+ }
+
+ if (!MsiRecordIsNull(row,5))
+ {
+ static const WCHAR szDLL[] =
+{'D','l','l','S','u','r','r','o','g','a','t','e',0};
+ UINT size;
+ sz = 0;
+ MsiRecordGetStringW(row,5,NULL,&sz);
+ sz++;
+ size = sz * sizeof(WCHAR);
+ buffer = HeapAlloc(GetProcessHeap(),0,size);
+ MsiRecordGetStringW(row,5,buffer,&sz);
+ RegSetValueExW(hkey3,szDLL,0,REG_SZ,(LPVOID)buffer,size);
+ HeapFree(GetProcessHeap(),0,buffer);
+ }
+
+ if (!MsiRecordIsNull(row,6))
+ {
+ static const WCHAR szActivate[] =
+{'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
+ static const WCHAR szY[] = {'Y',0};
+
+ if (MsiRecordGetInteger(row,6))
+ RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
+ }
+
+ if (!MsiRecordIsNull(row,7))
+ {
+ static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
+ static const WCHAR szUser[] =
+{'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
+
+ if (MsiRecordGetInteger(row,7))
+ RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34);
+ }
+
+ MsiCloseHandle(row);
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ RegCloseKey(hkey3);
+ RegCloseKey(hkey2);
+ return rc;
+}
+
+static UINT ACTION_RegisterClassInfo(MSIHANDLE hPackage)
+{
+ /*
+ * again i am assuming the words, "Whose key file respesents" when refering
+ * to a Component as to meanin that Components KeyPath file
+ *
+ * Also there is a very strong connection between ClassInfo and ProgID
+ * that i am mostly glossing over.
+ * What would be more proper is to load the ClassInfo and the ProgID info
+ * into memory data structures and then be able to enable and disable them
+ * based on component.
+ */
+
+ UINT rc;
+ MSIHANDLE view;
+ MSIHANDLE row = 0;
+ static const CHAR *ExecSeqQuery = "SELECT * from Class";
+ MSIPACKAGE* package;
+ static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
+ static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
+ static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
+ HKEY hkey,hkey2,hkey3;
+
+ package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
+ if (rc != ERROR_SUCCESS)
+ return ERROR_FUNCTION_FAILED;
+
+ rc = MsiDatabaseOpenViewA(package->db, ExecSeqQuery, &view);
+
+ if (rc != ERROR_SUCCESS)
+ goto end;
+
+ rc = MsiViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ goto end;
+ }
+
+ while (1)
+ {
+ WCHAR clsid[0x100];
+ WCHAR buffer[0x100];
+ WCHAR desc[0x100];
+ DWORD sz;
+ INT index;
+
+ rc = MsiViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ rc = ERROR_SUCCESS;
+ break;
+ }
+
+ sz=0x100;
+ MsiRecordGetStringW(row,3,buffer,&sz);
+
+ index = get_loaded_component(package,buffer);
+
+ if (index < 0)
+ {
+ MsiCloseHandle(row);
+ continue;
+ }
+
+ if (!package->components[index].Enabled ||
+ !package->components[index].FeatureState)
+ {
+ TRACE("Skipping class reg due to disabled component\n");
+ MsiCloseHandle(row);
+ continue;
+ }
+
+ sz=0x100;
+ MsiRecordGetStringW(row,1,clsid,&sz);
+ RegCreateKeyW(hkey,clsid,&hkey2);
+
+ if (!MsiRecordIsNull(row,5))
+ {
+ sz=0x100;
+ MsiRecordGetStringW(row,5,desc,&sz);
+
+ RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)desc,
+ (strlenW(desc)+1)*sizeof(WCHAR));
+ }
+ else
+ desc[0]=0;
+
+ sz=0x100;
+ MsiRecordGetStringW(row,2,buffer,&sz);
+
+ RegCreateKeyW(hkey2,buffer,&hkey3);
+
+ index = get_loaded_file(package,package->components[index].KeyPath);
+ RegSetValueExW(hkey3,NULL,0,REG_SZ,
+ (LPVOID)package->files[index].TargetPath,
+ (strlenW(package->files[index].TargetPath)+1)
+ *sizeof(WCHAR));
+
+ RegCloseKey(hkey3);
+
+ if (!MsiRecordIsNull(row,4))
+ {
+ sz=0x100;
+ MsiRecordGetStringW(row,4,buffer,&sz);
+
+ RegCreateKeyW(hkey2,szProgID,&hkey3);
+
+ RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)buffer,
+ (strlenW(buffer)+1)*sizeof(WCHAR));
+
+ RegCloseKey(hkey3);
+ }
+
+ if (!MsiRecordIsNull(row,6))
+ {
+ sz=0x100;
+ MsiRecordGetStringW(row,6,buffer,&sz);
+
+ RegSetValueExW(hkey2,szAppID,0,REG_SZ,(LPVOID)buffer,
+ (strlenW(buffer)+1)*sizeof(WCHAR));
+
+ register_appid(hPackage,buffer,desc);
+ }
+
+ RegCloseKey(hkey2);
+
+ FIXME("Process the rest of the fields >7\n");
+
+ ui_actiondata(hPackage,szRegisterClassInfo,row);
+
+ MsiCloseHandle(row);
+ }
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+
+end:
+ RegCloseKey(hkey);
+ return rc;
+}
+
+static UINT register_progid_base(MSIHANDLE row, LPWSTR clsid)
+{
+ static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
+ HKEY hkey,hkey2;
+ WCHAR buffer[0x1000];
+ DWORD sz;
+
+
+ sz = 0x1000;
+ MsiRecordGetStringW(row,1,buffer,&sz);
+ RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
+
+ if (!MsiRecordIsNull(row,4))
+ {
+ sz = 0x1000;
+ MsiRecordGetStringW(row,4,buffer,&sz);
+ RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
+ sizeof(WCHAR));
+ }
+
+ if (!MsiRecordIsNull(row,3))
+ {
+ sz = 0x1000;
+
+ MsiRecordGetStringW(row,3,buffer,&sz);
+ RegCreateKeyW(hkey,szCLSID,&hkey2);
+ RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
+ sizeof(WCHAR));
+
+ if (clsid)
+ strcpyW(clsid,buffer);
+
+ RegCloseKey(hkey2);
+ }
+ else
+ {
+ FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
+ return ERROR_FUNCTION_FAILED;
+ }
+ if (!MsiRecordIsNull(row,5))
+ FIXME ("UNHANDLED icon in Progid\n");
+ return ERROR_SUCCESS;
+}
+
+static UINT register_progid(MSIHANDLE hPackage, MSIHANDLE row, LPWSTR clsid);
+
+static UINT register_parent_progid(MSIHANDLE hPackage, LPCWSTR parent,
+ LPWSTR clsid)
+{
+ UINT rc;
+ MSIHANDLE view;
+ MSIHANDLE row = 0;
+ static const WCHAR Query_t[] =
+{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'
+,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'
+,'%','s','`',0};
+ WCHAR Query[0x1000];
+ MSIPACKAGE* package;
+
+ package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ sprintfW(Query,Query_t,parent);
+
+ rc = MsiDatabaseOpenViewW(package->db, Query, &view);
+
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MsiViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ rc = MsiViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ register_progid(hPackage,row,clsid);
+
+ MsiCloseHandle(row);
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+}
+
+static UINT register_progid(MSIHANDLE hPackage, MSIHANDLE row, LPWSTR clsid)
+{
+ UINT rc = ERROR_SUCCESS;
+
+ if (MsiRecordIsNull(row,2))
+ rc = register_progid_base(row,clsid);
+ else
+ {
+ WCHAR buffer[0x1000];
+ DWORD sz;
+ HKEY hkey,hkey2;
+ static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
+
+ sz = 0x1000;
+ MsiRecordGetStringW(row,2,buffer,&sz);
+ rc = register_parent_progid(hPackage,buffer,clsid);
+
+ sz = 0x1000;
+ MsiRecordGetStringW(row,1,buffer,&sz);
+ RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
+ /* clasid is same as parent */
+ RegCreateKeyW(hkey,szCLSID,&hkey2);
+ RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
+ sizeof(WCHAR));
+
+ RegCloseKey(hkey2);
+ if (!MsiRecordIsNull(row,4))
+ {
+ sz = 0x1000;
+ MsiRecordGetStringW(row,4,buffer,&sz);
+ RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer,
+ (strlenW(buffer)+1) * sizeof(WCHAR));
+ }
+
+ if (!MsiRecordIsNull(row,5))
+ FIXME ("UNHANDLED icon in Progid\n");
+
+ RegCloseKey(hkey);
+ }
+ return rc;
+}
+
+static UINT ACTION_RegisterProgIdInfo(MSIHANDLE hPackage)
+{
+ /*
+ * Sigh, here i am just brute force registering all progid
+ * this needs to be linked to the Classes that have been registerd
+ * but the easiest way to do that is to load all these stuff into
+ * memory for easy checking.
+ *
+ * gives me something to continue to work toward
+ */
+ UINT rc;
+ MSIHANDLE view;
+ MSIHANDLE row = 0;
+ static const CHAR *Query = "SELECT * FROM ProgId";
+ MSIPACKAGE* package;
+
+ package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ rc = MsiDatabaseOpenViewA(package->db, Query, &view);
+
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MsiViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ while (1)
+ {
+ WCHAR clsid[0x1000];
+
+ rc = MsiViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ rc = ERROR_SUCCESS;
+ break;
+ }
+
+ register_progid(hPackage,row,clsid);
+
+ MsiCloseHandle(row);
+ }
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+}
+
/* Msi functions that seem approperate here */
UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
{
@@ -3488,11 +3963,13 @@
MSIHANDLE view;
MSIHANDLE row = 0;
static const CHAR *ExecSeqQuery;
- MSIHANDLE db;
+ MSIPACKAGE* package;
- db = MsiGetActiveDatabase(hPackage);
- rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
- MsiCloseHandle(db);
+ package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ rc = MsiDatabaseOpenViewA(package->db, ExecSeqQuery, &view);
if (rc != ERROR_SUCCESS)
return rc;
More information about the wine-patches
mailing list