2025-04-27 07:49:33 -04:00

975 lines
30 KiB
C++

#include <windows.h>
#include <objbase.h>
#include "fusenet.h"
#define INITGUID
#include <guiddef.h>
// Update services
#include "server.h"
DEFINE_GUID(IID_IAssemblyUpdate,
0x301b3415,0xf52d,0x4d40,0xbd,0xf7,0x31,0xd8,0x27,0x12,0xc2,0xdc);
DEFINE_GUID(CLSID_CAssemblyUpdate,
0x37b088b8,0x70ef,0x4ecf,0xb1,0x1e,0x1f,0x3f,0x4d,0x10,0x5f,0xdd);
// CLR Hosting
#import "..\..\clrhost\asmexec.tlb" raw_interfaces_only
using namespace asmexec;
// note: a bit hacky to use something that's implemented under shell\shortcut\util.cpp
#include "project.hpp" // for extern HRESULT GetLastWin32Error(); only
#define WZ_TYPE_DOTNET L".NetAssembly"
#define WZ_TYPE_WIN32 L"win32Executable"
#define WZ_TYPE_AVALON L"avalon"
#define TYPE_DOTNET 1
#define TYPE_WIN32 2
#define TYPE_AVALON 3
IInternetSecurityManager* g_pSecurityMgr = NULL;
#include <stdio.h> // for _snwprintf
// debug msg stuff
void
Msg(LPWSTR pwz)
{
MessageBox(NULL, pwz, L"Fusion Manifest Host", 0);
}
// ----------------------------------------------------------------------------
HRESULT
RunCommand(LPWSTR wzCmdLine, LPCWSTR wzCurrentDir, BOOL fWait)
{
HRESULT hr = S_OK;
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
// wzCurrentDir: The string must be a full path and file name that includes a drive letter; or NULL
if(!CreateProcess(NULL, wzCmdLine, NULL, NULL, TRUE, 0, NULL, wzCurrentDir, &si, &pi))
{
hr = GetLastWin32Error();
goto exit;
}
if (fWait)
{
if(WaitForSingleObject(pi.hProcess, 180000L) == WAIT_TIMEOUT)
{
hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
goto exit;
}
}
exit:
if(pi.hProcess) CloseHandle(pi.hProcess);
if(pi.hThread) CloseHandle(pi.hThread);
return hr;
}
// ----------------------------------------------------------------------------
HRESULT
CopyToUSStartMenu(LPCWSTR pwzFilePath, LPCWSTR pwzRealFilename, BOOL bOverwrite)
{
HRESULT hr = S_OK;
WCHAR wzPath[MAX_PATH];
// BUGBUG?: use SHGetFolderPath()
if(GetEnvironmentVariable(L"USERPROFILE", wzPath, MAX_PATH-1) == 0)
{
hr = CO_E_PATHTOOLONG;
goto exit;
}
if (!PathAppend(wzPath, L"Start Menu\\Programs\\"))
{
hr = E_FAIL;
goto exit;
}
if (!PathAppend(wzPath, pwzRealFilename))
{
hr = E_FAIL;
goto exit;
}
if (CopyFile(pwzFilePath, wzPath, !bOverwrite) == 0)
{
hr = GetLastWin32Error();
//goto exit;
}
exit:
return hr;
}
// ----------------------------------------------------------------------------
// BUGBUG: should this be in-sync with what server does to register update?
#define REG_KEY_FUSION_SETTINGS L"Software\\Microsoft\\Fusion\\Installer\\1.0.0.0\\Policy"
#define REG_VAL_INTRANET_DISALLOW L"Download from Intranet Disallowed"
#define REG_VAL_TRUSTED_DISALLOW L"Download from Trusted Zone Disallowed"
#define REG_VAL_INTERNET_DISALLOW L"Download from Internet Disallowed"
#define REG_VAL_UNTRUSTED_DISALLOW L"Download from Untrusted Zone Disallowed"
// BUGBUG hacky should move this from extricon.cpp to util.cpp and declare in project.hpp
extern LONG GetRegKeyValue(HKEY hkeyParent, PCWSTR pcwzSubKey,
PCWSTR pcwzValue, PDWORD pdwValueType,
PBYTE pbyteBuf, PDWORD pdwcbBufLen);
// return: S_OK for yes/ok, E_ABORT for no/abort
// default is allow all
HRESULT
CheckZonePolicy(LPWSTR pwzURL)
{
HRESULT hr = S_OK;
DWORD dwZone = 0;
DWORD dwType = 0;
DWORD dwValue = -1;
DWORD dwSize = sizeof(dwValue);
if (g_pSecurityMgr == NULL)
{
// lazy init.
hr = CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_INPROC_SERVER,
IID_IInternetSecurityManager, (void**)&g_pSecurityMgr);
if (FAILED(hr))
{
g_pSecurityMgr = NULL;
goto exit;
}
}
if (SUCCEEDED(hr = g_pSecurityMgr->MapUrlToZone(pwzURL, &dwZone, 0)))
{
// BUGBUG: hack up code here... not much error checking...
switch(dwZone)
{
case 1: // Intranet Zone
// Get registry entry
if (GetRegKeyValue(HKEY_CURRENT_USER,
REG_KEY_FUSION_SETTINGS, REG_VAL_INTRANET_DISALLOW,
&dwType, (PBYTE) &dwValue, &dwSize)
== ERROR_SUCCESS)
{
if (dwValue == 1)
{
hr = E_ABORT;
Msg(L"Zone policy: Download from Intranet is disallowed. Aborting...");
}
}
break;
case 2: // Trusted Zone
// Get registry entry
if (GetRegKeyValue(HKEY_CURRENT_USER,
REG_KEY_FUSION_SETTINGS, REG_VAL_TRUSTED_DISALLOW,
&dwType, (PBYTE) &dwValue, &dwSize)
== ERROR_SUCCESS)
{
if (dwValue == 1)
{
hr = E_ABORT;
Msg(L"Zone policy: Download from Trusted Zone is disallowed. Aborting...");
}
}
break;
case 3: // Internet Zone
// Get registry entry
if (GetRegKeyValue(HKEY_CURRENT_USER,
REG_KEY_FUSION_SETTINGS, REG_VAL_INTERNET_DISALLOW,
&dwType, (PBYTE) &dwValue, &dwSize)
== ERROR_SUCCESS)
{
if (dwValue == 1)
{
hr = E_ABORT;
Msg(L"Zone policy: Download from Internet is disallowed. Aborting...");
}
}
break;
case 4: // Untrusted Zone
// Get registry entry
if (GetRegKeyValue(HKEY_CURRENT_USER,
REG_KEY_FUSION_SETTINGS, REG_VAL_UNTRUSTED_DISALLOW,
&dwType, (PBYTE) &dwValue, &dwSize)
== ERROR_SUCCESS)
{
if (dwValue == 1)
{
hr = E_ABORT;
Msg(L"Zone policy: Download from Untrusted Zone is disallowed. Aborting...");
}
}
break;
case 0: //Local machine
default:
break;
}
}
exit:
return hr;
}
// ----------------------------------------------------------------------------
// note: parameter pwzCodebase can be NULL
HRESULT
ResolveAndInstall(LPASSEMBLY_IDENTITY pAsmId, LPWSTR pwzCodebase, LPWSTR *ppwzManifestFileDir, LPWSTR *ppwzManifestFilePath, BOOL* pbIs1stTimeInstall)
{
HRESULT hr = S_OK;
LPASSEMBLY_CACHE_IMPORT pCacheImport = NULL;
DWORD dwCC = 0;
*pbIs1stTimeInstall = FALSE;
// look into the cache
if (FAILED(hr=CreateAssemblyCacheImport(&pCacheImport, pAsmId, CACHEIMP_CREATE_RESOLVE_REF)))
goto exit;
// hr from CreateAssemblyCacheImport() above
// Case 1, cached copy exist
// hr == S_OK
// Case 2, cached copy (of the referenced version) not exist
if (hr == S_FALSE)
{
LPASSEMBLY_DOWNLOAD pAsmDownload = NULL;
// BUGBUG?: what if it is not a partial ref but there's actually another version installed?
if (pwzCodebase == NULL)
{
Msg(L"No completed cached version of this application found and this manifest cannot be used to initiate an install. Cannot continue.");
hr = E_FAIL;
goto exit;
}
*pbIs1stTimeInstall = TRUE;
// check policy before download
if (FAILED(hr=CheckZonePolicy(pwzCodebase)))
goto exit;
if (FAILED(hr=CreateAssemblyDownload(&pAsmDownload)))
goto exit;
//BUGBUG: need ref def matching checks for desktop->subscription->app manifests' ids
// (synchronous & ui) download from codebase
hr=pAsmDownload->DownloadManifestAndDependencies(pwzCodebase, NULL, DOWNLOAD_FLAGS_PROGRESS_UI);
pAsmDownload->Release();
// hr from DownloadManifestAndDependencies() above
if (FAILED(hr))
{
if (hr == E_ABORT)
Msg(L"File download canceled.");
else
Msg(L"Error in file download. Cannot continue.");
goto exit;
}
// another version might have been completed at this time...
// get cache dir again to ensure running the highest version
if (FAILED(hr=CreateAssemblyCacheImport(&pCacheImport, pAsmId, CACHEIMP_CREATE_RESOLVE_REF)))
goto exit;
if (hr == S_FALSE)
{
Msg(L"No completed cached version found. Possible error in download cache commit. Cannot continue.");
hr = E_ABORT;
goto exit;
}
}
pCacheImport->GetManifestFileDir(ppwzManifestFileDir, &dwCC);
if (dwCC < 2)
{
// this should never happen
hr = E_FAIL;
goto exit;
}
pCacheImport->GetManifestFilePath(ppwzManifestFilePath, &dwCC);
if (dwCC < 2)
{
hr = E_FAIL;
goto exit;
}
exit:
if (pCacheImport)
pCacheImport->Release();
if (FAILED(hr))
{
if (*ppwzManifestFileDir)
{
delete *ppwzManifestFileDir;
*ppwzManifestFileDir = NULL;
}
if (*ppwzManifestFilePath)
{
delete *ppwzManifestFilePath;
*ppwzManifestFilePath = NULL;
}
}
return hr;
}
// ----------------------------------------------------------------------------
/*void _stdcall
EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);
hwnd - window handle that should be used as the owner window for
any windows your DLL creates
hinst - your DLL's instance handle
lpszCmdLine - ASCIIZ command line your DLL should parse
nCmdShow - describes how your DLL's windows should be displayed
*/
// ---------------------------------------------------------------------------
// DisableCurrentVersionW
// The rundll32 entry point for rollback to previous version
// The function should be named as 'DisableCurrentVersion' on rundll32's command line
// ---------------------------------------------------------------------------
// BUGBUG: WARNING!! this is **major hacked up code** and does open up some holes in the logic
// depends on the timing of this and check for max version in cache in app start....
// ie. SHOULD NEVER BE RUNNING THIS AND START DOWNLOAD/UPDATE!
//
// also, this depends on a few things such as how update service check if the
// version exists etc..
void CALLBACK
DisableCurrentVersionW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
{
HRESULT hr = S_OK;
LPASSEMBLY_MANIFEST_IMPORT pManImport = NULL;
LPASSEMBLY_IDENTITY pAsmId = NULL;
LPMANIFEST_APPLICATION_INFO pAppInfo = NULL;
LPASSEMBLY_CACHE_IMPORT pCacheImport = NULL;
LPWSTR pwzCacheDir = NULL;
LPWSTR pwzDisplayName = NULL;
DWORD dwCC = 0;
WCHAR wzBuf[1024];
LONG lResult;
HKEY hkeySubKey;
if (FAILED(hr = CoInitialize(NULL)))
goto exit;
// hacked up commandline parsing code
lpszCmdLine = lpszCmdLine+1;
*(lpszCmdLine+lstrlen(lpszCmdLine)-1) = L'\0';
if (FAILED(hr=CreateAssemblyManifestImport(&pManImport, lpszCmdLine)))
{
// temp msg
Msg(L"ManImport error.");
goto exit;
}
if (FAILED(hr=pManImport->GetManifestApplicationInfo(&pAppInfo)) || hr==S_FALSE)
{
// can't continue without this...
hr = E_ABORT;
Msg(L"This manifest does not have the proper format and cannot be used to start an application. Thus there is nothing to disable here.");
goto exit;
}
if (FAILED(hr=pManImport->GetAssemblyIdentity(&pAsmId)))
{
// temp msg
Msg(L"AsmId error.");
goto exit;
}
if (FAILED(hr=CreateAssemblyCacheImport(&pCacheImport, pAsmId, CACHEIMP_CREATE_RESOLVE_REF)))
{
// temp msg
Msg(L"CacheImport error.");
goto exit;
}
if (hr == S_FALSE)
{
Msg(L"No completed cached version found. Nothing to disable.");
hr = E_ABORT;
goto exit;
}
pCacheImport->GetManifestFileDir(&pwzCacheDir, &dwCC);
if (dwCC < 2)
{
// this should never happen
hr = E_FAIL;
goto exit;
}
// remove last L'\\'
*(pwzCacheDir+dwCC-2) = L'\0';
// find the name to use from the cache path
pwzDisplayName = wcsrchr(pwzCacheDir, L'\\');
// this has to be the same as how assemblycache does it!
lstrcpy(wzBuf, L"Software\\Microsoft\\Fusion\\Installer\\1.0.0.0\\Cache\\");
lstrcat(wzBuf, pwzDisplayName);
lResult = RegOpenKeyEx(HKEY_CURRENT_USER, wzBuf, 0, KEY_SET_VALUE,
&hkeySubKey);
if (lResult == ERROR_SUCCESS)
{
DWORD dwValue = 0;
// set to 0 to make it 'incomplete' so that StartW/host/cache will ignore it
// when executing the app but keep the dir name so that download
// will assume it is handled - assemblycache.cpp & assemblydownload.cpp's check
lResult = RegSetValueEx(hkeySubKey, L"Complete", NULL, REG_DWORD,
(PBYTE) &dwValue, sizeof(dwValue));
if (lResult == ERROR_SUCCESS)
{
// no error checking!
pCacheImport->Release();
hr=CreateAssemblyCacheImport(&pCacheImport, pAsmId, CACHEIMP_CREATE_RESOLVE_REF);
if (hr == S_FALSE)
{
dwValue = 1;
// change it back to what it was if no other completed version found
// no error checking!
lResult = RegSetValueEx(hkeySubKey, L"Complete", NULL, REG_DWORD,
(PBYTE) &dwValue, sizeof(dwValue));
// BUGBUG: known problem for fully qualified ref, eg. app manifest's asm id
// Should check for it and display and different msg here.
Msg(L"No other completed cached version found. Disabling current version cannot be done. Cancelling...");
}
else
{
Msg(L"Current version disabled. Next time another version of the app will run instead.");
}
}
RegCloseKey(hkeySubKey);
}
else
{
Msg(L"Registry error.");
}
exit:
if (pCacheImport)
pCacheImport->Release();
if (pAsmId)
pAsmId->Release();
if (pAppInfo)
pAppInfo->Release();
if (pManImport)
pManImport->Release();
if (pwzCacheDir)
delete pwzCacheDir;
if (FAILED(hr))
{
if (hr != E_ABORT)
Msg(L"Error occured.");
}
CoUninitialize();
return;
}
// ---------------------------------------------------------------------------
// StartW
// The single rundll32 entry point for both shell (file type host) and mimefilter/url
// The function should be named as 'Start' on rundll32's command line
// ---------------------------------------------------------------------------
void CALLBACK
StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
{
HRESULT hr = S_OK;
LPASSEMBLY_MANIFEST_IMPORT pManImport = NULL;
LPASSEMBLY_IDENTITY pAsmId = NULL;
LPMANIFEST_APPLICATION_INFO pAppInfo = NULL;
LPDEPENDENT_ASSEMBLY_INFO pDependAsmInfo = NULL;
LPWSTR pwzShortcutPath = NULL;
LPWSTR pwzShortcutUrl = NULL;
LPWSTR pwzAppRootDir = NULL;
LPWSTR pwzAppManifestPath = NULL;
LPWSTR pwzEntrypoint = NULL;
LPWSTR pwzType = NULL;
LPWSTR pwzCmdLine = NULL;
LPWSTR pwzCodebase = NULL;
DWORD dwCC = 0;
DWORD dwManifestType = MANIFEST_TYPE_UNKNOWN;
BOOL bIsFromMimeFilter = FALSE;
BOOL bIs1stTimeInstall = FALSE;
int iAppType = 0;
if (FAILED(hr = CoInitialize(NULL)))//CoInitializeEx(NULL, COINIT_MULTITHREADED);
goto exit;
// parse commandline
// accepted formats: "Path" <OR> "Path" "URL"
if (*lpszCmdLine == L'\"')
{
LPWSTR pwz = NULL;
pwz = wcschr(lpszCmdLine+1, L'\"');
if (pwz != NULL)
{
*pwz = L'\0';
// case 1 desktop/local, path to shortcut only
pwzShortcutPath = lpszCmdLine+1;
pwz = wcschr(pwz+1, L'\"');
if (pwz != NULL)
{
pwzShortcutUrl = pwz+1;
pwz = wcschr(pwzShortcutUrl, L'\"');
if (pwz != NULL)
{
*pwz = L'\0';
// case 2 url/mimefilter, path to temp shortcut and source URL
bIsFromMimeFilter = TRUE;
}
}
}
}
// exit if invalid arguments. ShortcutUrl is incomplete if bIsFromMimeFilter is FALSE
if (pwzShortcutPath == NULL || (pwzShortcutUrl != NULL && !bIsFromMimeFilter))
{
hr = E_INVALIDARG;
goto exit;
}
// valid start conditions to invoke this function, passing
// 1. path to desktop manifest (install redirect to subscription manifest on server)
// 2. path to desktop manifest (install redirect to applicaion manifest on server)
// 3. BUGBUG TO-BE-FIXED//path to application (no install)
// 4. URL to subscription manifest on server
// 5. URL to application manifest on server
if (FAILED(hr=CreateAssemblyManifestImport(&pManImport, pwzShortcutPath)))
{
Msg(L"Error in loading and parsing the manifest file.");
goto exit;
}
pManImport->ReportManifestType(&dwManifestType);
if (dwManifestType == MANIFEST_TYPE_UNKNOWN)
{
Msg(L"This manifest does not have a known format type.");
hr = E_ABORT;
goto exit;
}
// allow only valid start conditions
if (bIsFromMimeFilter &&
dwManifestType != MANIFEST_TYPE_SUBSCRIPTION &&
dwManifestType != MANIFEST_TYPE_APPLICATION)
{
Msg(L"Not supported: URL pointing to a desktop manifest.");
hr = E_ABORT;
goto exit;
}
if (!bIsFromMimeFilter &&
dwManifestType != MANIFEST_TYPE_DESKTOP)
//&& dwManifestType != MANIFEST_TYPE_APPLICATION)
{
Msg(L"This manifest does not have the proper format and cannot be used to start an application.");
hr = E_ABORT;
goto exit;
}
// get data from the manifest file
if (dwManifestType != MANIFEST_TYPE_SUBSCRIPTION)
{
if (FAILED(hr=pManImport->GetAssemblyIdentity(&pAsmId)))
{
Msg(L"This manifest does not have the proper format and contains no assembly identity.");
goto exit;
}
}
if (dwManifestType != MANIFEST_TYPE_APPLICATION)
{
// BUGBUG: hardcoded index '0'
pManImport->GetNextAssembly(0, &pDependAsmInfo);
if (pDependAsmInfo)
{
if (dwManifestType == MANIFEST_TYPE_SUBSCRIPTION)
{
pDependAsmInfo->GetAssemblyIdentity(&pAsmId);
}
pDependAsmInfo->Get(DEPENDENT_ASM_CODEBASE, &pwzCodebase, &dwCC);
}
if (!pAsmId || !pwzCodebase)
{
Msg(L"This subscription manifest contains no dependent assembly identity or a subscription codebase.");
hr = E_FAIL;
goto exit;
}
}
else
{
// if (bIsFromMimeFilter)
// {
// if URL->app manifest (case 5), codebase is that URL
// note: if path->app manifest (case 3), this does NOT apply
// BUGBUG: HACK: this implies re-download of the app manifest. pref?
size_t ccCodebase = wcslen(pwzShortcutUrl)+1;
pwzCodebase = new WCHAR[ccCodebase];
if (pwzCodebase == NULL)
{
hr = E_OUTOFMEMORY;
goto exit;
}
memcpy(pwzCodebase, pwzShortcutUrl, ccCodebase * sizeof(WCHAR));
// }
}
// search cache, download/install if necessary
if (FAILED(hr = ResolveAndInstall(pAsmId, pwzCodebase, &pwzAppRootDir, &pwzAppManifestPath, &bIs1stTimeInstall)))
goto exit;
// register for updates
if (bIs1stTimeInstall && bIsFromMimeFilter && dwManifestType == MANIFEST_TYPE_SUBSCRIPTION)
{
// note: this code must be identical to what assemblydownload.cpp DoCacheUpdate() does!
LPWSTR pwzName = NULL;
if ((hr = pAsmId->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME, &pwzName, &dwCC)) != S_OK)
{
Msg(L"Error in retrieving assembly name. Cannot register subscription for updates.");
// note: This- no asm name- should not be allowed!
}
else
{
IAssemblyUpdate *pAssemblyUpdate = NULL;
// register for updates
hr = CoCreateInstance(CLSID_CAssemblyUpdate, NULL, CLSCTX_LOCAL_SERVER,
IID_IAssemblyUpdate, (void**)&pAssemblyUpdate);
if (SUCCEEDED(hr))
{
DWORD pollingInterval;
hr = pManImport->GetPollingInterval (&pollingInterval);
hr = pAssemblyUpdate->RegisterAssemblySubscription(pwzName,
pwzShortcutUrl, pollingInterval);
pAssemblyUpdate->Release();
}
if (FAILED(hr))
{
Msg(L"Error in update services. Cannot register subscription for updates.");
//goto exit; do not terminate!
}
// else
// Error in update services. Cannot register subscription for updates - fail gracefully
// BUGBUG: need a way to recover from this and register later
delete pwzName;
}
}
// execute the app
if (bIsFromMimeFilter)
{
// if URL, crack the app manifest to get shell state info
// BUGBUG: if URL->app manifest (case 5), pwzShortcutPath is a copy and is already cracked-so no need in that case?
pManImport->Release();
if (FAILED(hr=CreateAssemblyManifestImport(&pManImport, pwzAppManifestPath)))
{
Msg(L"Error in loading and parsing the application manifest file.");
goto exit;
}
}
if (FAILED(hr=pManImport->GetManifestApplicationInfo(&pAppInfo)) || hr==S_FALSE)
{
// can't continue without this...
hr = E_ABORT;
Msg(L"This manifest does not have the shell information and cannot be used to start an application.");
goto exit;
}
if (FAILED(hr = pAppInfo->Get(MAN_APPLICATION_ENTRYPOINT, &pwzEntrypoint, &dwCC)))
{
Msg(L"This application does not have an entrypoint specified.");
goto exit;
}
if (FAILED(hr = pAppInfo->Get(MAN_APPLICATION_ENTRYIMAGETYPE, &pwzType, &dwCC)))
{
Msg(L"Error in retrieving application type. Cannot continue.");
goto exit;
}
// BUGBUG: use wcscmp case sensitive comparison?
if (_wcsicmp(pwzType, WZ_TYPE_DOTNET) == 0)
iAppType = TYPE_DOTNET;
else if (_wcsicmp(pwzType, WZ_TYPE_WIN32) == 0)
iAppType = TYPE_WIN32;
else if (_wcsicmp(pwzType, WZ_TYPE_AVALON) == 0)
iAppType = TYPE_AVALON;
if (iAppType == TYPE_DOTNET || iAppType == TYPE_WIN32 || iAppType == TYPE_AVALON)
{
size_t ccWorkingDir = wcslen(pwzAppRootDir);
size_t ccEntryPoint = wcslen(pwzEntrypoint)+1;
pwzCmdLine = new WCHAR[ccWorkingDir+ccEntryPoint]; // 2 strings + '\0'
if (pwzCmdLine == NULL)
{
hr = E_OUTOFMEMORY;
goto exit;
}
memcpy(pwzCmdLine, pwzAppRootDir, ccWorkingDir * sizeof(WCHAR));
memcpy(pwzCmdLine+ccWorkingDir, pwzEntrypoint, ccEntryPoint * sizeof(WCHAR));
// check if the entry point is in cache or not
if (GetFileAttributes(pwzCmdLine) == (DWORD)-1)
{
Msg(L"Entry point does not exist. Cannot continue.");
hr = E_ABORT;
goto exit;
}
}
if (iAppType == TYPE_DOTNET)// || iAppType == TYPE_AVALON)
{
DWORD dwZone;
//conexec WCHAR wzCmdLine[1025];
// note: at this point the codebase can be: URL to app manifest _or_ URL to subscription manifest
// (depends on how 1st time install is started with)
if (pwzCodebase == NULL)
{
Msg(L"This application does not have a codebase specified. Cannot continue to execute .NetAssembly.");
goto exit;
}
if (g_pSecurityMgr == NULL)
{
// lazy init.
hr = CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_INPROC_SERVER,
IID_IInternetSecurityManager, (void**)&g_pSecurityMgr);
if (FAILED(hr))
{
g_pSecurityMgr = NULL;
goto exit;
}
}
// BUGBUG?: shouldn't use codebase from ref manifest to set zone?
if (FAILED(hr = g_pSecurityMgr->MapUrlToZone(pwzCodebase, &dwZone, 0)))
{
goto exit;
}
/*conexec code path
if (_snwprintf(wzCmdLine, sizeof(wzCmdLine)/sizeof(WCHAR),
L"conexec.exe \"%s\" 3 %d %s", pwzCmdLine, dwZone, pwzCodebase) < 0)
{
hr = CO_E_PATHTOOLONG;
goto exit;
}
// BUGBUG: start directory: what if the exe is in a subdir of pwzAppRootDir?
// CreateProcess dislike having the filename in the path for the start directory
if (FAILED(hr=RunCommand(wzCmdLine, pwzAppRootDir, FALSE)))
goto exit;*/
try
{
IAsmExecutePtr pIAsmExecute(__uuidof(AsmExecute));
long lRetVal = -1;
LPWSTR pwzArg = NULL;
// BUGBUG: change AsmExec if it's no longer needed to send commandline argument
// clean up interface
if (iAppType == TYPE_AVALON)
{
// call with manifest file path as a parameter
pwzArg = pwzAppManifestPath;
}
//parameters: Codebase/filepath Flag Zone Url Arg
// BUGBUG: DWORD is unsigned and long is signed
hr = pIAsmExecute->Execute(_bstr_t(pwzCmdLine), 3, dwZone, _bstr_t(pwzCodebase), _bstr_t(pwzArg), &lRetVal);
// BUGBUG: do something about lRetVal
}
catch (_com_error &e)
{
hr = e.Error();
Msg((LPWSTR)e.ErrorMessage());
}
// hr from Execute() or inside catch(){} above
if (FAILED(hr))
goto exit;
}
else if (iAppType == TYPE_AVALON) //BUGBUG: a hack for avalon
{
WCHAR wzCmdLine[2048];
if (_snwprintf(wzCmdLine, sizeof(wzCmdLine)/sizeof(WCHAR),
L"\"%s\" \"%s\"", pwzCmdLine, pwzAppManifestPath) < 0)
{
hr = CO_E_PATHTOOLONG;
goto exit;
}
// BUGBUG: start directory: what if the exe is in a subdir of pwzAppRootDir?
// CreateProcess dislike having the filename in the path for the start directory
if (FAILED(hr=RunCommand(wzCmdLine, pwzAppRootDir, FALSE)))
{
Msg(L"Avalon: Create process error.");
goto exit;
}
}
else if (iAppType == TYPE_WIN32)
{
// BUGBUG: Win32 app has no sandboxing... use SAFER?
// BUGBUG: start directory: what if the exe is in a subdir of pwzAppRootDir?
// CreateProcess dislike having the filename in the path for the start directory
if (FAILED(hr=RunCommand(pwzCmdLine, pwzAppRootDir, FALSE)))
{
Msg(L"Win32Executable: Create process error.");
goto exit;
}
}
//else
// unknown type....
exit:
if (g_pSecurityMgr != NULL)
{
g_pSecurityMgr->Release();
g_pSecurityMgr = NULL;
}
if (pAsmId)
pAsmId->Release();
if (pDependAsmInfo)
pDependAsmInfo->Release();
if (pAppInfo)
pAppInfo->Release();
if (pManImport)
pManImport->Release();
if (pwzAppManifestPath)
delete pwzAppManifestPath;
if (pwzAppRootDir)
delete pwzAppRootDir;
if (pwzEntrypoint)
delete pwzEntrypoint;
if (pwzType)
delete pwzType;
if (pwzCmdLine)
delete pwzCmdLine;
if (pwzCodebase)
delete pwzCodebase;
if (FAILED(hr))
{
if (hr != E_ABORT)
Msg(L"Error occured.");
}
else
{
if (bIsFromMimeFilter && bIs1stTimeInstall)
{
// BUGBUG: should generate the desktop manifest file
/* // assume it's an URL
LPWSTR pwzFilename = wcsrchr(pwzShortcutUrl, L'/');
if (pwzFilename != NULL)
{
pwzFilename++;
CopyToUSStartMenu(pwzShortcutPath, pwzFilename, FALSE);
}
//else
// error as filename not found but ignore...*/
}
}
if (bIsFromMimeFilter)
{
// delete the temp file from the mimefilter
// ignore return value
DeleteFile(pwzShortcutPath);
}
CoUninitialize();
return;
}