#include #include "dll.h" #include "util.h" #include class CUNCFileSource : public IApplicationFileSource { public: CUNCFileSource(); HRESULT CreateNew( /* [out] */ LPAPPLICATIONFILESOURCE* ppAppFileSrc); HRESULT GetFile( /* [in] */ LPCWSTR wzSourceFilename, /* [in] */ LPCWSTR wzDestinationLocalFilePath, /* [in] */ LPCWSTR wzHash); HRESULT GetFile( /* [in] */ LPCWSTR wzSourceFilePath, /* [in] */ LPCWSTR wzDestinationLocalFilePath); HRESULT SetSourcePath( /* [in] */ LPCWSTR wzSourceFilePath); HRESULT BuildLocalAppRootHierarchy( /* [in] */ APPNAME* pAppName, /* [out] */ LPWSTR wzLocalAppRoot); HRESULT GetFullFilePath( /* [in] */ LPCWSTR wzFilename, /* [out] */ LPWSTR wzFullFilePath); private: // this should contain the last / or \, excluding a filename WCHAR wzSourcePath[MAX_PATH]; // UNC/filesystem restirction }; CUNCFileSource::CUNCFileSource() { wzSourcePath[0] = L'\0'; } HRESULT CUNCFileSource::CreateNew(LPAPPLICATIONFILESOURCE* ppAppFileSrc) { HRESULT hr = S_OK; LPAPPLICATIONFILESOURCE pAppFileSrc = NULL; if (!ppAppFileSrc) { hr = E_INVALIDARG; goto exit; } pAppFileSrc = new CUNCFileSource(); if (!pAppFileSrc) { hr = E_OUTOFMEMORY; *ppAppFileSrc = NULL; goto exit; } *ppAppFileSrc = pAppFileSrc; exit: return hr; } HRESULT CUNCFileSource::GetFile(LPCWSTR wzSourceFilePath, LPCWSTR wzDestinationLocalFilePath) { HRESULT hr = S_OK; WCHAR* pwzFileName = NULL; // unconditional get and overwrite // check the path exist? create (sub)directories? pwzFileName = PathFindFileName ( wzDestinationLocalFilePath ); if ( pwzFileName > wzDestinationLocalFilePath ) { *(pwzFileName-1) = L'\0'; int len = wcslen(wzDestinationLocalFilePath); if (len > 3) { /* must be at least c:\a */ hr = CreatePathHierarchy(wzDestinationLocalFilePath); } // note: this few lines must follow the previous CreatePathHierarchy() line *(pwzFileName-1) = L'\\'; if (FAILED(hr)) goto exit; } if (CopyFile(wzSourceFilePath, wzDestinationLocalFilePath, FALSE) == 0) { hr = GetLastWin32Error(); goto exit; } exit: return hr; } HRESULT CUNCFileSource::GetFile(LPCWSTR wzSourceFilename, LPCWSTR wzDestinationLocalFilePath, LPCWSTR wzHash) { // note: unknown behaviour if wzSourcePath\wzSourceFilename == wzDestinationLocalFilePath HRESULT hr=S_OK; WCHAR wzFullFilePath[MAX_PATH]; // 1. check if the file exist, if so, check file integrity if (PathFileExists(wzDestinationLocalFilePath)) { if (FAILED(hr = CheckIntegrity(wzDestinationLocalFilePath, wzHash))) goto exit; if (hr == S_FALSE) { // hash mismatch/no hash, force overwrite hr = S_OK; } else goto exit; // else we are done, file already there and unchanged } // 2. assemble the full source path if (FAILED(hr = GetFullFilePath(wzSourceFilename, wzFullFilePath))) goto exit; // 3. copy it over if (FAILED(hr = GetFile(wzFullFilePath, wzDestinationLocalFilePath))) goto exit; // should this copy the file by bytes and check hash the same time? // 4. check file integrity, assume ok if no hash if (wzHash != NULL && wzHash[0] != L'\0') { if (FAILED(hr = CheckIntegrity(wzDestinationLocalFilePath, wzHash))) goto exit; if (hr == S_FALSE) { // hash mismatch - something very wrong hr = CRYPT_E_HASH_VALUE; goto exit; } } exit: return hr; } // this should only be called once HRESULT CUNCFileSource::SetSourcePath(LPCWSTR wzSourceFilePath) { // keep the source path HRESULT hr=S_OK; WCHAR* p; // copy and avoid buffer overflows wcsncpy(wzSourcePath, wzSourceFilePath, MAX_PATH-1); wzSourcePath[MAX_PATH-1] = L'\0'; // strip out the filename portion of the filepath p = PathFindFileName(wzSourcePath); if ((p-wzSourcePath) >= MAX_PATH) { hr = CO_E_PATHTOOLONG; goto exit; } else if (p <= wzSourcePath) { // this file path has no filename in it or is invalid (eg. root) hr = E_INVALIDARG; goto exit; } *(p-1) = L'\0'; exit: if (FAILED(hr)) wzSourcePath[0] = L'\0'; return hr; } // returning the local app root path with all directories created HRESULT CUNCFileSource::BuildLocalAppRootHierarchy(APPNAME* pAppName, LPWSTR wzLocalAppRoot) { // build from wzSourcePath HRESULT hr=S_OK; int offset = 0; int len = wcslen(wzSourcePath); WCHAR wzAppDir[MAX_PATH]; if (len <3) { /* must be at least \\a or c:\*/ hr = E_INVALIDARG; goto exit; } if (PathIsUNC(wzSourcePath)) offset = 2; // UNC source else if (wzSourcePath[1] == L':' && wzSourcePath[2] == L'\\') { offset = 3; // local file source // check if the string ends at/after the offset! if (len <= 3) { // eg. C:\ - should disallow root hr = E_INVALIDARG; goto exit; } } else { // what else is this?! hr = E_FAIL; goto exit; } // 1 get default local root if (FAILED(hr=GetDefaultLocalRoot(wzLocalAppRoot))) goto exit; // 2 append part of source path as the app root if (FAILED(hr=GetAppDir(pAppName, wzAppDir))) goto exit; if (!PathAppend(wzLocalAppRoot, wzAppDir)) { hr = E_FAIL; goto exit; } // 3 create the directories if (FAILED(hr=CreatePathHierarchy(wzLocalAppRoot))) { goto exit; } exit: if (FAILED(hr)) wzLocalAppRoot[0] = L'\0'; return hr; } // returning the source file path from a filename HRESULT CUNCFileSource::GetFullFilePath(LPCWSTR wzFilename, LPWSTR wzFullFilePath) { // wzFilename cannot = L'\0' // wzFullFilePath must be of length MAX_PATH HRESULT hr=S_OK; if (wzSourcePath[0] == L'\0') { // source path not set hr = E_UNEXPECTED; goto exit; } wcscpy(wzFullFilePath, wzSourcePath); if (!PathAppend(wzFullFilePath, wzFilename)) { hr = E_FAIL; //goto exit; } exit: return hr; } // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // the following functions acts similar to their shlwapi Path... counterparts // Returns a pointer to the last component of a path string. // // in: // path name, either fully qualified or not // // returns: // pointer into the path where the path is. if none is found // returns a poiter to the start of the path // // http://www.microsoft.com/foo/bar -> bar // http://www.microsoft.com/foo -> foo // http://www.microsoft.com/foo/ -> foo/ (is this busted?) // http://www.microsoft.com/ -> http://www.microsoft.com/ // http://www.microsoft.com -> http://www.microsoft.com // http:// -> http:// // http: -> http: // www.microsoft.com -> www.microsoft.com STDAPI_(LPWSTR) UrlFindFileName(LPCWSTR pPath) { LPCWSTR pW; BOOL fSkip = FALSE; for (pW = pPath; *pPath; pPath = pPath+1) { if (pPath[0] == L':' && pPath[1] && pPath[1] == L'/') fSkip = TRUE; if (pPath[0] == L'/' && pPath[1] && pPath[1] != L'/') { if (fSkip) fSkip = FALSE; else pW = pPath + 1; } } return (LPWSTR)pW; // const -> non const } // this returns successfully only if a filename is present /*STDAPI_(LPWSTR) UrlFindExtension(LPCWSTR pPath) { LPCWSTR pFN = UrlFindFileName(pPath); int len = wcslen(pPath); LPCWSTR pW = pPath+len; // no filename there if (pFN == pPath) return (LPWSTR)(pPath+len); for (; *pFN; pFN = pFN+1) { if (pFN[0] == L'.') pW = pFN; } return (LPWSTR)pW; }*/ // size of pszPath should be set to MAX_URL_LENGTH STDAPI_(BOOL) UrlAppend(LPWSTR pszPath, LPCWSTR pszMore) { int len = wcslen(pszPath); int len2 = wcslen(pszMore); // check string overlaps! if ((pszPath < pszMore && pszMore < pszPath+len) || (pszMore < pszPath && pszPath < pszMore+len2)) return FALSE; if ((len >= MAX_URL_LENGTH-1) || (len+len2 >= MAX_URL_LENGTH-1)) return FALSE; if (pszPath[len-1] != L'/') { if ((len >= MAX_URL_LENGTH-2) || (len+len2 >= MAX_URL_LENGTH-2)) return FALSE; pszPath[len] = L'/'; pszPath[len+1] = L'\0'; } wcsncat(pszPath, pszMore, len2); return TRUE; } // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- class CHTTPFileSource : public IApplicationFileSource { public: CHTTPFileSource(); HRESULT CreateNew( /* [out] */ LPAPPLICATIONFILESOURCE* ppAppFileSrc); HRESULT GetFile( /* [in] */ LPCWSTR wzSourceFilename, /* [in] */ LPCWSTR wzDestinationLocalFilePath, /* [in] */ LPCWSTR wzHash); HRESULT GetFile( /* [in] */ LPCWSTR wzSourceFilePath, /* [in] */ LPCWSTR wzDestinationLocalFilePath); HRESULT SetSourcePath( /* [in] */ LPCWSTR wzSourceFilePath); HRESULT BuildLocalAppRootHierarchy( /* [in] */ APPNAME* pAppName, /* [out] */ LPWSTR wzLocalAppRoot); HRESULT GetFullFilePath( /* [in] */ LPCWSTR wzFilename, /* [out] */ LPWSTR wzFullFilePath); private: // this should contain the last / or \, excluding a filename WCHAR wzSourcePath[MAX_URL_LENGTH]; // http URL restirction // S_OK == hash match; S_FALSE == hash unmatch HRESULT GetFileFromInternet( /* [in] */ LPCWSTR wzSourceFilePath, /* [in] */ LPCWSTR wzDestinationLocalFilePath, /* [in] */ LPCWSTR wzHash); }; CHTTPFileSource::CHTTPFileSource() { wzSourcePath[0] = L'\0'; } HRESULT CHTTPFileSource::CreateNew(LPAPPLICATIONFILESOURCE* ppAppFileSrc) { HRESULT hr = S_OK; LPAPPLICATIONFILESOURCE pAppFileSrc = NULL; if (!ppAppFileSrc) { hr = E_INVALIDARG; goto exit; } pAppFileSrc = new CHTTPFileSource(); if (!pAppFileSrc) { hr = E_OUTOFMEMORY; *ppAppFileSrc = NULL; goto exit; } *ppAppFileSrc = pAppFileSrc; exit: return hr; } HRESULT CHTTPFileSource::GetFileFromInternet(LPCWSTR wzSourceFilePath, LPCWSTR wzDestinationLocalFilePath, LPCWSTR wzHash) { HRESULT hr = S_OK; WCHAR* pwzFileName = NULL; HINTERNET hInternet = NULL; HINTERNET hTransfer = NULL; HANDLE hFile = INVALID_HANDLE_VALUE; DWORD dwRead = 0; DWORD dwWritten = 0; BYTE buffer[4096]; HASHCONTEXT hc; WCHAR wzComputedHash[HASHSTRINGLENGTH]; BOOL fDoHash = TRUE; // unconditional get and overwrite if (wzHash == NULL || wzHash[0] == L'\0') fDoHash = FALSE; // check the path exist? create (sub)directories? pwzFileName = PathFindFileName( wzDestinationLocalFilePath ); if ( pwzFileName > wzDestinationLocalFilePath ) { *(pwzFileName-1) = L'\0'; int len = wcslen(wzDestinationLocalFilePath); if (len > 3) { /* must be at least c:\a */ hr = CreatePathHierarchy(wzDestinationLocalFilePath); } // note: this few lines must follow the previous CreatePathHierarchy() line *(pwzFileName-1) = L'\\'; if (FAILED(hr)) goto exit; } ////////////////////////////////////////////////////////////////////// // Step 1: Open the http connection hInternet = InternetOpen(L"App", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if(hInternet == NULL) { hr = GetLastWin32Error(); goto exit; } // note: cache write mean the refresh might not work and old bits could return hTransfer = InternetOpenUrl(hInternet, wzSourceFilePath, NULL, 0, 0, 0); if(hTransfer == NULL) { hr = GetLastWin32Error(); goto exit; } if (fDoHash) BeginHash(&hc); // need to check if there's any error, eg. not found (404)... InternetGetLastResponseInfo()? ////////////////////////////////////////////////////////////////////// // Step 2: Create the file; Copy the files over the internet // need write access, will open (and replace/overwrite) exiting file // ??? FILE_SHARE_READ? but we might write to if outdated... while(InternetReadFile(hTransfer, buffer, sizeof(buffer), &dwRead) && dwRead != 0) { // Open the disk file if (hFile == INVALID_HANDLE_VALUE) { hFile = CreateFile(wzDestinationLocalFilePath, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); } // Failed to open the disk file if(hFile == INVALID_HANDLE_VALUE) { hr = GetLastWin32Error(); goto exit; } // Write bytes to the disk file // synchronous download if ( !WriteFile(hFile, buffer, dwRead, &dwWritten, NULL) || dwWritten != dwRead) { hr = GetLastWin32Error(); goto exit; } if (fDoHash) ContinueHash(&hc, buffer, (unsigned) dwRead); } if (dwRead != 0) { hr = GetLastWin32Error(); goto exit; } if (fDoHash) { EndHash(&hc, wzComputedHash); if (wcscmp(wzHash, wzComputedHash) != 0) hr = S_FALSE; else hr = S_OK; } exit: if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); if (hInternet != NULL) InternetCloseHandle(hInternet); if (hTransfer != NULL) InternetCloseHandle(hTransfer); hInternet = NULL; hTransfer = NULL; hFile = INVALID_HANDLE_VALUE; return hr; } HRESULT CHTTPFileSource::GetFile(LPCWSTR wzSourceFilePath, LPCWSTR wzDestinationLocalFilePath) { HRESULT hr = S_OK; WCHAR* pwzFileName = NULL; // BUGBUG: this pretty much duplicates CUNCFileSource::GetFile(,) // get file from a different location - via CopyFile // unconditional get and overwrite // check the path exist? create (sub)directories? pwzFileName = PathFindFileName ( wzDestinationLocalFilePath ); if ( pwzFileName > wzDestinationLocalFilePath ) { *(pwzFileName-1) = L'\0'; int len = wcslen(wzDestinationLocalFilePath); if (len > 3) { /* must be at least c:\a */ hr = CreatePathHierarchy(wzDestinationLocalFilePath); } // note: this few lines must follow the previous CreatePathHierarchy() line *(pwzFileName-1) = L'\\'; if (FAILED(hr)) goto exit; } if (CopyFile(wzSourceFilePath, wzDestinationLocalFilePath, FALSE) == 0) { hr = GetLastWin32Error(); goto exit; } exit: return hr; } HRESULT CHTTPFileSource::GetFile(LPCWSTR wzSourceFilename, LPCWSTR wzDestinationLocalFilePath, LPCWSTR wzHash) { // note: unknown behaviour if wzSourcePath\wzSourceFilename == wzDestinationLocalFilePath HRESULT hr=S_OK; WCHAR wzFullFilePath[MAX_URL_LENGTH]; // 1. check if the file exist, if so, check file integrity if (PathFileExists(wzDestinationLocalFilePath)) { if (FAILED(hr = CheckIntegrity(wzDestinationLocalFilePath, wzHash))) goto exit; if (hr == S_FALSE) { // hash mismatch/no hash, force overwrite hr = S_OK; } else goto exit; // else we are done, file already there and unchanged } // 2. assemble the full source path if (FAILED(hr = GetFullFilePath(wzSourceFilename, wzFullFilePath))) goto exit; // 3. copy it over if (FAILED(hr = GetFileFromInternet(wzFullFilePath, wzDestinationLocalFilePath, wzHash))) goto exit; // should this copy the file by bytes and check hash the same time? // 4. check file integrity, assume ok if no hash if (hr == S_FALSE) { DbgMsg(L"hash mismatch"); // hash mismatch - something very wrong hr = CRYPT_E_HASH_VALUE; goto exit; } exit: return hr; } // this should only be called once HRESULT CHTTPFileSource::SetSourcePath(LPCWSTR wzSourceFilePath) { // keep the source path HRESULT hr=S_OK; WCHAR* p; // copy and avoid buffer overflows wcsncpy(wzSourcePath, wzSourceFilePath, MAX_URL_LENGTH-1); wzSourcePath[MAX_URL_LENGTH-1] = L'\0'; // strip out the filename portion of the filepath p = UrlFindFileName(wzSourcePath); if ((p-wzSourcePath) >= MAX_URL_LENGTH) { hr = CO_E_PATHTOOLONG; goto exit; } else if (p <= wzSourcePath) { // this file path has no filename in it or is invalid (eg. root) hr = E_INVALIDARG; goto exit; } *(p-1) = L'\0'; exit: if (FAILED(hr)) wzSourcePath[0] = L'\0'; return hr; } // returning the local app root path with all directories created HRESULT CHTTPFileSource::BuildLocalAppRootHierarchy(APPNAME* pAppName, LPWSTR wzLocalAppRoot) { // BUGBUG: this pretty much duplicates CUNCFileSource::BuildLocalAppRootHierarchy(,) // build from wzSourcePath HRESULT hr=S_OK; int len = wcslen(wzSourcePath); DWORD dwLen = MAX_URL_LENGTH-1; WCHAR wzHostName[MAX_URL_LENGTH]; WCHAR wzAppDir[MAX_PATH]; if (len <8) { /* must be at least http://a */ hr = E_INVALIDARG; goto exit; } if (FAILED(hr = UrlGetPart(wzSourcePath, wzHostName, &dwLen, URL_PART_HOSTNAME, 0))) { // what is this?! hr = E_FAIL; goto exit; } // 1 get default local root if (FAILED(hr=GetDefaultLocalRoot(wzLocalAppRoot))) goto exit; // 2 append part of source path as the app root if (FAILED(hr=GetAppDir(pAppName, wzAppDir))) goto exit; if (!PathAppend(wzLocalAppRoot, wzAppDir)) { hr = E_FAIL; goto exit; } // 3 create the directories if (FAILED(hr=CreatePathHierarchy(wzLocalAppRoot))) { goto exit; } exit: if (FAILED(hr)) wzLocalAppRoot[0] = L'\0'; return hr; } // returning the source file path from a filename HRESULT CHTTPFileSource::GetFullFilePath(LPCWSTR wzFilename, LPWSTR wzFullFilePath) { // wzFilename cannot = L'\0' // wzFullFilePath must be of length MAX_URL_LENGTH HRESULT hr=S_OK; if (wzSourcePath[0] == L'\0') { // source path not set hr = E_UNEXPECTED; goto exit; } wcscpy(wzFullFilePath, wzSourcePath); if (!UrlAppend(wzFullFilePath, wzFilename)) { hr = E_FAIL; //goto exit; } exit: return hr; } ///////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// HRESULT ProcessUrl(LPCWSTR wzRefFilePath, LPCWSTR wzRefRealFilename, APPNAME* pAppName, LPWSTR wzCodebase) { HRESULT hr=S_OK; CHTTPFileSource httpfs; WCHAR wzLocalPath[MAX_PATH]; WCHAR *p = NULL; // step 1: check the commandline argument's extension - somewhat optional if ((_wcsicmp(PathFindExtension(wzRefRealFilename), SHORTCUTFILEEXT) != 0) || !PathIsURL(wzCodebase) || //!PathFileExists(wzRefFilePath) || not work w/ UNC source UrlIsFileUrl(wzCodebase) || UrlIsOpaque(wzCodebase)) // BUGBUG? :check http:// too { hr = E_INVALIDARG; // file ext mismatch OR is a file:// or path is not an URL AND file not exist goto exit; } // step 2: get the shortcut file and the .manifest file if (FAILED(hr = httpfs.SetSourcePath(wzCodebase))) goto exit; if (FAILED(hr = httpfs.BuildLocalAppRootHierarchy(pAppName, wzLocalPath))) goto exit; if(!PathAppend(wzLocalPath, wzRefRealFilename)) { hr = E_FAIL; DbgMsg(L"path for .app fails"); goto exit; } // get file via CopyFile if (FAILED(hr = httpfs.GetFile(wzRefFilePath, wzLocalPath))) // ignore E_UNEXPECTED? { DbgMsg(L"get .app fails"); goto exit; } *PathFindFileName(wzLocalPath) = L'\0'; p = UrlFindFileName(wzCodebase); if (p == wzCodebase || !PathAppend(wzLocalPath, p)) { hr = E_FAIL; DbgMsg(L"path for .manifest fails"); goto exit; } if (FAILED(hr = httpfs.GetFile(p, wzLocalPath, NULL))) // ignore E_UNEXPECTED? { DbgMsg(L"get .manifest fails"); goto exit; } // step 3: process the .manifest file if (FAILED(hr = ProcessAppManifest(wzLocalPath, &httpfs, pAppName))) goto exit; exit: if (hr == E_ABORT) MsgShow(L"Operation aborted."); else if (FAILED(hr)) MsgShow(L"Error Encountered."); else { // if SUCCEEDED // do not overwrite if shortcut exists. ignore error // note: this should probably be done only in the "1st install" case // - ie. need feedback from ProcessAppManifest() CopyToStartMenu(wzRefFilePath, wzRefRealFilename, FALSE); } return hr; } ///////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// HRESULT ProcessUNC(LPCWSTR wzRefFilePath, LPCWSTR wzRefRealFilename, APPNAME* pAppName, LPWSTR wzCodebase) { // BUGBUG: this pretty much duplicates ProcessUrl HRESULT hr=S_OK; CUNCFileSource uncfs; WCHAR wzLocalPath[MAX_PATH]; WCHAR *p = NULL; // step 1: check the commandline argument's extension - somewhat optional if ((_wcsicmp(PathFindExtension(wzRefRealFilename), SHORTCUTFILEEXT) != 0) || (!PathIsUNC(wzCodebase) && !PathFileExists(wzCodebase))) { hr = E_INVALIDARG; // file ext mismatch OR (path is not an UNC AND file not exist(ie. not local)) goto exit; } // step 2: get the shortcut file and the .manifest file if (FAILED(hr = uncfs.SetSourcePath(wzCodebase))) goto exit; if (FAILED(hr = uncfs.BuildLocalAppRootHierarchy(pAppName, wzLocalPath))) goto exit; if(!PathAppend(wzLocalPath, wzRefRealFilename)) { hr = E_FAIL; DbgMsg(L"path for .app fails"); goto exit; } if (FAILED(hr = uncfs.GetFile(wzRefFilePath, wzLocalPath))) // ignore E_UNEXPECTED? { DbgMsg(L"get .app fails"); goto exit; } *PathFindFileName(wzLocalPath) = L'\0'; p = PathFindFileName(wzCodebase); if (p == wzCodebase || !PathAppend(wzLocalPath, p)) { hr = E_FAIL; DbgMsg(L"path for .manifest fails"); goto exit; } if (FAILED(hr = uncfs.GetFile(p, wzLocalPath, NULL))) // ignore E_UNEXPECTED? { DbgMsg(L"get .manifest fails"); goto exit; } // step 3: process the .manifest file if (FAILED(hr = ProcessAppManifest(wzLocalPath, &uncfs, pAppName))) goto exit; exit: if (hr == E_ABORT) MsgShow(L"Operation aborted."); else if (FAILED(hr)) MsgShow(L"Error Encountered."); else { // if SUCCEEDED // do not overwrite if shortcut exists. ignore error // note: this should probably be done only in the "1st install" case // - ie. need feedback from ProcessAppManifest() CopyToStartMenu(wzRefFilePath, wzRefRealFilename, FALSE); } return hr; } ///////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// int __cdecl wmain( int argc, wchar_t *argv[], wchar_t *envp[] ) { BOOL isRefFileTemp = FALSE; LPWSTR pwzRef = NULL; LPWSTR pwzRefRealFilename = NULL; WCHAR wzCodebase[MAX_URL_LENGTH]; APPNAME appName; // BUGBUG: ** a hack to hide the console window when starts ** //- should convert this to a window-less WinMain app ShowWindow(GetConsoleWindow(), SW_HIDE); if (argc < 2) { MsgShow(L"No commandline argument specified"); goto exit; } if (PathFileExists(argv[1]) || PathIsUNC(argv[1])) { // ref local or on a UNC pwzRef = argv[1]; pwzRefRealFilename = PathFindFileName(argv[1]); if (pwzRefRealFilename == argv[1]) { MsgShow(L"Invalid file path"); goto exit; } } else if (PathIsURL(argv[1])) { // ref is from a URL if (argc < 3) { // arguments: // msg ambiguity is intented MsgShow(L"Invalid argument"); goto exit; } // should only be called this way by the mimefilter // if so, the ref file is a temp file that has to be deleted pwzRef = argv[2]; // note: will delete the file named by argv[2], the temp ref file isRefFileTemp = TRUE; pwzRefRealFilename = UrlFindFileName(argv[1]); if (pwzRefRealFilename == argv[1]) { MsgShow(L"Invalid file path"); goto exit; } } else { MsgShow(L"Invalid commandline argument specified"); goto exit; } wzCodebase[0] = L'\0'; appName._wzDisplayName[0] = L'\0'; appName._wzName[0] = L'\0'; appName._wzVersion[0] = L'\0'; appName._wzCulture[0] = L'\0'; appName._wzPKT[0] = L'\0'; // parse the shortcut to get the codebase if (FAILED(ProcessRef(pwzRef, &appName, wzCodebase))) { MsgShow(L".app file processing fails"); goto exit; } if (PathIsURL(wzCodebase)) { // note: this basically allows a ref file on a UNC pointing to // app files on a web server. possible security risk? // security token is still computed from the codebase, // ie, URL, though // ignore return value ProcessUrl(pwzRef, pwzRefRealFilename, &appName, wzCodebase); } else // default is UNC/local path (PathIsUNC(wzCodebase)) { // note: this allows a ref file on a web server // to run something from the disk or UNC. security? // security token is still computed from the codebase, // ie, UNC, though // ignore return value ProcessUNC(pwzRef, pwzRefRealFilename, &appName, wzCodebase); } exit: if (isRefFileTemp) { if (argv[2][0] != L'\0') { // ignore return value DeleteFile(argv[2]); } } return 0; }