#include #include #include "fusenet.h" #define INITGUID #include // 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 // 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" "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; }