Implemented CreateShortcut and PublishProduct.
This commit is contained in:
parent
24e9a34494
commit
2cf222f9b7
|
@ -145,6 +145,8 @@ 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 ACTION_CreateShortcuts(MSIHANDLE hPackage);
|
||||
static UINT ACTION_PublishProduct(MSIHANDLE hPackage);
|
||||
|
||||
static UINT HANDLE_CustomType1(MSIHANDLE hPackage, const LPWSTR source,
|
||||
const LPWSTR target, const INT type);
|
||||
|
@ -199,6 +201,10 @@ 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};
|
||||
const static WCHAR szCreateShortcuts[] =
|
||||
{'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
|
||||
const static WCHAR szPublishProduct[] =
|
||||
{'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
|
||||
|
||||
/********************************************************
|
||||
* helper functions to get around current HACKS and such
|
||||
|
@ -852,12 +858,15 @@ UINT ACTION_PerformAction(MSIHANDLE hPackage, const WCHAR *action)
|
|||
rc = ACTION_RegisterClassInfo(hPackage);
|
||||
else if (strcmpW(action,szRegisterProgIdInfo)==0)
|
||||
rc = ACTION_RegisterProgIdInfo(hPackage);
|
||||
else if (strcmpW(action,szCreateShortcuts)==0)
|
||||
rc = ACTION_CreateShortcuts(hPackage);
|
||||
else if (strcmpW(action,szPublishProduct)==0)
|
||||
rc = ACTION_PublishProduct(hPackage);
|
||||
|
||||
/*
|
||||
Called during itunes but unimplemented and seem important
|
||||
|
||||
ResolveSource (sets SourceDir)
|
||||
CreateShortcuts (would be nice to have soon)
|
||||
RegisterProduct
|
||||
InstallFinalize
|
||||
*/
|
||||
|
@ -3049,6 +3058,13 @@ static void resolve_keypath(MSIHANDLE hPackage, MSIPACKAGE* package, INT
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok further analysis makes me think that this work is
|
||||
* actually done in the PublishComponents and PublishFeatures
|
||||
* step. And not here. It appears like the keypath and all that is
|
||||
* resolved in this step, however actaully written in the Publish steps.
|
||||
* But we will leave it here for now
|
||||
*/
|
||||
static UINT ACTION_ProcessComponents(MSIHANDLE hPackage)
|
||||
{
|
||||
MSIPACKAGE* package;
|
||||
|
@ -3712,6 +3728,7 @@ static UINT ACTION_RegisterProgIdInfo(MSIHANDLE hPackage)
|
|||
}
|
||||
|
||||
register_progid(hPackage,row,clsid);
|
||||
ui_actiondata(hPackage,szRegisterProgIdInfo,row);
|
||||
|
||||
MsiCloseHandle(row);
|
||||
}
|
||||
|
@ -3720,6 +3737,319 @@ static UINT ACTION_RegisterProgIdInfo(MSIHANDLE hPackage)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static UINT build_icon_path(MSIHANDLE hPackage, LPCWSTR icon_name,
|
||||
LPWSTR FilePath)
|
||||
{
|
||||
WCHAR ProductCode[0x100];
|
||||
WCHAR SystemFolder[MAX_PATH];
|
||||
DWORD sz;
|
||||
|
||||
static const WCHAR szInstaller[] =
|
||||
{'I','n','s','t','a','l','l','e','r','\\',0};
|
||||
static const WCHAR szProductCode[] =
|
||||
{'P','r','o','d','u','c','t','C','o','d','e',0};
|
||||
static const WCHAR szFolder[] =
|
||||
{'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
|
||||
|
||||
sz = 0x100;
|
||||
MsiGetPropertyW(hPackage,szProductCode,ProductCode,&sz);
|
||||
if (strlenW(ProductCode)==0)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
sz = MAX_PATH;
|
||||
MsiGetPropertyW(hPackage,szFolder,SystemFolder,&sz);
|
||||
strcatW(SystemFolder,szInstaller);
|
||||
strcatW(SystemFolder,ProductCode);
|
||||
create_full_pathW(SystemFolder);
|
||||
|
||||
strcpyW(FilePath,SystemFolder);
|
||||
strcatW(FilePath,cszbs);
|
||||
strcatW(FilePath,icon_name);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT ACTION_CreateShortcuts(MSIHANDLE hPackage)
|
||||
{
|
||||
UINT rc;
|
||||
MSIHANDLE view;
|
||||
MSIHANDLE row = 0;
|
||||
static const CHAR *Query = "SELECT * from Shortcut";
|
||||
MSIPACKAGE* package;
|
||||
|
||||
IShellLinkW *sl;
|
||||
IPersistFile *pf;
|
||||
HRESULT res;
|
||||
|
||||
package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
res = CoInitialize( NULL );
|
||||
if (FAILED (res))
|
||||
{
|
||||
ERR("CoInitialize failed\n");
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
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 target_file[MAX_PATH];
|
||||
WCHAR buffer[0x1000];
|
||||
DWORD sz;
|
||||
DWORD index;
|
||||
static const WCHAR szlnk[]={'.','l','n','k',0};
|
||||
|
||||
rc = MsiViewFetch(view,&row);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
rc = ERROR_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
sz = 0x1000;
|
||||
MsiRecordGetStringW(row,4,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 shortcut creation due to disabled component\n");
|
||||
MsiCloseHandle(row);
|
||||
continue;
|
||||
}
|
||||
|
||||
ui_actiondata(hPackage,szCreateShortcuts,row);
|
||||
|
||||
res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_IShellLinkW, (LPVOID *) &sl );
|
||||
|
||||
if (FAILED(res))
|
||||
{
|
||||
ERR("Is IID_IShellLink\n");
|
||||
MsiCloseHandle(row);
|
||||
continue;
|
||||
}
|
||||
|
||||
res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
|
||||
if( FAILED( res ) )
|
||||
{
|
||||
ERR("Is IID_IPersistFile\n");
|
||||
MsiCloseHandle(row);
|
||||
continue;
|
||||
}
|
||||
|
||||
sz = 0x1000;
|
||||
MsiRecordGetStringW(row,2,buffer,&sz);
|
||||
resolve_folder(hPackage, buffer,target_file,FALSE,FALSE,NULL);
|
||||
|
||||
sz = 0x1000;
|
||||
MsiRecordGetStringW(row,3,buffer,&sz);
|
||||
reduce_to_longfilename(buffer);
|
||||
strcatW(target_file,buffer);
|
||||
if (!strchrW(target_file,'.'))
|
||||
strcatW(target_file,szlnk);
|
||||
|
||||
sz = 0x1000;
|
||||
MsiRecordGetStringW(row,5,buffer,&sz);
|
||||
if (strchrW(buffer,'['))
|
||||
{
|
||||
LPWSTR deformated;
|
||||
deformat_string(hPackage,buffer,&deformated);
|
||||
IShellLinkW_SetPath(sl,deformated);
|
||||
HeapFree(GetProcessHeap(),0,deformated);
|
||||
}
|
||||
else
|
||||
{
|
||||
FIXME("UNHANDLED shortcut format, advertised shortcut\n");
|
||||
IPersistFile_Release( pf );
|
||||
IShellLinkW_Release( sl );
|
||||
MsiCloseHandle(row);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!MsiRecordIsNull(row,6))
|
||||
{
|
||||
LPWSTR deformated;
|
||||
sz = 0x1000;
|
||||
MsiRecordGetStringW(row,6,buffer,&sz);
|
||||
deformat_string(hPackage,buffer,&deformated);
|
||||
IShellLinkW_SetArguments(sl,deformated);
|
||||
HeapFree(GetProcessHeap(),0,deformated);
|
||||
}
|
||||
|
||||
if (!MsiRecordIsNull(row,7))
|
||||
{
|
||||
LPWSTR deformated;
|
||||
sz = 0;
|
||||
MsiRecordGetStringW(row,7,NULL,&sz);
|
||||
sz++;
|
||||
deformated = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
|
||||
MsiRecordGetStringW(row,7,deformated,&sz);
|
||||
IShellLinkW_SetDescription(sl,deformated);
|
||||
HeapFree(GetProcessHeap(),0,deformated);
|
||||
}
|
||||
|
||||
if (!MsiRecordIsNull(row,8))
|
||||
IShellLinkW_SetHotkey(sl,MsiRecordGetInteger(row,8));
|
||||
|
||||
if (!MsiRecordIsNull(row,9))
|
||||
{
|
||||
WCHAR Path[MAX_PATH];
|
||||
INT index;
|
||||
|
||||
sz = 0x1000;
|
||||
MsiRecordGetStringW(row,9,buffer,&sz);
|
||||
|
||||
build_icon_path(hPackage,buffer,Path);
|
||||
index = MsiRecordGetInteger(row,10);
|
||||
|
||||
IShellLinkW_SetIconLocation(sl,Path,index);
|
||||
}
|
||||
|
||||
if (!MsiRecordIsNull(row,11))
|
||||
IShellLinkW_SetShowCmd(sl,MsiRecordGetInteger(row,11));
|
||||
|
||||
if (!MsiRecordIsNull(row,12))
|
||||
{
|
||||
WCHAR Path[MAX_PATH];
|
||||
|
||||
sz = 0x1000;
|
||||
MsiRecordGetStringW(row,12,buffer,&sz);
|
||||
resolve_folder(hPackage, buffer, Path, FALSE, FALSE, NULL);
|
||||
IShellLinkW_SetWorkingDirectory(sl,Path);
|
||||
}
|
||||
|
||||
TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
|
||||
IPersistFile_Save(pf,target_file,FALSE);
|
||||
|
||||
IPersistFile_Release( pf );
|
||||
IShellLinkW_Release( sl );
|
||||
|
||||
MsiCloseHandle(row);
|
||||
}
|
||||
MsiViewClose(view);
|
||||
MsiCloseHandle(view);
|
||||
|
||||
|
||||
CoUninitialize();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 99% of the work done here is only done for
|
||||
* advertised installs. However this is where the
|
||||
* Icon table is processed and written out
|
||||
* so that is waht i am going to do here
|
||||
*/
|
||||
static UINT ACTION_PublishProduct(MSIHANDLE hPackage)
|
||||
{
|
||||
UINT rc;
|
||||
MSIHANDLE view;
|
||||
MSIHANDLE row = 0;
|
||||
static const CHAR *Query="SELECT * from Icon";
|
||||
MSIPACKAGE* package;
|
||||
DWORD sz;
|
||||
|
||||
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)
|
||||
{
|
||||
HANDLE the_file;
|
||||
WCHAR FilePath[MAX_PATH];
|
||||
WCHAR FileName[MAX_PATH];
|
||||
CHAR buffer[1024];
|
||||
|
||||
rc = MsiViewFetch(view,&row);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
rc = ERROR_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
sz = MAX_PATH;
|
||||
MsiRecordGetStringW(row,1,FileName,&sz);
|
||||
if (sz == 0)
|
||||
{
|
||||
ERR("Unable to get FileName\n");
|
||||
MsiCloseHandle(row);
|
||||
continue;
|
||||
}
|
||||
|
||||
build_icon_path(hPackage,FileName,FilePath);
|
||||
|
||||
TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
|
||||
|
||||
the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (the_file == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ERR("Unable to create file %s\n",debugstr_w(FilePath));
|
||||
MsiCloseHandle(row);
|
||||
continue;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
DWORD write;
|
||||
sz = 1024;
|
||||
rc = MsiRecordReadStream(row,2,buffer,&sz);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Failed to get stream\n");
|
||||
CloseHandle(the_file);
|
||||
DeleteFileW(FilePath);
|
||||
break;
|
||||
}
|
||||
WriteFile(the_file,buffer,sz,&write,NULL);
|
||||
} while (sz == 1024);
|
||||
|
||||
CloseHandle(the_file);
|
||||
MsiCloseHandle(row);
|
||||
}
|
||||
MsiViewClose(view);
|
||||
MsiCloseHandle(view);
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
/* Msi functions that seem approperate here */
|
||||
UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
|
||||
{
|
||||
|
|
|
@ -173,27 +173,6 @@ static VOID set_installer_properties(MSIHANDLE hPackage)
|
|||
static const WCHAR TF[]=
|
||||
{'T','e','m','p','F','o','l','d','e','r',0};
|
||||
|
||||
/* Not yet set ... but needed by iTunes
|
||||
*
|
||||
DesktopFolder
|
||||
FavoritesFolder
|
||||
FontsFolder
|
||||
PrimaryVolumePath
|
||||
ProgramFiles64Folder
|
||||
ProgramMenuFolder
|
||||
SendToFolder
|
||||
StartMenuFolder
|
||||
StartupFolder
|
||||
System16Folder
|
||||
System64Folder
|
||||
TemplateFolder
|
||||
*/
|
||||
|
||||
/* asked for by iTunes ... but are they installer set?
|
||||
*
|
||||
* GlobalAssemblyCache
|
||||
*/
|
||||
|
||||
/*
|
||||
* Other things i notice set
|
||||
*
|
||||
|
@ -266,6 +245,7 @@ Privilaged
|
|||
GetTempPathW(MAX_PATH,pth);
|
||||
MsiSetPropertyW(hPackage, TF, pth);
|
||||
|
||||
|
||||
/* in a wine enviroment the user is always admin and privlaged */
|
||||
MsiSetPropertyA(hPackage,"AdminUser","1");
|
||||
MsiSetPropertyA(hPackage,"Privileged","1");
|
||||
|
@ -288,8 +268,26 @@ Privilaged
|
|||
MsiSetPropertyA(hPackage,"WindowsBuild",verstr);
|
||||
/* just fudge this */
|
||||
MsiSetPropertyA(hPackage,"ServicePackLevel","6");
|
||||
}
|
||||
|
||||
/* FIXME: these need to be set properly */
|
||||
|
||||
MsiSetPropertyA(hPackage,"ProgramMenuFolder",
|
||||
"C:\\Windows\\Start Menu\\Programs\\");
|
||||
MsiSetPropertyA(hPackage,"FavoritesFolder",
|
||||
"C:\\Windows\\Favorites\\");
|
||||
MsiSetPropertyA(hPackage,"FontsFolder",
|
||||
"C:\\Windows\\Fonts\\");
|
||||
MsiSetPropertyA(hPackage,"SendToFolder",
|
||||
"C:\\Windows\\SendTo\\");
|
||||
MsiSetPropertyA(hPackage,"StartMenuFolder",
|
||||
"C:\\Windows\\Start Menu\\");
|
||||
MsiSetPropertyA(hPackage,"StartupFolder",
|
||||
"C:\\Windows\\Start Menu\\Programs\\Startup\\");
|
||||
MsiSetPropertyA(hPackage,"TemplateFolder",
|
||||
"C:\\Windows\\ShellNew\\");
|
||||
MsiSetPropertyA(hPackage, "DesktopFolder",
|
||||
"C:\\Windows\\Desktop\\");
|
||||
}
|
||||
|
||||
UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue