|
|
/*
* a t t a c h . c p p * * Purpose: * Attachment utilities * * History * * Copyright (C) Microsoft Corp. 1995, 1996. */
#include <pch.hxx>
#include "dllmain.h"
#include "resource.h"
#include "error.h"
#include "mimeolep.h"
#include "shellapi.h"
#include "shlobj.h"
#include "shlwapi.h"
#include "shlwapip.h"
#include "mimeole.h"
#include "commdlg.h"
#include "demand.h"
#include "saferun.h"
ASSERTDATA
/*
* t y p e d e f s */
/*
* m a c r o s */
/*
* c o n s t a n t s */ #define MAX_CHARS_FOR_NUM 20
static const CHAR c_szWebMark[] = "<!-- saved from url=(0022)http://internet.e-mail -->\r\n"; static const WCHAR c_wszWebMark[] = L"<!-- saved from url=(0022)http://internet.e-mail -->\r\n"; /*
* g l o b a l s */
/*
* p r o t o t y p e s */ HRESULT HrCleanTempFile(LPATTACHDATA pAttach); HRESULT HrGetTempFile(IMimeMessage *pMsg, LPATTACHDATA lpAttach); DWORD AthGetShortPathName(LPCWSTR lpszLongPath, LPWSTR lpszShortPath, DWORD cchBuffer);
STDAPI HrGetAttachIconByFile(LPWSTR szFilename, BOOL fLargeIcon, HICON *phIcon) { HICON hIcon = NULL; LPWSTR lpszExt; SHFILEINFOW rShFileInfo;
if (szFilename) { // Does the file exist already ?
if ((UINT)GetFileAttributesWrapW(szFilename) != (UINT)-1) { // Try to get the icon out of the file
SHGetFileInfoWrapW(szFilename, 0, &rShFileInfo, sizeof(rShFileInfo), SHGFI_ICON |(fLargeIcon ? 0 : SHGFI_SMALLICON)); hIcon=rShFileInfo.hIcon; } else if (lpszExt = PathFindExtensionW(szFilename)) { // Lookup the icon for lpszExt
SHGetFileInfoWrapW(lpszExt, FILE_ATTRIBUTE_NORMAL, &rShFileInfo, sizeof (rShFileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_ICON | (fLargeIcon ? 0 : SHGFI_SMALLICON)); hIcon=rShFileInfo.hIcon; } }
if (!hIcon) hIcon = CopyIcon(LoadIcon (g_hLocRes, MAKEINTRESOURCE (idiDefaultAtt)));
*phIcon=hIcon; return S_OK; }
STDAPI HrGetAttachIcon(IMimeMessage *pMsg, HBODY hAttach, BOOL fLargeIcon, HICON *phIcon) { // Locals
HRESULT hr = S_OK; LPWSTR lpszFile=0;
if (!phIcon || !hAttach || !pMsg) return E_INVALIDARG;
*phIcon=NULL;
// Get file name for body part. If get an error, doesn't matter. Still use
// a default icon that will be provided through HrGetAttachIconByFile
MimeOleGetBodyPropW(pMsg, hAttach, PIDTOSTR(PID_ATT_GENFNAME), NOFLAGS, &lpszFile); hr = HrGetAttachIconByFile(lpszFile, fLargeIcon, phIcon); SafeMemFree(lpszFile); return hr; }
//
// GetUIVersion()
//
// returns the version of shell32
// 3 == win95 gold / NT4
// 4 == IE4 Integ / win98
// 5 == win2k / millennium
//
UINT GetUIVersion() { static UINT s_uiShell32 = 0;
if (s_uiShell32 == 0) { HINSTANCE hinst = LoadLibrary("SHELL32.DLL"); if (hinst) { DLLGETVERSIONPROC pfnGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinst, "DllGetVersion"); DLLVERSIONINFO dllinfo;
dllinfo.cbSize = sizeof(DLLVERSIONINFO); if (pfnGetVersion && pfnGetVersion(&dllinfo) == NOERROR) s_uiShell32 = dllinfo.dwMajorVersion; else s_uiShell32 = 3;
FreeLibrary(hinst); } } return s_uiShell32; }
STDAPI HrDoAttachmentVerb(HWND hwnd, ULONG uVerb, IMimeMessage *pMsg, LPATTACHDATA pAttach) { HRESULT hr = S_OK; SHELLEXECUTEINFOW rShellExec; LPSTREAM lpstmAtt = NULL; LPWSTR lpszShortName = NULL, lpszParameters = NULL, lpszExt = NULL; DWORD dwFlags; WCHAR szCommand[MAX_PATH]; HKEY hKeyAssoc = NULL;
AssertSz( uVerb < AV_MAX, "Bad Verb");
if (uVerb == AV_PROPERTIES) { AssertSz(FALSE, "AV_PROPERTIES is NYI!!"); return E_NOTIMPL; } if (!pAttach) return E_INVALIDARG; // Save As - much simpler case
if (uVerb == AV_SAVEAS) { hr=HrSaveAttachmentAs(hwnd, pMsg, pAttach); goto error; // done
} // If opening attachment, lets verify thsi
if (uVerb == AV_OPEN) { // If nVerb is to open the attachment, lets verify that with the user
hr = IsSafeToRun(hwnd, pAttach->szFileName, TRUE); if (hr == MIMEEDIT_E_USERCANCEL) // map mimeedit error to athena error
hr = hrUserCancel; if (FAILED(hr)) // user doesn't want to do this
goto error; if (hr == MIMEEDIT_S_SAVEFILE) { hr=HrSaveAttachmentAs(hwnd, pMsg, pAttach); // done
goto error; } } // get temp file
hr = HrGetTempFile(pMsg, pAttach); if (FAILED(hr)) goto error; Assert(lstrlenW(pAttach->szTempFile)); // Setup Shell Execute Info Struct
ZeroMemory (&rShellExec, sizeof (rShellExec)); rShellExec.cbSize = sizeof (rShellExec); rShellExec.fMask = SEE_MASK_NOCLOSEPROCESS; rShellExec.hwnd = hwnd; rShellExec.nShow = SW_SHOWNORMAL; // Verb
if (uVerb == AV_OPEN) { // Were going to run the file
hr = VerifyTrust(hwnd, pAttach->szFileName, pAttach->szTempFile); if (FAILED(hr)) { hr = hrUserCancel; goto error; } StrCpyNW(szCommand, pAttach->szTempFile, ARRAYSIZE(szCommand)); rShellExec.lpFile = szCommand; // If the file does not have an associated type, do an OpenAs.
// We're not testing the result of AssocQueryKeyW because even if it fails,
// we want to try to open the file.
lpszExt = PathFindExtensionW(pAttach->szTempFile); AssocQueryKeyW(NULL, ASSOCKEY_CLASS, lpszExt, NULL, &hKeyAssoc); if((hKeyAssoc == NULL) && (GetUIVersion() != 5)) rShellExec.lpVerb = L"OpenAs"; else RegCloseKey(hKeyAssoc); } else if (uVerb == AV_PRINT) { StrCpyNW(szCommand, pAttach->szTempFile, ARRAYSIZE(szCommand)); rShellExec.lpFile = szCommand; rShellExec.lpVerb = L"Print"; } else if (uVerb == AV_QUICKVIEW) { UINT uiSysDirLen; const WCHAR c_szSubDir[] = L"\\VIEWERS\\QUIKVIEW.EXE"; // Find out where the viewer lives
uiSysDirLen = GetSystemDirectoryWrapW(szCommand, ARRAYSIZE(szCommand)); if (0 == uiSysDirLen || uiSysDirLen >= ARRAYSIZE(szCommand) || uiSysDirLen + ARRAYSIZE(c_szSubDir) > ARRAYSIZE(szCommand)) { hr = E_FAIL; goto error; } StrCpyNW(szCommand + uiSysDirLen, c_szSubDir, ARRAYSIZE(szCommand) - uiSysDirLen); // Alloc for short file name
ULONG cchShortName = MAX_PATH + lstrlenW(pAttach->szTempFile) + 1; if (!MemAlloc ((LPVOID *)&lpszShortName, cchShortName * sizeof (WCHAR))) { hr = E_OUTOFMEMORY; goto error; } // Alloc a string for the parameters
ULONG cchParameters = 30 + cchShortName; if (!MemAlloc ((LPVOID *)&lpszParameters, cchParameters * sizeof (WCHAR))) { hr = E_OUTOFMEMORY; goto error; } // Get Short File Name
if (0 == AthGetShortPathName(pAttach->szTempFile, lpszShortName, cchShortName)) StrCpyNW(lpszShortName, pAttach->szTempFile, cchShortName); // Put together the paramenters for QVSTUB.EXE
Assert(cchParameters > cchShortName); StrCpyNW(lpszParameters, L"-v -f:", cchParameters); StrCatBuffW(lpszParameters, lpszShortName, cchParameters); // Setup Shellexec
rShellExec.lpParameters = lpszParameters; rShellExec.lpFile = szCommand; } else Assert (FALSE); if (fIsNT5()) // quoted paths cause problems downlevel
PathQuoteSpacesW(szCommand);
// Execute it - even if this fails, we handled it - it will give a good error
ShellExecuteExWrapW(&rShellExec); pAttach->hProcess = rShellExec.hProcess; error: MemFree(lpszParameters); MemFree(lpszShortName); return hr; }
DWORD AthGetShortPathName(LPCWSTR pwszLongPath, LPWSTR pwszShortPath, DWORD cchBuffer) { CHAR szShortPath[MAX_PATH*2]; // Each Unicode char might go multibyte
LPSTR pszLongPath = NULL; DWORD result = 0;
Assert(pwszLongPath); pszLongPath = PszToANSI(CP_ACP, pwszLongPath);
if (pszLongPath) { result = GetShortPathName(pszLongPath, szShortPath, ARRAYSIZE(szShortPath)); if (result && result <= ARRAYSIZE(szShortPath)) { MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szShortPath, lstrlen(szShortPath), pwszShortPath, cchBuffer); pwszShortPath[cchBuffer - 1] = 0; }
MemFree(pszLongPath); }
return result; }
STDAPI HrAttachDataFromBodyPart(IMimeMessage *pMsg, HBODY hAttach, LPATTACHDATA *ppAttach) { LPATTACHDATA pAttach; LPWSTR pszW; IMimeBodyW *pBody;
Assert (pMsg && ppAttach && hAttach);
if (!MemAlloc((LPVOID *)&pAttach, sizeof(ATTACHDATA))) return E_OUTOFMEMORY;
// fill in attachment data
ZeroMemory(pAttach, sizeof(ATTACHDATA));
if (pMsg->BindToObject(hAttach, IID_IMimeBodyW, (LPVOID *)&pBody)==S_OK) { if (pBody->GetDisplayNameW(&pszW)==S_OK) { StrCpyNW(pAttach->szDisplay, pszW, ARRAYSIZE(pAttach->szDisplay)); MemFree(pszW); } ReleaseObj(pBody); } if (MimeOleGetBodyPropW(pMsg, hAttach, PIDTOSTR(PID_ATT_GENFNAME), NOFLAGS, &pszW)==S_OK) { if(IsPlatformWinNT() != S_OK) { CHAR pszFile[MAX_PATH*2]; DWORD cchSizeW = (lstrlenW(pszW) + 1);
WideCharToMultiByte(CP_ACP, 0, pszW, -1, pszFile, ARRAYSIZE(pszFile), NULL, NULL); pszFile[ARRAYSIZE(pszFile) - 1] = '\0'; MultiByteToWideChar(CP_ACP, 0, pszFile, -1, pszW, cchSizeW); pszW[cchSizeW - 1] = 0;
CleanupFileNameInPlaceW(pszW); }
StrCpyNW(pAttach->szFileName, pszW, ARRAYSIZE(pAttach->szFileName)); MemFree(pszW); } SideAssert(HrGetAttachIcon(pMsg, hAttach, FALSE, &pAttach->hIcon)==S_OK); pAttach->hAttach = hAttach; pAttach->fSafe = (IsSafeToRun(NULL, pAttach->szFileName, FALSE) == MIMEEDIT_S_OPENFILE); *ppAttach = pAttach; return S_OK; }
STDAPI HrAttachDataFromFile(IStream *pstm, LPWSTR pszFileName, LPATTACHDATA *ppAttach) { LPATTACHDATA pAttach=0; LPMIMEBODY pBody=0; HRESULT hr; int cFileNameLength;
Assert(ppAttach);
if (!MemAlloc((LPVOID *)&pAttach, sizeof(ATTACHDATA))) return E_OUTOFMEMORY;
// fill in attachment data
ZeroMemory(pAttach, sizeof(ATTACHDATA));
HrGetDisplayNameWithSizeForFile(pszFileName, pAttach->szDisplay, ARRAYSIZE(pAttach->szDisplay)); StrCpyNW(pAttach->szFileName, pszFileName, ARRAYSIZE(pAttach->szFileName)); if (!pstm) { // for new attachments set tempfile to be the same as filename
// note: if creating from an IStream then pszFileName is not a valid path
// we can create a tempfile later
StrCpyNW(pAttach->szTempFile, pszFileName, ARRAYSIZE(pAttach->szTempFile)); } ReplaceInterface(pAttach->pstm, pstm); SideAssert(HrGetAttachIconByFile(pszFileName, FALSE, &pAttach->hIcon)==S_OK); if (ppAttach) *ppAttach=pAttach; return S_OK; }
STDAPI HrFreeAttachData(LPATTACHDATA pAttach) { if (pAttach) { HrCleanTempFile(pAttach); ReleaseObj(pAttach->pstm); if (pAttach->hIcon) DestroyIcon(pAttach->hIcon); MemFree(pAttach); } return NOERROR; }
HRESULT HrCleanTempFile(LPATTACHDATA pAttach) { if (pAttach) { if (*pAttach->szTempFile && pAttach->hAttach) { // we only clean the tempfile if hAttach != NULL. Otherwise we assume it's a new attachment
// and szTempFile points to the source file
// If the file was launched, don't delete the temp file if the process still has it open
if (pAttach->hProcess) { if (WaitForSingleObject (pAttach->hProcess, 0) == WAIT_OBJECT_0) DeleteFileWrapW(pAttach->szTempFile); } else DeleteFileWrapW(pAttach->szTempFile); } *pAttach->szTempFile = NULL; pAttach->hProcess=NULL; } return NOERROR; }
HRESULT HrAttachSafetyFromBodyPart(IMimeMessage *pMsg, HBODY hAttach, BOOL *pfSafe) { LPWSTR pszW = NULL;
Assert (pMsg && pfSafe && hAttach);
*pfSafe = FALSE; if (MimeOleGetBodyPropW(pMsg, hAttach, PIDTOSTR(PID_ATT_GENFNAME), NOFLAGS, &pszW)==S_OK) { if(IsPlatformWinNT() != S_OK) { CHAR pszFile[MAX_PATH*2]; DWORD cchSizeW = lstrlenW(pszW)+1;
WideCharToMultiByte(CP_ACP, 0, pszW, -1, pszFile, ARRAYSIZE(pszFile), NULL, NULL); pszFile[ARRAYSIZE(pszFile) - 1] = 0; MultiByteToWideChar(CP_ACP, 0, pszFile, -1, pszW, cchSizeW); pszW[cchSizeW - 1] = 0;
CleanupFileNameInPlaceW(pszW); } *pfSafe = (IsSafeToRun(NULL, pszW, FALSE) == MIMEEDIT_S_OPENFILE); MemFree(pszW); }
return S_OK; }
STDAPI HrGetDisplayNameWithSizeForFile(LPWSTR pszPathName, LPWSTR pszDisplayName, int cchMaxDisplayName) { HANDLE hFile; DWORD uFileSize; WCHAR szSize[MAX_CHARS_FOR_NUM+1+3], szBuff[MAX_CHARS_FOR_NUM+1]; LPWSTR pszFileName = NULL, pszFirst; int iSizeLen = 0, iLenFirst;
szSize[0] = L'\0';
hFile = CreateFileWrapW(pszPathName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != hFile) { uFileSize = GetFileSize(hFile, NULL); CloseHandle(hFile); if ((uFileSize != 0xffffffff) && StrFormatByteSizeW(uFileSize, szBuff, ARRAYSIZE(szBuff) - 1)) { StrCpyNW(szSize, L" (", ARRAYSIZE(szSize)); StrCatBuffW(szSize, szBuff, ARRAYSIZE(szSize)); StrCatBuffW(szSize, L")", ARRAYSIZE(szSize)); } } pszFileName = PathFindFileNameW(pszPathName);
iSizeLen = lstrlenW(szSize); if (pszFileName) pszFirst = pszFileName; else pszFirst = pszPathName;
iLenFirst = lstrlenW(pszFirst); StrCpyNW(pszDisplayName, pszFirst, cchMaxDisplayName);
if (iLenFirst + iSizeLen + 1 > cchMaxDisplayName) return E_FAIL;
StrCpyNW(pszDisplayName + iLenFirst, szSize, cchMaxDisplayName - iLenFirst); return S_OK; }
STDAPI HrSaveAttachmentAs(HWND hwnd, IMimeMessage *pMsg, LPATTACHDATA lpAttach) { HRESULT hr = S_OK; OPENFILENAMEW ofn; WCHAR szTitle[CCHMAX_STRINGRES], szFilter[CCHMAX_STRINGRES], szFile[MAX_PATH];
*szFile=0; *szFilter=0; *szTitle=0;
Assert (lpAttach->szFileName); if (lpAttach->szFileName) StrCpyNW(szFile, lpAttach->szFileName, ARRAYSIZE(szFile));
ZeroMemory (&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwnd; LoadStringWrapW(g_hLocRes, idsFilterAttSave, szFilter, ARRAYSIZE(szFilter)); ReplaceCharsW(szFilter, L'|', L'\0'); ofn.lpstrFilter = szFilter; ofn.nFilterIndex = 1; ofn.lpstrFile = szFile; ofn.nMaxFile = ARRAYSIZE(szFile); LoadStringWrapW(g_hLocRes, idsSaveAttachmentAs, szTitle, ARRAYSIZE(szTitle)); ofn.lpstrTitle = szTitle; ofn.Flags = OFN_NOCHANGEDIR | OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
// Show SaveAs Dialog
if (HrAthGetFileNameW(&ofn, FALSE) != S_OK) { hr = hrUserCancel; goto error; } if (lpAttach->hAttach == NULL) { if (!PathFileExistsW(lpAttach->szFileName)) { hr = hrNotFound; goto error; }
// if hAttach == NULL then try and copy the file
CopyFileWrapW(lpAttach->szFileName, szFile, TRUE); } else { // Verify the Attachment's Stream
hr=HrSaveAttachToFile(pMsg, lpAttach->hAttach, szFile); if (FAILED(hr)) goto error; } error: return hr; }
HRESULT HrGetTempFile(IMimeMessage *pMsg, LPATTACHDATA lpAttach) { HRESULT hr; if (*lpAttach->szTempFile) return S_OK; if (!FBuildTempPathW(lpAttach->szFileName, lpAttach->szTempFile, ARRAYSIZE(lpAttach->szTempFile), FALSE)) { hr = E_FAIL; goto error; } if (lpAttach->hAttach) { hr=HrSaveAttachToFile(pMsg, lpAttach->hAttach, lpAttach->szTempFile); if (FAILED(hr)) goto error; } else { AssertSz(lpAttach->pstm, "if no hAttach then pstm should be set"); hr = WriteStreamToFileW(lpAttach->pstm, lpAttach->szTempFile, CREATE_ALWAYS, GENERIC_WRITE); if (FAILED(hr)) goto error; } error: if (FAILED(hr)) { // Null out temp file as we didn't really create it
*(lpAttach->szTempFile)=0; } return hr; }
const BYTE c_rgbUTF[3] = {0xEF, 0xBB, 0xBF}; STDAPI HrSaveAttachToFile(IMimeMessage *pMsg, HBODY hAttach, LPWSTR lpszFileName) { HRESULT hr; LPSTREAM pstm=NULL, pstmOut=NULL; BOOL fEndian, fUTFEncoded = FALSE; BYTE rgbBOM[2]; BYTE rgbUTF[3]; DWORD cbRead;
if (pMsg == NULL || hAttach == NULL) IF_FAILEXIT(hr = E_INVALIDARG);
// bind to the attachment data
IF_FAILEXIT(hr=pMsg->BindToObject(hAttach, IID_IStream, (LPVOID *)&pstm));
// create a file stream
IF_FAILEXIT(hr = OpenFileStreamW(lpszFileName, CREATE_ALWAYS, GENERIC_WRITE, &pstmOut));
// if we have an .HTM file, then pre-pend 'mark of the web' comment
// If we are a unicode file, the BOM will be "0xFFFE"
// If we are a UTF8 file, the BOM will be "0xEFBBBF"
if (PathIsHTMLFileW(lpszFileName)) { if (S_OK == HrIsStreamUnicode(pstm, &fEndian)) { // Don't rewind otherwise end up with BOM after 'mark of the web' as well.
IF_FAILEXIT(hr = pstm->Read(rgbBOM, sizeof(rgbBOM), &cbRead));
// Since HrIsStreamUnicode succeeded, there should be at least two
Assert(sizeof(rgbBOM) == cbRead);
IF_FAILEXIT(hr = pstmOut->Write(rgbBOM, cbRead, NULL)); IF_FAILEXIT(hr = pstmOut->Write(c_wszWebMark, sizeof(c_wszWebMark)-sizeof(WCHAR), NULL)); } else { // Check for UTF8 file BOM
IF_FAILEXIT(hr = pstm->Read(rgbUTF, sizeof(rgbUTF), &cbRead)); if (sizeof(rgbUTF) == cbRead) { fUTFEncoded = (0 == memcmp(c_rgbUTF, rgbUTF, sizeof(rgbUTF))); }
// If we are not UTF8 encoded, then rewind, else write out BOM
if (!fUTFEncoded) IF_FAILEXIT(hr = HrRewindStream(pstm)); else IF_FAILEXIT(hr = pstmOut->Write(c_rgbUTF, sizeof(c_rgbUTF), NULL));
IF_FAILEXIT(hr = pstmOut->Write(c_szWebMark, sizeof(c_szWebMark)-sizeof(CHAR), NULL));
} } // write out the actual file data
IF_FAILEXIT(hr = HrCopyStream(pstm, pstmOut, NULL));
exit: ReleaseObj(pstm); ReleaseObj(pstmOut); return hr; }
/*
* Why? * * we wrap this as if we don't use NOCHANGEDIR, then things like ShellExec * fail if the current directory is nolonger valid. Eg: attach a file from a:\ * and remove the floppy. Then all ShellExec's fail. So we maintain our own * last directory buffer. We should use thread-local for this, as it is possible * that two thread could whack the same buffer, it is unlikley that a user action * could cause two open file dialogs in the note and the view to open at exactly the * same time. */
WCHAR g_wszLastDir[MAX_PATH];
HRESULT SetDefaultSpecialFolderPath() { LPITEMIDLIST pidl = NULL; HRESULT hr = E_FAIL;
if (SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl)==S_OK) { if (SHGetPathFromIDListWrapW(pidl, g_wszLastDir)) hr = S_OK; SHFree(pidl); } return hr; }
STDAPI HrAthGetFileName(OPENFILENAME *pofn, BOOL fOpen) { BOOL fRet; LPSTR pszDir = NULL; HRESULT hr = S_OK;
Assert(pofn != NULL);
// force NOCHANGEDIR
pofn->Flags |= OFN_NOCHANGEDIR;
if (pofn->lpstrInitialDir == NULL) { if (!PathFileExistsW(g_wszLastDir)) SideAssert(SetDefaultSpecialFolderPath()==S_OK); IF_NULLEXIT(pszDir = PszToANSI(CP_ACP, g_wszLastDir)); pofn->lpstrInitialDir = pszDir; }
if (fOpen) fRet = GetOpenFileName(pofn); else fRet = GetSaveFileName(pofn); if (fRet) { // store the last path
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pofn->lpstrFile, lstrlen(pofn->lpstrFile), g_wszLastDir, ARRAYSIZE(g_wszLastDir)); if (!PathIsDirectoryW(g_wszLastDir)) PathRemoveFileSpecW(g_wszLastDir); } else TraceResult(hr = E_FAIL);
exit: MemFree(pszDir); return hr; }
STDAPI HrAthGetFileNameW(OPENFILENAMEW *pofn, BOOL fOpen) { BOOL fRet;
Assert(pofn != NULL);
// force NOCHANGEDIR
pofn->Flags |= OFN_NOCHANGEDIR;
if (pofn->lpstrInitialDir == NULL) { if (!PathFileExistsW(g_wszLastDir)) SideAssert(SetDefaultSpecialFolderPath()==S_OK); pofn->lpstrInitialDir = g_wszLastDir; }
if (fOpen) fRet = GetOpenFileNameWrapW(pofn); else fRet = GetSaveFileNameWrapW(pofn); if (fRet) { // store the last path
StrCpyNW(g_wszLastDir, pofn->lpstrFile, ARRAYSIZE(g_wszLastDir)); if (!PathIsDirectoryW(g_wszLastDir)) PathRemoveFileSpecW(g_wszLastDir); } return fRet?S_OK:E_FAIL; }
STDAPI HrGetLastOpenFileDirectory(int cchMax, LPSTR lpsz) { if (!PathFileExistsW(g_wszLastDir)) SideAssert(SetDefaultSpecialFolderPath()==S_OK);
WideCharToMultiByte(CP_ACP, 0, g_wszLastDir, lstrlenW(g_wszLastDir), lpsz, cchMax, NULL, NULL); lpsz[cchMax - 1] = 0; return S_OK; }
STDAPI HrGetLastOpenFileDirectoryW(int cchMax, LPWSTR lpsz) { if (!PathFileExistsW(g_wszLastDir)) SideAssert(SetDefaultSpecialFolderPath()==S_OK);
StrCpyNW(lpsz, g_wszLastDir, cchMax); return S_OK; }
|