|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1994
//
// File: persist.cxx
//
// Contents: Implmentation of Office9 Thicket Save API
//
//----------------------------------------------------------------------------
#include "priv.h"
//#include "headers.hxx"
//#include "formkrnl.hxx"
#include <platform.h>
#include <mlang.h>
#include "resource.h"
#include "impexp.h"
#include "reload.h"
//#include <siterc.h>
#include "packager.h"
#include "iehelpid.h"
#include "thicket.h"
#include "apithk.h"
#include <mluisupp.h>
#include <mshtmcid.h>
#define NUM_OLE_CMDS 1
#define SAVEAS_OK 0x00000001
#define SAVEAS_NEVER_ASK_AGAIN 0x00000002
#define CODEPAGE_UNICODE 0x000004B0
#define CODEPAGE_UTF8 0x0000FDE9
#define UNICODE_TEXT TEXT("Unicode")
#define REGSTR_VAL_SAVEDIRECTORY TEXT("Save Directory")
#define REGKEY_SAVEAS_WARNING_RESTRICTION TEXT("SOFTWARE\\Microsoft\\Internet Explorer\\Main")
#define REGVALUE_SAVEAS_WARNING TEXT("NoSaveAsPOSTWarning")
#define WM_WORKER_THREAD_COMPLETED WM_USER + 1000
#define MAX_ENCODING_DESC_LEN 1024
const static DWORD aSaveAsHelpIDs[] = { IDC_SAVE_CHARSET, IDH_CHAR_SET_SAVE_AS, 0, 0 };
INT_PTR CALLBACK SaveAsWarningDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
HRESULT SaveToThicket( HWND hwnd, LPCTSTR pszFileName, IHTMLDocument2 *pDoc, UINT codepageSrc, UINT codepageDst, UINT iPackageStyle );
HRESULT FormsGetFileName( HWND hwndOwner, LPTSTR pstrFile, int cchFile, LPARAM lCustData, DWORD *pnFilterIndex, BOOL bForceHTMLOnly); HRESULT GetFileNameFromURL( LPWSTR pwszURL, LPTSTR pszFile, DWORD cchFile);
void ReportThicketError( HWND hwnd, HRESULT hr );
#define DOWNLOAD_PROGRESS 0x9001
#define DOWNLOAD_COMPLETE 0x9002
#define THICKET_TIMER 0x9003
#define THICKET_INTERVAL 1000
#define MDLGMSG(psz, x) TraceMsg(0, "shd TR-MODELESS::%s %x", psz, x)
static DWORD s_dwInetComVerMS = 0; static DWORD s_dwInetComVerLS = 0;
struct ThicketCPInfo { UINT cpSrc; UINT cpDst; LPWSTR lpwstrDocCharSet; };
class CThicketUI { public: CThicketUI(void) : _hDlg(NULL), _hWndProg(NULL), _iErrorDL(0), _hrDL(E_FAIL), #ifndef NO_MARSHALLING
_pstmDoc(NULL), #else
_pDoc(NULL), #endif
_pszFileName(NULL), _dwDLMax(0), _codepageSrc(0), _codepageDst(0), _iPackageStyle(PACKAGE_THICKET), _fCancel(FALSE) {};
~CThicketUI(void) { #ifndef NO_MARSHALLING
SAFERELEASE(_pstmDoc); #endif
SAFELOCALFREE(_pszFileName); };
// CThicketUI methods
HRESULT SaveDocument( HWND hWnd, LPCTSTR pszFileName, IHTMLDocument2 *pDoc, UINT codepageSrc, UINT codepageDst, UINT iPackageStyle );
protected: static BOOL_PTR ThicketUIDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); static DWORD WINAPI ThicketUIThreadProc( LPVOID );
BOOL DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
HWND _hDlg; HWND _hWndProg; int _iErrorDL; HRESULT _hrDL; #ifndef UNIX
IStream *_pstmDoc; // marshalled IHTMLDocument2
#else
IHTMLDocument2 *_pDoc; #endif
LPTSTR _pszFileName; DWORD _dwDLMax; UINT _codepageSrc; UINT _codepageDst; BOOL _fThreadStarted; UINT _iPackageStyle; BOOL _fCancel; };
HRESULT CThicketUI::SaveDocument( HWND hWnd, LPCTSTR pszFileName, IHTMLDocument2 *pDoc, UINT codepageSrc, UINT codepageDst, UINT iPackageStyle) { _pszFileName = StrDup(pszFileName); _codepageSrc = codepageSrc; _codepageDst = codepageDst; _iPackageStyle = iPackageStyle;
#ifndef NO_MARSHALLING
// We don't do anything with pDoc until we're on the worker thread,
// so marshall it.
_hrDL = CoMarshalInterThreadInterfaceInStream(IID_IHTMLDocument2, pDoc, &_pstmDoc);
if (SUCCEEDED(_hrDL)) #else
_pDoc = pDoc; #endif
{ // Needs to be modal cuz we're going to work with pDoc on the worker thread
// so we don't want the user to navigate away from it, close the window, etc.
DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(IDD_SAVETHICKET), hWnd, CThicketUI::ThicketUIDlgProc, (LPARAM)this);
// HWND hwnd = MLCreateDialogParamWrap(MLGetHinst(), MAKEINTRESOURCE(IDD_SAVETHICKET),
// NULL, CThicketUI::ThicketUIDlgProc, (LPARAM)this);
// if (!hwnd)
// _hrDL = E_FAIL;
}
return _hrDL; }
BOOL_PTR CThicketUI::ThicketUIDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { BOOL fRet = FALSE; CThicketUI* ptui = NULL;
if (msg == WM_INITDIALOG) { ptui = (CThicketUI*)lParam; } else ptui = (CThicketUI*)GetWindowLongPtr(hDlg, DWLP_USER);
if (ptui) { fRet = ptui->DlgProc(hDlg, msg, wParam, lParam);
if (msg == WM_DESTROY || msg == WM_WORKER_THREAD_COMPLETED) { SetWindowLongPtr(hDlg, DWLP_USER, lParam); fRet = TRUE; } }
return fRet; }
BOOL CThicketUI::DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { BOOL fRet = TRUE;
switch (msg) { case WM_INITDIALOG: _hDlg = hDlg; _hWndProg = GetDlgItem(hDlg, IDC_THICKETPROGRESS); SetWindowLongPtr(hDlg, DWLP_USER, lParam);
_hrDL = S_FALSE;
#ifndef NO_MARSHALLING
//_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) ThicketUIThreadProc, this, 0, &_idThread);
if (!(_fThreadStarted = SHQueueUserWorkItem(ThicketUIThreadProc, this, 0, (DWORD_PTR)NULL, (DWORD_PTR *)NULL, "shdocvw.dll", TPS_LONGEXECTIME))) _hrDL = E_FAIL; #else
ThicketUIThreadProc((LPVOID)this); #endif
if (FAILED(_hrDL)) EndDialog(hDlg, 0); else { ShowWindow(hDlg, SW_SHOWNORMAL); Animate_OpenEx(GetDlgItem(hDlg, IDD_ANIMATE), HINST_THISDLL, IDA_DOWNLOAD); ShowWindow(GetDlgItem(hDlg, IDD_DOWNLOADICON), SW_HIDE); } fRet = FALSE; break;
case WM_COMMAND: switch (LOWORD(wParam)) { case IDCANCEL: _fCancel = TRUE; // and wait for the worker thread to quit, polling at WM_TIMER
break;
default: break; } break;
case WM_WORKER_THREAD_COMPLETED: _hrDL = (DWORD) wParam; EndDialog(hDlg,0); break;
//case WM_CLOSE:
// KillTimer( hDlg, THICKET_TIMER );
// _fCancel = TRUE;
// while( _hrDL == S_FALSE );
// break;
case WM_DESTROY: _fCancel = TRUE; while( _hrDL == S_FALSE ) { Sleep(0); } break;
default: fRet = FALSE; }
return fRet; }
DWORD WINAPI CThicketUI::ThicketUIThreadProc( LPVOID ppv ) { HRESULT hr = S_OK; CThicketUI* ptui = (CThicketUI *)ppv;
ASSERT(ptui);
hr = CoInitialize(NULL); if (SUCCEEDED(hr)) { IHTMLDocument2 *pDoc = NULL;
#ifndef NO_MARSHALLING
hr = CoGetInterfaceAndReleaseStream( ptui->_pstmDoc, IID_IHTMLDocument2,(LPVOID*)&pDoc);
// CoGetInterfaceAndReleaseStream always releases the stream
ptui->_pstmDoc = NULL; #else
pDoc = ptui->_pDoc; pDoc->AddRef(); #endif
if (SUCCEEDED(hr)) { CThicketProgress tprog( ptui->_hDlg ); CDocumentPackager docPkgr(ptui->_iPackageStyle);
hr = S_FALSE;
hr = docPkgr.PackageDocument( pDoc, ptui->_pszFileName, &ptui->_fCancel, &tprog, 0, 100, ptui->_codepageDst );
pDoc->Release(); // release marshalled interface
}
CoUninitialize(); }
PostMessage(ptui->_hDlg, WM_WORKER_THREAD_COMPLETED, hr, 0);
return 0; }
//+------------------------------------------------------------------------
//
//
//
//-------------------------------------------------------------------------
HRESULT SaveToThicket( HWND hWnd, LPCTSTR pszFileName, IHTMLDocument2 *pDoc, UINT codepageSrc, UINT codepageDst, UINT iPackageStyle ) { HRESULT hr; CThicketUI* ptui;
#ifdef OLD_THICKET
LPTSTR lpszURL;
lpszURL = bstrDocURL;
const DWORD dwMaxPathLen = 24;
URL_COMPONENTS urlComp; TCHAR rgchUrlPath[MAX_PATH]; TCHAR rgchCanonicalUrl[MAX_URL_STRING]; DWORD dwLen;
dwLen = ARRAYSIZE(rgchCanonicalUrl);
hr = UrlCanonicalize( lpszURL, rgchCanonicalUrl, &dwLen, 0); if (FAILED(hr)) return E_FAIL;
ZeroMemory(&urlComp, sizeof(urlComp));
urlComp.dwStructSize = sizeof(urlComp); urlComp.lpszUrlPath = rgchUrlPath; urlComp.dwUrlPathLength = ARRAYSIZE(rgchUrlPath);
hr = InternetCrackUrl(rgchCanonicalUrl, lstrlen(rgchCanonicalUrl), ICU_DECODE, &urlComp); if (FAILED(hr)) return E_FAIL;
// Since this is not a snap-shot, saving the doc over itself is a no-op.
// This means we can avoid some nasty issues with the save-over, safe-save,
// et al, by short circuiting the save here.
if ( StrCmpI(pszFileName, rgchUrlPath) == 0 ) { if (PathFileExists(pszFileName)) return S_OK; else return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); }
#endif //OLD_THICKET
ptui = new CThicketUI; if (ptui) { hr = ptui->SaveDocument( hWnd, pszFileName, pDoc, codepageSrc, codepageDst, iPackageStyle ); delete ptui; } else hr = E_OUTOFMEMORY;
return hr; }
//+------------------------------------------------------------------------
//
//
//
//-------------------------------------------------------------------------
void SaveBrowserFile( HWND hwnd, LPUNKNOWN punk ) { HRESULT hr; TCHAR szFileDst[MAX_PATH]; DWORD iFilter = 1; IHTMLDocument2 *pDoc; BSTR bstrURL = NULL; ThicketCPInfo tcpi; BSTR bstrCharSet = NULL; BSTR bstrTitle = NULL; BSTR bstrMime = NULL; IOleCommandTarget *pOleCommandTarget = NULL; WCHAR *pwzExt = NULL; OLECMD pCmd[NUM_OLE_CMDS]; ULONG nCmds = NUM_OLE_CMDS; BOOL bForceHTMLOnly = FALSE;
static const WCHAR *wzImage = L" Image";
hr = punk->QueryInterface(IID_IHTMLDocument2, (void**)&pDoc); if (FAILED(hr)) goto Cleanup;
if (FAILED(pDoc->get_URL( &bstrURL ))) goto Cleanup;
hr = pDoc->get_charset( &bstrCharSet ); if (FAILED(hr)) goto Cleanup;
tcpi.cpSrc = CP_ACP; tcpi.lpwstrDocCharSet = bstrCharSet;
// If it is an image file, then bring up trident to do the save.
// APPCOMPAT: This is a crappy way to do this. We are hard-coding the
// image types, so we know to put up the "Save as image" dialog.
// We originally tried looking at the MIME type, but Trident returns
// inconsistent MIME types to us (ex. under some platforms we get
// "JPG Image" and under others we get "JPG File"!).
ASSERT(bstrURL);
pwzExt = bstrURL + lstrlenW(bstrURL);
while (pwzExt > bstrURL && *pwzExt != L'.') { pwzExt--; }
hr = pDoc->QueryInterface(IID_IOleCommandTarget, (void **)&pOleCommandTarget); if (FAILED(hr)) { goto Cleanup; }
if (pwzExt > bstrURL) {
// Found a "dot". Now pwzExt points to what we think is the extension
if (!StrCmpIW(pwzExt, L".JPG") || !StrCmpIW(pwzExt, L".GIF") || !StrCmpIW(pwzExt, L".BMP") || !StrCmpIW(pwzExt, L".XBM") || !StrCmpIW(pwzExt, L".ART") || !StrCmpIW(pwzExt, L".PNG") || !StrCmpIW(pwzExt, L".WMF") || !StrCmpIW(pwzExt, L".TIFF") || !StrCmpIW(pwzExt, L".JPEG")) { hr = pOleCommandTarget->Exec(&CGID_MSHTML, IDM_SAVEPICTURE, 0, NULL, NULL);
// FEATURE: Handle a failed HR here. It is very unlikely that
// this will fail, yet regular save-as code (that follows)
// will succeed. We always exit out of here, so we will
// never get two UI dialogs thrown at the user. We should
// come up with a good scheme to propagate an error dialog
// to the user. Possible scenario: low disk space causing
// a fail-out.
goto Cleanup; } }
// IE5 RAID #54672: Save-as has problems saving pages generated by POSTs
// This code is to detect if the page was generated by POST data and
// warn the user that saving may not work.
pCmd[0].cmdID = SHDVID_PAGEFROMPOSTDATA; hr = pOleCommandTarget->QueryStatus(&CGID_ShellDocView, nCmds, pCmd, NULL);
if (FAILED(hr)) { goto Cleanup; }
if (pCmd[0].cmdf & OLECMDF_LATCHED) { HKEY hkeySaveAs = 0; DWORD dwValue = 0; DWORD dwSize = 0; INT_PTR iFlags = 0;
bForceHTMLOnly = TRUE;
if (RegOpenKeyEx(HKEY_CURRENT_USER, REGKEY_SAVEAS_WARNING_RESTRICTION, 0, KEY_READ, &hkeySaveAs) == ERROR_SUCCESS) { dwSize = sizeof(DWORD);
if (RegQueryValueEx(hkeySaveAs, REGVALUE_SAVEAS_WARNING, NULL, NULL, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS) {
if (dwValue) { // restriction set, don't show dialog
RegCloseKey(hkeySaveAs); goto Continue; } }
RegCloseKey(hkeySaveAs); }
iFlags = DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(DLG_SAVEAS_WARNING), hwnd, SaveAsWarningDlgProc, (LPARAM)0);
if (!(iFlags & SAVEAS_OK)) { goto Cleanup; } if (iFlags & SAVEAS_NEVER_ASK_AGAIN) { HKEY hkey = 0; DWORD dwNeverAsk = 1;
if (RegOpenKeyEx(HKEY_CURRENT_USER, REGKEY_SAVEAS_WARNING_RESTRICTION, 0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS) {
RegSetValueEx(hkey, REGVALUE_SAVEAS_WARNING, 0, REG_DWORD, (CONST BYTE *)&dwNeverAsk, sizeof(dwNeverAsk)); RegCloseKey(hkey); } } } Continue:
// Suggest a file name
szFileDst[0] = 0;
// Our favorite candidate is the title, fall back on the file name.
hr = pDoc->get_title(&bstrTitle); if (SUCCEEDED(hr) && lstrlenW(bstrTitle)) { StrCpyN(szFileDst, bstrTitle, ARRAYSIZE(szFileDst)); } else hr = GetFileNameFromURL(bstrURL, szFileDst, ARRAYSIZE(szFileDst));
if (FAILED(hr)) goto Cleanup;
PathCleanupSpec(NULL, szFileDst);
hr = FormsGetFileName(hwnd, szFileDst, ARRAYSIZE(szFileDst), (LONG_PTR)&tcpi, &iFilter, bForceHTMLOnly);
if (hr==S_OK) hr = SaveToThicket( hwnd, szFileDst, pDoc, tcpi.cpSrc, tcpi.cpDst, iFilter);
Cleanup:
if (FAILED(hr)) ReportThicketError(hwnd, hr);
if (pOleCommandTarget) pOleCommandTarget->Release();
if (pDoc) pDoc->Release();
if (bstrURL) SysFreeString(bstrURL);
if (bstrCharSet) SysFreeString(bstrCharSet);
if (bstrTitle) SysFreeString(bstrTitle);
return; }
void ReportThicketError( HWND hwnd, HRESULT hr ) { LPTSTR lpstrMsg = NULL;
switch (hr) { case HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY): case E_OUTOFMEMORY: lpstrMsg = MAKEINTRESOURCE(IDS_THICKETERRMEM); break;
case E_ACCESSDENIED: case STG_E_ACCESSDENIED: lpstrMsg = MAKEINTRESOURCE(IDS_THICKETERRACC); break;
case HRESULT_FROM_WIN32(ERROR_DISK_FULL): case STG_E_MEDIUMFULL: lpstrMsg = MAKEINTRESOURCE(IDS_THICKETERRFULL); break;
case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND): lpstrMsg = MAKEINTRESOURCE(IDS_THICKETERRFNF); break;
case E_ABORT: // Ray says we don't want a canceled message box.
//lpstrMsg = MAKEINTRESOURCE(IDS_THICKETABORT);
break;
case E_FAIL: default: lpstrMsg = MAKEINTRESOURCE(IDS_THICKETERRMISC); break; }
if ( lpstrMsg ) { MLShellMessageBox( hwnd, lpstrMsg, MAKEINTRESOURCE(IDS_THICKETERRTITLE), MB_OK | MB_ICONERROR); } }
//+--------------------------------------------------------------------------
//
// File: file.cxx
//
// Contents: Import/export dialog helpers
//
// History: 16-May-95 RobBear Taken from formtool
//
//---------------------------------------------------------------------------
const CHAR c_szNT4ResourceLocale[] = ".DEFAULT\\Control Panel\\International"; const CHAR c_szWin9xResourceLocale[] = ".Default\\Control Panel\\desktop\\ResourceLocale"; const CHAR c_szLocale[] = "Locale";
LANGID MLGetShellLanguage() { LANGID lidShell = 0;
// FEATURE: this fn is copied from shlwapi. there really should be a
// shlwapi export. if MLGetUILanguage has any merit, then
// MLGetShellLanguage has merit as well.
if (IsOS(OS_WIN2000ORGREATER)) { static LANGID (CALLBACK* pfnGetUserDefaultUILanguage)(void) = NULL;
if (pfnGetUserDefaultUILanguage == NULL) { HMODULE hmod = GetModuleHandle(TEXT("KERNEL32"));
if (hmod) pfnGetUserDefaultUILanguage = (LANGID (CALLBACK*)(void))GetProcAddress(hmod, "GetUserDefaultUILanguage"); } if (pfnGetUserDefaultUILanguage) lidShell = pfnGetUserDefaultUILanguage(); } else { CHAR szLangID[12]; DWORD cb, dwRet;
cb = sizeof(szLangID) - 2*sizeof(szLangID[0]); // avoid 2 byte buffer overrun
if (IsOS(OS_NT)) dwRet = SHGetValueA(HKEY_USERS, c_szNT4ResourceLocale, c_szLocale, NULL, szLangID + 2, &cb); else dwRet = SHGetValueA(HKEY_USERS, c_szWin9xResourceLocale, NULL, NULL, szLangID + 2, &cb);
if (ERROR_SUCCESS == dwRet) { // IE uses a string rep of the hex value
szLangID[0] = '0'; szLangID[1] = 'x'; StrToIntExA(szLangID, STIF_SUPPORT_HEX, (LPINT)&lidShell); } }
return lidShell; }
/*
* Stolen from Trident's src\core\cdutil\file.cxx */
// Hook procedure for open file dialog.
UINT_PTR APIENTRY SaveOFNHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { ULONG i, iCurSel; BOOL bFoundEncoding = FALSE; WCHAR wzEncoding[MAX_ENCODING_DESC_LEN];
switch (uiMsg) { // Populate the dropdown.
case WM_INITDIALOG: { HRESULT hr; LPOPENFILENAME pofn = (LPOPENFILENAME)lParam; ThicketCPInfo *ptcpi = (ThicketCPInfo *)pofn->lCustData; IMultiLanguage2 *pMultiLanguage = NULL; IEnumCodePage *pEnumCodePage = NULL; //UINT codepageDefault = ptcpi->cp;
MIMECSETINFO csetInfo; LANGID langid;
#ifdef UNIX
SetWindowLongPtr(hdlg, DWLP_USER, (LONG_PTR)ptcpi); #endif /* UNIX */
hr = CoCreateInstance( CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, IID_IMultiLanguage2, (void**)&pMultiLanguage); if (hr) break;
hr = pMultiLanguage->GetCharsetInfo(ptcpi->lpwstrDocCharSet,&csetInfo); if (hr) break;
#ifndef UNIX
// the shell combobox where this stuff shows up
// doesn't know how to fontlink... so we have
// to stay in the shell's codepage
langid = MLGetShellLanguage(); #else
langid = GetSystemDefaultLangID(); #endif /* UNIX */
if (pMultiLanguage->EnumCodePages( MIMECONTF_SAVABLE_BROWSER | MIMECONTF_VALID, langid, &pEnumCodePage) == S_OK) { MIMECPINFO cpInfo; ULONG ccpInfo; UINT cpDefault;
if (pMultiLanguage->GetCodePageInfo(csetInfo.uiInternetEncoding, langid, &cpInfo) == S_OK && !(cpInfo.dwFlags & MIMECONTF_SAVABLE_BROWSER)) { // If the codepage selected is not savable (eg JP_AUTO),
// use the family codepage.
cpDefault = cpInfo.uiFamilyCodePage; } else cpDefault = csetInfo.uiInternetEncoding;
ptcpi->cpSrc = csetInfo.uiInternetEncoding;
if (cpDefault == CODEPAGE_UNICODE && pofn->nFilterIndex == PACKAGE_MHTML) { cpDefault = CODEPAGE_UTF8; }
for (i = 0; pEnumCodePage->Next(1, &cpInfo, &ccpInfo) == S_OK; ++i) { TCHAR *lpszDesc; INT_PTR iIdx;
if (cpInfo.uiCodePage == CODEPAGE_UNICODE && pofn->nFilterIndex == PACKAGE_MHTML) { i--; continue; }
if (cpDefault == cpInfo.uiCodePage) { StrCpyNW(wzEncoding, cpInfo.wszDescription, lstrlen(cpInfo.wszDescription) + 1); bFoundEncoding = TRUE; }
lpszDesc = cpInfo.wszDescription;
iIdx = SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_ADDSTRING, 0, (LPARAM)lpszDesc); SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_SETITEMDATA, iIdx, (LPARAM)cpInfo.uiCodePage); }
if (bFoundEncoding) { INT_PTR iIndex = 0;
iIndex = SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_FINDSTRINGEXACT, -1, (LPARAM)wzEncoding);
SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_SETCURSEL, (WPARAM)iIndex, 0); } else { // No encoding found! Bad error. Recover by selecting
// the first one.
SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_SETCURSEL, 0, 0); }
} SAFERELEASE(pEnumCodePage); SAFERELEASE(pMultiLanguage); break; }
#ifdef UNIX
case WM_COMMAND: { switch (GET_WM_COMMAND_ID(wParam,lParam)) { case IDOK: { ThicketCPInfo *ptcpi = (ThicketCPInfo *)GetWindowLongPtr(hdlg,DWLP_USER);
ptcpi->cpDst = CP_ACP; iCurSel = (int) SendDlgItemMessage (hdlg, IDC_SAVE_CHARSET, CB_GETCURSEL, 0, 0); ptcpi->cpDst = (UINT)SendDlgItemMessage (hdlg, IDC_SAVE_CHARSET, CB_GETITEMDATA, (WPARAM)iCurSel, (LPARAM)0);
// To spare us from re-instantiating MLANG, we'll set the src and dest
// to CP_ACP if no change is indicated.
if (ptcpi->cpDst == ptcpi->cpSrc) ptcpi->cpDst = ptcpi->cpSrc = CP_ACP; } break; } } break; #endif /* UNIX */
case WM_NOTIFY: { LPOFNOTIFY phdr = (LPOFNOTIFY)lParam;
switch (phdr->hdr.code) { case CDN_FILEOK: { LPOPENFILENAME pofn = (LPOPENFILENAME)phdr->lpOFN; ThicketCPInfo *ptcpi = (ThicketCPInfo *)pofn->lCustData;
iCurSel = (int) SendDlgItemMessage (hdlg, IDC_SAVE_CHARSET, CB_GETCURSEL, 0, 0); ptcpi->cpDst = //*(UINT *)phdr->lpOFN->lCustData =
(UINT)SendDlgItemMessage (hdlg, IDC_SAVE_CHARSET, CB_GETITEMDATA, (WPARAM)iCurSel, (LPARAM)0); }
// HACK! This case is implemented to implement a hack for
// IE5 RAID #60672. MIMEOLE cannot save UNICODE encoding,
// so when the user selects MHTML saves, we should remove
// this option. This code should be removed when MIMEOLE
// fixes their bug (targeted for NT5 RTM). Contact SBailey
// for the status of this.
case CDN_TYPECHANGE: { LPOPENFILENAME pofn = (LPOPENFILENAME)phdr->lpOFN; ThicketCPInfo *ptcpi = (ThicketCPInfo *)pofn->lCustData; UINT uiCPSel, uiCP; int iType = pofn->nFilterIndex; UINT iCount; int iCurSel; int iSet = -1;
if (iType == PACKAGE_MHTML) { iCurSel = (int)SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_GETCURSEL, 0, 0);
uiCPSel = (UINT)SendDlgItemMessage (hdlg, IDC_SAVE_CHARSET, CB_GETITEMDATA, (WPARAM)iCurSel, (LPARAM)0); // If you selected unicode, make it look like you
// really selected UTF-8
if (uiCPSel == CODEPAGE_UNICODE) { uiCPSel = CODEPAGE_UTF8; }
i = (int) SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_FINDSTRINGEXACT, (WPARAM)0, (LPARAM)UNICODE_TEXT); if (i != CB_ERR) { SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_DELETESTRING, i, (LPARAM)0); }
iCount = (int)SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_GETCOUNT, 0, 0);
// Set selected item back
for (i = 0; i < iCount; i++) { uiCP = (UINT)SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_GETITEMDATA, (WPARAM)i, (LPARAM)0); if (uiCP == uiCPSel) { iSet = i; } }
if (iSet != 0xffffffff) { SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_SETCURSEL, (WPARAM)iSet, (LPARAM)0); } } else { // Store current selection
iCurSel = (int)SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_GETCURSEL, 0, 0);
uiCPSel = (UINT)SendDlgItemMessage (hdlg, IDC_SAVE_CHARSET, CB_GETITEMDATA, (WPARAM)iCurSel, (LPARAM)0);
// Add unicode back in, if it was removed
i = (int) SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_FINDSTRINGEXACT, (WPARAM)0, (LPARAM)UNICODE_TEXT);
if (i == CB_ERR) { // Unicode does not exist, add it back in
i = (int) SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_ADDSTRING, 0, (LPARAM)UNICODE_TEXT); SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_SETITEMDATA, i, (LPARAM)CODEPAGE_UNICODE);
// Make sure the same encoding selected before is
// still selected.
iCount = (int)SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_GETCOUNT, 0, 0); for (i = 0; i < iCount; i++) { uiCP = (UINT)SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_GETITEMDATA, (WPARAM)i, (LPARAM)0); if (uiCP == uiCPSel) { iSet = i; } } if (iCurSel != 0xffffffff) { SendDlgItemMessage(hdlg, IDC_SAVE_CHARSET, CB_SETCURSEL, (WPARAM)iSet, (LPARAM)0); } }
}
} break; } } break;
case WM_HELP: { SHWinHelpOnDemandWrap((HWND)((LPHELPINFO) lParam)->hItemHandle, c_szHelpFile, HELP_WM_HELP, (DWORD_PTR)aSaveAsHelpIDs); } break;
case WM_CONTEXTMENU: { SHWinHelpOnDemandWrap((HWND) wParam, c_szHelpFile, HELP_CONTEXTMENU, (DWORD_PTR)aSaveAsHelpIDs); } break; } return (FALSE); }
//
// Protect the naive users from themselves, if somebody enters a filename
// of microsoft.com when saving http://www.microsoft.com we don't want
// to save a .COM file since this will be interpreted as an executable.
// bad things will happen
//
void CleanUpFilename(LPTSTR pszFile, int iPackageStyle) { //
// If we find .COM as the file extension replace it with the file extension
// of the filetype they are saving the file as
//
LPTSTR pszExt = PathFindExtension(pszFile);
ASSERT(pszExt); if (StrCmpI(pszExt, TEXT(".COM")) == 0) // REVIEW any other file types???
{ //
// Map the package style to a default extension. NOTE this relies on
// the fact that the filter index maps to the PACKAGE style enum
// (as does the rest of the thicket code).
//
switch (iPackageStyle) { case PACKAGE_THICKET: case PACKAGE_HTML: StrCatBuff(pszFile, TEXT(".htm"), MAX_PATH); break;
case PACKAGE_MHTML: StrCatBuff(pszFile, TEXT(".mht"), MAX_PATH); break;
case PACKAGE_TEXT: StrCatBuff(pszFile, TEXT(".txt"), MAX_PATH); break;
default: ASSERT(FALSE); // Unknown package type
break; } } }
//+---------------------------------------------------------------------------
//
// Function: FormsGetFileName
//
// Synopsis: Gets a file name using either the GetOpenFileName or
// GetSaveFileName functions.
//
// Arguments: [fSaveFile] -- TRUE means use GetSaveFileName
// FALSE means use GetOpenFileName
//
// [idFilterRes] -- The string resource specifying text in the
// dialog box. It must have the
// following format:
// Note: the string has to be _one_ contiguous string.
// The example is broken up to make it fit
// on-screen. The verical bar ("pipe") characters
// are changed to '\0'-s on the fly.
// This allows the strings to be localized
// using Espresso.
//
// IDS_FILENAMERESOURCE, "Save Dialog As| // the title
// odg| // default extension
// Forms3 Dialog (*.odg)| // pairs of filter strings
// *.odg|
// Any File (*.*)|
// *.*|"
//
// [pstrFile] -- Buffer for file name.
// [cchFile] -- Size of buffer in characters.
//
// Modifies: [pstrFile]
//
//----------------------------------------------------------------------------
#ifdef _MAC
extern "C" { char * __cdecl _p2cstr(unsigned char *); } #endif
#define CHAR_DOT TEXT('.')
#define CHAR_DOT_REPLACEMENT TEXT('_')
void ReplaceDotsInFileName(LPTSTR pszFileName) { ASSERT(pszFileName);
while (*pszFileName) { if (*pszFileName == CHAR_DOT) { *pszFileName = CHAR_DOT_REPLACEMENT; } pszFileName++; } }
HRESULT FormsGetFileName( HWND hwndOwner, LPTSTR pstrFile, int cchFile, LPARAM lCustData, DWORD *pnFilterIndex, BOOL bForceHTMLOnly) { HRESULT hr = S_OK; BOOL fOK; DWORD dwCommDlgErr; LPTSTR pstr; OPENFILENAME ofn; TCHAR achBuffer[4096]; // Max. size of a string resource
TCHAR * cp; TCHAR * pstrExt; int cbBuffer; TCHAR achPath[MAX_PATH]; DWORD dwType = REG_SZ; DWORD cbData = MAX_PATH * sizeof(TCHAR); int idFilterRes;
// Initialize ofn struct
memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwndOwner; ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | #ifndef UNIX
OFN_NOCHANGEDIR | OFN_EXPLORER; #else
OFN_NOCHANGEDIR; #endif /* UNIX */
ofn.lpfnHook = NULL; ofn.nMaxFile = cchFile; ofn.lCustData = lCustData; ofn.lpstrFile = pstrFile; #ifndef NO_IME
// We add an extra control to the save file dialog.
if (lCustData) { ofn.Flags |= OFN_ENABLETEMPLATE | OFN_ENABLEHOOK; ofn.lpfnHook = SaveOFNHookProc; ofn.lpTemplateName = MAKEINTRESOURCE(IDD_ADDTOSAVE_DIALOG); ofn.hInstance = g_hinst; }
#endif
//
// Find the extension and set the filter index based on what the
// extension is. After these loops pstrExt will either be NULL if
// we didn't find an extension, or will point to the extension starting
// at the '.'
pstrExt = pstrFile; while (*pstrExt) pstrExt++; while ( pstrExt >= pstrFile ) { if( *pstrExt == TEXT('.') ) break; pstrExt--; } if( pstrExt < pstrFile ) pstrExt = NULL;
// Load the filter spec.
// FEATURE: Convert table to stringtable for localization
if ( SHRestricted2W( REST_NoBrowserSaveWebComplete, NULL, 0 ) ) idFilterRes = IDS_NOTHICKET_SAVE; else if ( s_dwInetComVerMS != 0xFFFFFFFF ) { #ifndef UNIX
if (s_dwInetComVerMS == 0) { TCHAR szPath[MAX_PATH];
GetSystemDirectory( szPath, MAX_PATH ); StrCatBuff( szPath, TEXT("\\INETCOMM.DLL"), MAX_PATH ); if (FAILED(GetVersionFromFile(szPath, &s_dwInetComVerMS, &s_dwInetComVerLS))) s_dwInetComVerMS = 0xFFFFFFFF; }
if (s_dwInetComVerMS >= 0x50000 && s_dwInetComVerMS != 0xFFFFFFFF) idFilterRes = IDS_THICKET_SAVE; else idFilterRes = IDS_NOMHTML_SAVE; #else
// on UNIX we don't have inetcomm.dll if oe is not installed
{ HINSTANCE hInetComm = NULL;
if ((hInetComm = LoadLibrary(TEXT("INETCOMM.DLL")))) { idFilterRes = IDS_THICKET_SAVE; FreeLibrary(hInetComm); } else idFilterRes = IDS_NOMHTML_SAVE; } #endif
} else idFilterRes = IDS_THICKET_SAVE;
cbBuffer = MLLoadShellLangString(idFilterRes, achBuffer, ARRAYSIZE(achBuffer)); ASSERT(cbBuffer > 0); if ( ! cbBuffer ) return E_FAIL;
ofn.lpstrTitle = achBuffer;
for ( cp = achBuffer; *cp; cp++ ) { if ( *cp == TEXT('|') ) { *cp = TEXT('\0'); } }
ASSERT(ofn.lpstrTitle);
// Default extension is second string.
pstr = (LPTSTR) ofn.lpstrTitle; while (*pstr++) { }
// N.B. (johnv) Here we assume that filter index one corresponds with the default
// extension, otherwise we would have to introduce a default filter index into
// the resource string.
ofn.nFilterIndex = ((pnFilterIndex)? *pnFilterIndex : 1); ofn.lpstrDefExt = pstr;
// Filter is third string.
while(*pstr++) { }
ofn.lpstrFilter = pstr;
// Try to match the extension with an entry in the filter list
// If we match, remove the extension from the incoming path string,
// set the default extension to the one we found, and appropriately
// set the filter index.
if (pstrExt && !bForceHTMLOnly) { // N.B. (johnv) We are searching more than we need to.
int iIndex = 0; const TCHAR* pSearch = ofn.lpstrFilter;
while( pSearch ) { if( StrStr( pSearch, pstrExt ) ) { ofn.nFilterIndex = (iIndex / 2) + 1; ofn.lpstrDefExt = pstrExt + 1;
// Remove the extension from the file name we pass in
*pstrExt = TEXT('\0');
break; } pSearch += lstrlen(pSearch); if( pSearch[1] == 0 ) break;
pSearch++; iIndex++; } }
// Suggest HTML Only as default save-type
if (bForceHTMLOnly) { // NOTE: These are hard-coded indices based on shdoclc.rc's
// IDS_THICKET_SAVE, IDS_NOMHTML_SAVE, IDS_NOTHICKET_SAVE ordering.
// This saves us the perf hit of doing string comparisons to find
// HTML only
switch (idFilterRes) { case IDS_NOTHICKET_SAVE: ofn.nFilterIndex = 1; break;
case IDS_NOMHTML_SAVE: ofn.nFilterIndex = 2; break;
default: ASSERT(idFilterRes == IDS_THICKET_SAVE); ofn.nFilterIndex = 3; break; } }
if ( SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_MAIN, REGSTR_VAL_SAVEDIRECTORY, &dwType, achPath, &cbData) != ERROR_SUCCESS || !PathFileExists(achPath)) { SHGetSpecialFolderPath(hwndOwner, achPath, CSIDL_PERSONAL, FALSE); }
ofn.lpstrInitialDir = achPath;
// We don't want to suggest dots in the filename
ReplaceDotsInFileName(pstrFile);
// Now, at last, we're ready to call the save file dialog
fOK = GetSaveFileName(&ofn);
// if working with the abbreviated format list, adjust the index
if (idFilterRes == IDS_NOTHICKET_SAVE) ofn.nFilterIndex += 2; else if ( idFilterRes == IDS_NOMHTML_SAVE && ofn.nFilterIndex > 1 ) ofn.nFilterIndex += 1;
if (fOK) { //
// Protect the naive users from themselves, if somebody enters a filename
// of microsoft.com when saving http://www.microsoft.com we don't want
// to save a .COM file since this will be interpreted as an executable.
// bad things will happen
//
CleanUpFilename(pstrFile, ofn.nFilterIndex);
TCHAR *lpszFileName;
StrCpyN( achPath, pstrFile, ARRAYSIZE(achPath) );
lpszFileName = PathFindFileName( achPath ); *lpszFileName = 0;
SHSetValue(HKEY_CURRENT_USER, REGSTR_PATH_MAIN, REGSTR_VAL_SAVEDIRECTORY, REG_SZ, achPath, (lstrlen(achPath) * sizeof(TCHAR)));
if (pnFilterIndex) *pnFilterIndex = ofn.nFilterIndex;
if (ofn.nFilterIndex != PACKAGE_MHTML) { // we can only do this if we're not packaging MHTML
// because MHTML requires that we tag with the explicit
// charset, even if it was the default. unlike thicket
// which inherits the charset from the original document,
// MHTML must be explicitly tagged or else some system
// charset tags will sneak in.
ThicketCPInfo * ptcpi = (ThicketCPInfo *)lCustData;
// To spare us from re-instantiating MLANG, we'll set the src and dest
// to CP_ACP if no change is indicated.
if (ptcpi->cpDst == ptcpi->cpSrc) ptcpi->cpDst = ptcpi->cpSrc = CP_ACP; } } else { #ifndef WINCE
dwCommDlgErr = CommDlgExtendedError(); if (dwCommDlgErr) { hr = HRESULT_FROM_WIN32(dwCommDlgErr); } else { hr = S_FALSE; } #else // WINCE
hr = E_FAIL; #endif // WINCE
}
return hr; }
HRESULT GetFileNameFromURL( LPWSTR pwszURL, LPTSTR pszFile, DWORD cchFile) { HRESULT hr = S_OK; PARSEDURLW puw = {0}; int cchUrl;
cchUrl = SysStringLen(pwszURL);
if (cchUrl) { puw.cbSize = sizeof(PARSEDURLW); if (SUCCEEDED(ParseURLW(pwszURL, &puw))) { OLECHAR *pwchBookMark; DWORD dwSize; INTERNET_CACHE_ENTRY_INFOW ceiT; LPINTERNET_CACHE_ENTRY_INFOW pcei = NULL;
// Temporarily, null out the '#' in the url
pwchBookMark = StrRChrW(puw.pszSuffix, NULL,'#'); if (pwchBookMark) { *pwchBookMark = 0; }
dwSize = sizeof(INTERNET_CACHE_ENTRY_INFO); if ( !GetUrlCacheEntryInfoW( pwszURL, &ceiT, &dwSize ) && GetLastError() == ERROR_INSUFFICIENT_BUFFER && (pcei = (LPINTERNET_CACHE_ENTRY_INFOW)new BYTE[dwSize]) != NULL && GetUrlCacheEntryInfoW( pwszURL, pcei, &dwSize ) ) { StrCpyN(pszFile, PathFindFileName(pcei->lpszLocalFileName), cchFile); PathUndecorate(pszFile); }
if(pcei) delete[] pcei;
if (pwchBookMark) *pwchBookMark = '#';
if ( !pszFile[0] ) { OLECHAR *pwchQuery; TCHAR szFileT[MAX_PATH];
// Temporarily, null out the '?' in the url
pwchQuery = StrRChrW(puw.pszSuffix, NULL,'?'); if (pwchQuery) { *pwchQuery = 0; }
// IE5 bug 15055 - http://my.excite.com/?uid=B56E4E2D34DF3FED.save_uid
// fails to save because we were passing "my.excite.com/" as the file
// name to the file dialog. It doesn't like this.
if (!pwchQuery || (pwchQuery[-1] != '/' && pwchQuery[-1] != '\\')) { dwSize = ARRAYSIZE(szFileT);
StrCpyN(szFileT, PathFindFileName(puw.pszSuffix), dwSize);
if ( !InternetCanonicalizeUrl( szFileT, pszFile, &dwSize, ICU_DECODE | ICU_NO_ENCODE) ) StrCpyN(pszFile, szFileT, cchFile);
pszFile[cchFile - 1] = 0; }
if (pwchQuery) *pwchQuery = '?'; } } }
if (!pszFile[0]) { MLLoadString(IDS_UNTITLED, pszFile, cchFile); }
return hr; }
INT_PTR CALLBACK SaveAsWarningDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { BOOL fRet = FALSE; HRESULT hr = S_OK; int iFlags = 0; INT_PTR bChecked = 0;
switch (msg) { case WM_INITDIALOG: MessageBeep(MB_ICONEXCLAMATION); fRet = TRUE;
case WM_COMMAND: bChecked = SendDlgItemMessage(hDlg, IDC_SAVEAS_WARNING_CB, BM_GETCHECK, 0, 0 ); iFlags = (bChecked) ? (SAVEAS_NEVER_ASK_AGAIN) : (0);
switch (LOWORD(wParam)) { case IDYES: iFlags |= SAVEAS_OK; // fall through
case IDNO: EndDialog(hDlg, iFlags); fRet = TRUE; break; } default: fRet = FALSE; }
return fRet; }
|