// wordpad.cpp : Defines the class behaviors for the application. // // This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) 1992-1995 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Foundation Classes Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Microsoft Foundation Classes product. #include "stdafx.h" #include "wordpad.h" #include "mainfrm.h" #include "ipframe.h" #include "wordpdoc.h" #include "wordpvw.h" #include "strings.h" #include "key.h" #include "filenewd.h" #include #include #include #include "fixhelp.h" #include "filedlg.h" #if _WIN32_IE < 0x400 #undef _WIN32_IE #define _WIN32_IE 0x0400 #endif #include #define szRichName L"RICHED20" #define szNewRichName L"MSFTEDIT.DLL" extern BOOL AFXAPI AfxFullPath(LPTSTR lpszPathOut, LPCTSTR lpszFileIn); static BOOL RegisterHelper(LPCTSTR* rglpszRegister, LPCTSTR* rglpszSymbols, BOOL bReplace); #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif CLIPFORMAT cfEmbeddedObject; CLIPFORMAT cfRTF; CLIPFORMAT cfRTO; int CWordPadApp::m_nOpenMsg = RegisterWindowMessage(_T("WordPadOpenMessage")); int CWordPadApp::m_nPrinterChangedMsg = RegisterWindowMessage(_T("WordPadPrinterChanged")); int CWordPadApp::m_nOLEHelpMsg = RegisterWindowMessage(SZOLEUI_MSG_HELP); CUnit CWordPadApp::m_units[] = { // TPU, SmallDiv,MedDiv,LargeDiv,MinMove,szAbbrev, bSpace CUnit(1440, 180, 720, 1440, 90, IDS_INCH1_ABBREV, FALSE),//" CUnit(568, 142, 284, 568, 142, IDS_CM_ABBREV, TRUE),//cm's CUnit(20, 120, 720, 720, 100, IDS_POINT_ABBREV, TRUE),//points CUnit(240, 240, 1440, 1440, 120, IDS_PICA_ABBREV, TRUE),//picas CUnit(1440, 180, 720, 1440, 90, IDS_INCH2_ABBREV, FALSE),//in CUnit(1440, 180, 720, 1440, 90, IDS_INCH3_ABBREV, FALSE),//inch CUnit(1440, 180, 720, 1440, 90, IDS_INCH4_ABBREV, FALSE),//inches // Non-localized units CUnit(1440, 180, 720, 1440, 90, IDS_INCH1_NOLOC, FALSE),//" CUnit(1440, 180, 720, 1440, 90, IDS_INCH2_NOLOC, FALSE),//in CUnit(1440, 180, 720, 1440, 90, IDS_INCH3_NOLOC, FALSE),//inch CUnit(1440, 180, 720, 1440, 90, IDS_INCH4_NOLOC, FALSE),//inches CUnit(568, 142, 284, 568, 142, IDS_CM_NOLOC, TRUE),//cm's CUnit(20, 120, 720, 720, 100, IDS_POINT_NOLOC, TRUE),//points CUnit(240, 240, 1440, 1440, 120, IDS_PICA_NOLOC, TRUE)//picas }; const int CWordPadApp::m_nPrimaryNumUnits = 4; const int CWordPadApp::m_nNumUnits = sizeof(m_units) / sizeof(m_units[0]); ///////////////////////////////////////////////////////////////////////////// // CWordPadApp BEGIN_MESSAGE_MAP(CWordPadApp, CWinApp) //{{AFX_MSG_MAP(CWordPadApp) ON_COMMAND(ID_APP_ABOUT, OnAppAbout) ON_COMMAND(ID_FILE_NEW, OnFileNew) ON_COMMAND(ID_FILE_OPEN, OnFileOpen) //}}AFX_MSG_MAP END_MESSAGE_MAP() void CWordPadCommandLineInfo::ParseParam(const char* pszParam,BOOL bFlag,BOOL bLast) { if (bFlag) { if (lstrcmpA(pszParam, "t") == 0) { m_bForceTextMode = TRUE; return; } } CCommandLineInfo::ParseParam(pszParam, bFlag, bLast); } ///////////////////////////////////////////////////////////////////////////// // CWordPadApp construction CWordPadApp::CWordPadApp() : m_optionsText(0), m_optionsRTF(1), m_optionsWord(2), m_optionsWrite(2), m_optionsIP(2), m_optionsNull(0), m_initialization_phase(InitializationPending), m_pInitializationThread(NULL), m_always_convert_to_rtf(FALSE) { // _tsetlocale(LC_ALL, _T("")); setlocale(LC_ALL, ""); // change made by t-stefb DWORD dwVersion = ::GetVersion(); m_bWin4 = (BYTE)dwVersion >= 4; #ifndef _UNICODE m_bWin31 = (dwVersion > 0x80000000 && !m_bWin4); #endif m_nDefFont = (m_bWin4) ? DEFAULT_GUI_FONT : ANSI_VAR_FONT; m_dcScreen.Attach(::GetDC(NULL)); m_bLargeIcons = m_dcScreen.GetDeviceCaps(LOGPIXELSX) >= 120; m_bForceOEM = FALSE; } CWordPadApp::~CWordPadApp() { if (m_atomEnableCTF) GlobalDeleteAtom(m_atomEnableCTF); if (m_atomProcessCTF) GlobalDeleteAtom(m_atomProcessCTF); if (m_dcScreen.m_hDC != NULL) ::ReleaseDC(NULL, m_dcScreen.Detach()); delete m_pInitializationThread; } ///////////////////////////////////////////////////////////////////////////// // The one and only CWordPadApp object CWordPadApp theApp; // Register the application's document templates. Document templates // serve as the connection between documents, frame windows and views. static CSingleDocTemplate DocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CWordPadDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame window RUNTIME_CLASS(CWordPadView)); // This identifier was generated to be statistically unique for your app. // You may change it if you prefer to choose a specific identifier. static const CLSID BASED_CODE clsid = { 0x73FDDC80L, 0xAEA9, 0x101A, { 0x98, 0xA7, 0x00, 0xAA, 0x00, 0x37, 0x49, 0x59} }; ///////////////////////////////////////////////////////////////////////////// // CWordPadApp initialization BOOL CWordPadApp::InitInstance() { ParseCommandLine(cmdInfo); if (::FindWindow(szWordPadClass, NULL) && IsDocOpen(cmdInfo.m_strFileName)) return FALSE; SetRegistryKey(szRegKey); // The resistry stuff shouldn't be localized so just hardcode it if (NULL != m_pszProfileName) free((void *) m_pszProfileName); m_pszProfileName = _tcsdup(TEXT("Wordpad")); LoadOptions(); Enable3dControls(); if (!cmdInfo.m_bRunEmbedded) { switch (m_nCmdShow) { case SW_RESTORE: case SW_SHOW: case SW_SHOWDEFAULT: case SW_SHOWNA: case SW_SHOWNOACTIVATE: case SW_SHOWNORMAL: case SW_SHOWMAXIMIZED: if (m_bMaximized) m_nCmdShow = SW_SHOWMAXIMIZED; break; } } else { //Excel 4 will start OLE servers minimized m_nCmdShow = SW_SHOWNORMAL; } int nCmdShow = m_nCmdShow; LoadAbbrevStrings(); m_pszHelpFilePath = _tcsdup(WORDPAD_HELP_FILE) ; // Initialize OLE libraries if (!AfxOleInit()) { AfxMessageBox(IDP_OLE_INIT_FAILED); return FALSE; } RegisterFormats(); // Initialize RichEdit control if (LoadLibrary(szNewRichName) == NULL && LoadLibrary(szRichName) == NULL) { AfxMessageBox(IDS_RICHED_LOAD_FAIL, MB_OK|MB_ICONEXCLAMATION); return FALSE; } // initialize Cicero process ATOMs m_atomEnableCTF = AddAtom(TF_ENABLE_PROCESS_ATOM); m_atomProcessCTF = AddAtom(TF_PROCESS_ATOM); // Standard initialization // If you are not using these features and wish to reduce the size // of your final executable, you should remove from the following // the specific initialization routines you do not need. LoadStdProfileSettings(); // Load standard INI file options (including MRU) // Register the application's document templates. Document templates // serve as the connection between documents, frame windows and views. DocTemplate.SetContainerInfo(IDR_CNTR_INPLACE); DocTemplate.SetServerInfo( IDR_SRVR_EMBEDDED, IDR_SRVR_INPLACE, RUNTIME_CLASS(CInPlaceFrame)); // Connect the COleTemplateServer to the document template. // The COleTemplateServer creates new documents on behalf // of requesting OLE containers by using information // specified in the document template. m_server.ConnectTemplate(clsid, &DocTemplate, TRUE); // // Setup deferred initialization now so the printer can start // initializing in case we get a print or printto command at startup // m_pInitializationThread = AfxBeginThread( DoDeferredInitialization, this, THREAD_PRIORITY_IDLE, 0, CREATE_SUSPENDED); if (NULL != m_pInitializationThread) { m_pInitializationThread->m_bAutoDelete = FALSE; m_pInitializationThread->ResumeThread(); } // Check to see if launched as OLE server if (cmdInfo.m_bRunEmbedded || cmdInfo.m_bRunAutomated) { // Register all OLE server (factories) as running. This enables the // OLE libraries to create objects from other applications. COleTemplateServer::RegisterAll(); AfxOleSetUserCtrl(FALSE); // Application was run with /Embedding or /Automation. Don't show the // main window in this case. return TRUE; } // make sure the main window is showing m_bPromptForType = FALSE; OnFileNew(); m_bPromptForType = TRUE; m_nCmdShow = -1; if (m_pMainWnd == NULL) // i.e. OnFileNew failed return FALSE; TRY { if (!cmdInfo.m_strFileName.IsEmpty()) // open an existing document m_nCmdShow = nCmdShow; // Dispatch commands specified on the command line if (cmdInfo.m_nShellCommand != CCommandLineInfo::FileNew && !ProcessShellCommand(cmdInfo)) { return FALSE; } } CATCH(CFileException, e) { CString error; AfxFormatString1(error, AFX_IDP_FAILED_TO_OPEN_DOC, cmdInfo.m_strFileName); AfxMessageBox(error, MB_ICONEXCLAMATION, AFX_IDP_FAILED_TO_OPEN_DOC); return FALSE; } END_CATCH // Enable File Manager drag/drop open m_pMainWnd->DragAcceptFiles(); // // Set the current directory to "My Documents" so that will be the default // location for the first save/open // TCHAR szDefaultPath[MAX_PATH]; if (SHGetSpecialFolderPath(NULL, szDefaultPath, CSIDL_PERSONAL, FALSE)) SetCurrentDirectory(szDefaultPath); return TRUE; } BOOL CWordPadApp::IsDocOpen(LPCTSTR lpszFileName) { if (lpszFileName[0] == NULL) return FALSE; TCHAR szPath[_MAX_PATH]; AfxFullPath(szPath, lpszFileName); ATOM atom = GlobalAddAtom(szPath); ASSERT(atom != NULL); if (atom == NULL) return FALSE; EnumWindows(StaticEnumProc, (LPARAM)&atom); if (atom == NULL) return TRUE; DeleteAtom(atom); return FALSE; } BOOL CALLBACK CWordPadApp::StaticEnumProc(HWND hWnd, LPARAM lParam) { TCHAR szClassName[30]; GetClassName(hWnd, szClassName, 30); if (lstrcmp(szClassName, szWordPadClass) != 0) return TRUE; ATOM* pAtom = (ATOM*)lParam; ASSERT(pAtom != NULL); DWORD_PTR dw = 0; ::SendMessageTimeout(hWnd, m_nOpenMsg, NULL, (LPARAM)*pAtom, SMTO_ABORTIFHUNG, 500, &dw); if (dw) { ::SetForegroundWindow(hWnd); DeleteAtom(*pAtom); *pAtom = NULL; return FALSE; } return TRUE; } void CWordPadApp::RegisterFormats() { cfEmbeddedObject = (CLIPFORMAT)::RegisterClipboardFormat(_T("Embedded Object")); cfRTF = (CLIPFORMAT)::RegisterClipboardFormat(CF_RTF); cfRTO = (CLIPFORMAT)::RegisterClipboardFormat(CF_RETEXTOBJ); } CDocOptions& CWordPadApp::GetDocOptions(int nDocType) { switch (nDocType) { case RD_WINWORD6: case RD_WORDPAD: case RD_WORD97: return m_optionsWord; case RD_RICHTEXT: return m_optionsRTF; case RD_TEXT: case RD_OEMTEXT: case RD_UNICODETEXT: return m_optionsText; case RD_WRITE: return m_optionsWrite; case RD_EMBEDDED: return m_optionsIP; } ASSERT(FALSE); return m_optionsNull; } CDockState& CWordPadApp::GetDockState(int nDocType, BOOL bPrimary) { return GetDocOptions(nDocType).GetDockState(bPrimary); } void CWordPadApp::SaveOptions() { WriteProfileInt(szSection, szWordSel, m_bWordSel); WriteProfileInt(szSection, szUnits, GetUnits()); WriteProfileInt(szSection, szMaximized, m_bMaximized); WriteProfileBinary(szSection, szFrameRect, (BYTE*)&m_rectInitialFrame, sizeof(CRect)); WriteProfileBinary(szSection, szPageMargin, (BYTE*)&m_rectPageMargin, sizeof(CRect)); m_optionsText.SaveOptions(szTextSection); m_optionsRTF.SaveOptions(szRTFSection); m_optionsWord.SaveOptions(szWordSection); m_optionsWrite.SaveOptions(szWriteSection); m_optionsIP.SaveOptions(szIPSection); WriteProfileInt( szSection, TEXT("DefaultFormat"), CWordpadFileDialog::GetDefaultFileType()); if (ShouldAlwaysConvertToRTF()) WriteProfileInt(szSection, TEXT("AlwaysConvertToRTF"), TRUE); } void CWordPadApp::SetUnits(int n) { RIPMSG(n>=0 && n = m_nPrimaryNumUnits) { n = m_nPrimaryNumUnits - 1; } m_nUnits = n; } void CWordPadApp::LoadOptions() { BYTE* pb = NULL; UINT nLen = 0; HKEY key; bool bNewInstall = true; if (ERROR_SUCCESS == RegOpenKeyEx(GetAppRegistryKey(), szSection, 0, KEY_READ, &key)) { bNewInstall = false; RegCloseKey(key); } HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); if (hFont == NULL) hFont = (HFONT)GetStockObject(ANSI_VAR_FONT); VERIFY(GetObject(hFont, sizeof(LOGFONT), &m_lf)); m_bWordSel = GetProfileInt(szSection, szWordSel, TRUE); TCHAR buf[2]; buf[0] = NULL; GetLocaleInfo(GetUserDefaultLCID(), LOCALE_IMEASURE, buf, 2); int nDefUnits = buf[0] == _T('1') ? 0 : 1; SetUnits(GetProfileInt(szSection, szUnits, nDefUnits)); m_bMaximized = GetProfileInt(szSection, szMaximized, (int)FALSE); if (GetProfileBinary(szSection, szFrameRect, &pb, &nLen)) { ASSERT(nLen == sizeof(CRect)); memcpy(&m_rectInitialFrame, pb, sizeof(CRect)); delete [] pb; } else m_rectInitialFrame.SetRect(0,0,0,0); CRect rectScreen(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); CRect rectInt; rectInt.IntersectRect(&rectScreen, &m_rectInitialFrame); if (rectInt.Width() < 10 || rectInt.Height() < 10) m_rectInitialFrame.SetRect(0, 0, 0, 0); if (GetProfileBinary(szSection, szPageMargin, &pb, &nLen)) { ASSERT(nLen == sizeof(CRect)); memcpy(&m_rectPageMargin, pb, sizeof(CRect)); delete [] pb; } else m_rectPageMargin.SetRect(1800, 1440, 1800, 1440); // // Set the default format to RTF for new installs, Word6 (or whatever) was // perviously selected for upgrades // int defformat = RD_NATIVE; if (!bNewInstall) defformat = _VerifyDefaultFormat(GetProfileInt(szSection,TEXT("DefaultFormat"), RD_WORDPAD), RD_WORDPAD); CWordpadFileDialog::SetDefaultFileType(defformat); if (GetProfileInt(szSection, TEXT("AlwaysConvertToRTF"), FALSE)) SetAlwaysConvertToRTF(); m_nFilterIndex = GetIndexFromType(RD_DEFAULT, TRUE); m_optionsText.LoadOptions(szTextSection); m_optionsRTF.LoadOptions(szRTFSection); m_optionsWord.LoadOptions(szWordSection); m_optionsWrite.LoadOptions(szWriteSection); m_optionsIP.LoadOptions(szIPSection); } void CWordPadApp::LoadAbbrevStrings() { for (int i=0;i= div/2) pVal[i]++; while ((pVal[i] == 10) && (i != 0)) { pVal[i] = 0; pVal[--i]++; } while (nDec && pVal[nDec] == 0) nDec--; StringCchPrintf(buf, cchBuf, L"%.*f", nDec, (float)nValue/(float)div); if (m_units[m_nUnits].m_bSpaceAbbrev) StringCchCat(buf, cchBuf, L" "); StringCchCat(buf, cchBuf, GetAbbrev()); } ///////////////////////////////////////////////////////////////////////////// // CWordPadApp commands void CWordPadApp::OnAppAbout() { CString strTitle; VERIFY(strTitle.LoadString(AFX_IDS_APP_TITLE)); ShellAbout(m_pMainWnd->GetSafeHwnd(), strTitle, _T(""), LoadIcon(IDR_MAINFRAME)); } int CWordPadApp::ExitInstance() { FreeLibrary(GetModuleHandle(szRichName)); HMODULE hMod = GetModuleHandle(szNewRichName); if (hMod) FreeLibrary(hMod); SaveOptions(); return CWinApp::ExitInstance(); } void CWordPadApp::OnFileNew() { int nDocType = -1; if (!m_bPromptForType) { if (cmdInfo.m_bForceTextMode) nDocType = RD_TEXT; else if (!cmdInfo.m_strFileName.IsEmpty()) { CFileException fe; nDocType = GetDocTypeFromName(cmdInfo.m_strFileName, fe); if (DocTypeDisabled(nDocType)) { nDocType = RD_DEFAULT; } } if (nDocType == -1) nDocType = RD_DEFAULT; } else { CFileNewDialog dlg; if (dlg.DoModal() == IDCANCEL) return; nDocType = (dlg.m_nSel == 1) ? RD_TEXT : (dlg.m_nSel == 2) ? RD_UNICODETEXT : RD_RICHTEXT; if (nDocType != RD_TEXT) cmdInfo.m_bForceTextMode = FALSE; } m_nNewDocType = nDocType; DocTemplate.OpenDocumentFile(NULL); // if returns NULL, the user has already been alerted } // prompt for file name - used for open and save as // static function called from app BOOL CWordPadApp::PromptForFileName(CString& fileName, UINT nIDSTitle, DWORD dwFlags, BOOL bOpenFileDialog, int* pType) { ScanForConverters(); CWordpadFileDialog dlgFile(bOpenFileDialog); CString title; VERIFY(title.LoadString(nIDSTitle)); dlgFile.m_ofn.Flags |= dwFlags; int nIndex = m_nFilterIndex; if (!bOpenFileDialog) { int nDocType = (pType != NULL) ? *pType : RD_DEFAULT; nIndex = GetIndexFromType(nDocType, bOpenFileDialog); if (nIndex == -1) nIndex = GetIndexFromType(RD_DEFAULT, bOpenFileDialog); if (nIndex == -1) nIndex = GetIndexFromType(RD_NATIVE, bOpenFileDialog); ASSERT(nIndex != -1); nIndex++; } dlgFile.m_ofn.nFilterIndex = nIndex; // strDefExt is necessary to hold onto the memory from GetExtFromType CString strDefExt = GetExtFromType(GetTypeFromIndex(nIndex-1, bOpenFileDialog)); // // The open file dialog doesn't want the extension to start with '.' but // thats how GetExtFromType gives it to us. // dlgFile.m_ofn.lpstrDefExt = strDefExt; ASSERT(TEXT('.') == *dlgFile.m_ofn.lpstrDefExt); ++dlgFile.m_ofn.lpstrDefExt; CString strFilter = GetFileTypes(bOpenFileDialog); dlgFile.m_ofn.lpstrFilter = strFilter; dlgFile.m_ofn.lpstrTitle = title; dlgFile.m_ofn.lpstrFile = fileName.GetBuffer(_MAX_PATH); BOOL bRet; int namelen; do { bRet = (dlgFile.DoModal() == IDOK) ? TRUE : FALSE; if (!bRet) break; // The converters only speak ansi so make sure the filename isn't to // long for DBCS. namelen = WideCharToMultiByte(CP_ACP, 0, fileName, -1, NULL, 0,NULL,NULL); if (namelen > MAX_PATH - 2) { CString message; AfxFormatString1(message, IDS_FILENAME_TO_LONG, fileName); AfxMessageBox(message); } } while (namelen > MAX_PATH - 2); fileName.ReleaseBuffer(); if (bRet) { if (bOpenFileDialog) m_nFilterIndex = dlgFile.m_ofn.nFilterIndex; if (pType != NULL) { int nIndex = (int)dlgFile.m_ofn.nFilterIndex - 1; ASSERT(nIndex >= 0); *pType = GetTypeFromIndex(nIndex, bOpenFileDialog); } } return bRet; } void CWordPadApp::OnFileOpen() { // prompt the user (with all document templates) CString newName; int nType = RD_DEFAULT; if (!PromptForFileName(newName, AFX_IDS_OPENFILE, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, &nType)) return; // open cancelled if (nType == RD_OEMTEXT) m_bForceOEM = TRUE; OpenDocumentFile(newName); m_bForceOEM = FALSE; // if returns NULL, the user has already been alerted } BOOL CWordPadApp::OnDDECommand(LPTSTR /*lpszCommand*/) { return FALSE; } ///////////////////////////////////////////////////////////////////////////// // DDE and ShellExecute support //HKEY_CLASSES_ROOT\.RTF = rtffile //HKEY_CLASSES_ROOT\rtffile = //HKEY_CLASSES_ROOT\rtffile\CLSID = {73FDDC80-AEA9-101A-98A7-00AA00374959} //HKEY_CLASSES_ROOT\rtffile\protocol\StdFileEditing\server = WORDPAD.EXE //HKEY_CLASSES_ROOT\rtffile\protocol\StdFileEditing\verb\0 = &Edit //HKEY_CLASSES_ROOT\rtffile\shell\open\command = WORDPAD.EXE %1 //HKEY_CLASSES_ROOT\rtffile\shell\print\command = WORDPAD.EXE /p %1 #define REGENTRY(key, value) _T(key) _T("\0\0") _T(value) #define REGENTRYX(key, valuename, value) _T(key) _T("\0") _T(valuename) _T("\0") _T(value) static const TCHAR sz00[] = REGENTRY("%2", "%5"); static const TCHAR sz01[] = REGENTRY("%2\\CLSID", "%1"); static const TCHAR sz02[] = REGENTRY("%2\\Insertable", ""); static const TCHAR sz03[] = REGENTRY("%2\\protocol\\StdFileEditing\\verb\\0", "&Edit"); static const TCHAR sz04[] = REGENTRY("%2\\protocol\\StdFileEditing\\server", "%3"); static const TCHAR sz05[] = REGENTRY("CLSID\\%1", "%5"); static const TCHAR sz06[] = REGENTRY("CLSID\\%1\\ProgID", "%2"); static const TCHAR sz07[] = REGENTRY("CLSID\\%1\\InprocHandler32", "ole32.dll"); static const TCHAR sz08[] = REGENTRY("CLSID\\%1\\LocalServer32", "%3"); static const TCHAR sz09[] = REGENTRY("CLSID\\%1\\Verb\\0", "&Edit,0,2"); static const TCHAR sz10[] = REGENTRY("CLSID\\%1\\Verb\\1", "&Open,0,2"); static const TCHAR sz11[] = REGENTRY("CLSID\\%1\\Insertable", ""); static const TCHAR sz12[] = REGENTRY("CLSID\\%1\\AuxUserType\\2", "%4"); static const TCHAR sz13[] = REGENTRY("CLSID\\%1\\AuxUserType\\3", "%6"); static const TCHAR sz14[] = REGENTRY("CLSID\\%1\\DefaultIcon", "%3,1"); static const TCHAR sz15[] = REGENTRY("CLSID\\%1\\MiscStatus", "0"); static const TCHAR sz16[] = REGENTRY("%2\\shell\\open\\command", "%3 \"%%1\""); static const TCHAR sz17[] = REGENTRY("%2\\shell\\print\\command", "%3 /p \"%%1\""); static const TCHAR sz18[] = REGENTRY("%7", "%2"); static const TCHAR sz19[] = REGENTRY("%2", ""); // like sz00 only no long type name static const TCHAR sz20[] = REGENTRY("%2\\shell\\printto\\command", "%3 /pt \"%%1\" \"%%2\" \"%%3\" \"%%4\""); static const TCHAR sz21[] = REGENTRY("%2\\DefaultIcon", "%3,%8"); static const TCHAR sz22[] = REGENTRYX("%7\\ShellNew", "NullFile", "true"); static const TCHAR sz23[] = REGENTRYX("%7\\ShellNew", "Data", "{\\rtf1}"); // %1 - class ID // %2 - class name WordPad.Document.1 // %3 - SFN executable path C:\PROGRA~1\ACCESS~1\WORDPAD.EXE // %4 - short type name Document // %5 - long type name Microsoft WordPad Document // %6 - long application name Microsoft WordPad // %7 = extension .rtf // %8 = default icon 0,1,2,3 #define NUM_REG_ARGS 8 static const LPCTSTR rglpszWordPadRegister[] = {sz00, sz02, sz03, sz05, sz09, sz10, sz11, sz15, NULL}; static const LPCTSTR rglpszWordPadOverwrite[] = {sz01, sz04, sz06, sz07, sz08, sz12, sz13, sz14, sz16, sz17, sz20, NULL}; //static const LPCTSTR rglpszExtRegister[] = //{sz00, sz18, NULL}; //static const LPCTSTR rglpszExtOverwrite[] = //{sz01, sz16, sz17, sz21, NULL}; static const LPCTSTR rglpszWriExtRegister[] = {sz18, NULL}; static const LPCTSTR rglpszWriRegister[] = {sz00, sz01, sz16, sz17, sz20, sz21, NULL}; static const LPCTSTR rglpszRtfExtRegister[] = {sz18, sz23, NULL}; static const LPCTSTR rglpszRtfRegister[] = {sz00, sz01, sz16, sz17, sz20, sz21, NULL}; static const LPCTSTR rglpszTxtExtRegister[] = {sz18, sz22, NULL}; static const LPCTSTR rglpszTxtRegister[] = {sz00, sz01, sz16, sz17, sz20, sz21, NULL}; static const LPCTSTR rglpszDocExtRegister[] = {sz18, sz22, NULL}; static const LPCTSTR rglpszDocRegister[] = {sz00, sz01, sz16, sz17, sz20, sz21, NULL}; static void RegisterExt(LPCTSTR lpszExt, LPCTSTR lpszProgID, UINT nIDTypeName, LPCTSTR* rglpszSymbols, LPCTSTR* rglpszExtRegister, LPCTSTR* rglpszRegister, int nIcon) { // don't overwrite anything with the extensions CString strWhole; VERIFY(strWhole.LoadString(nIDTypeName)); CString str; AfxExtractSubString(str, strWhole, DOCTYPE_PROGID); rglpszSymbols[1] = lpszProgID; rglpszSymbols[4] = str; rglpszSymbols[6] = lpszExt; WCHAR buf[12]; EVAL(SUCCEEDED(StringCchPrintf(buf, ARRAYSIZE(buf), L"%d", nIcon))); // Can never fail rglpszSymbols[7] = buf; // check for .ext and progid CKey key; if (!key.Open(HKEY_CLASSES_ROOT, lpszExt, KEY_READ)) // .ext doesn't exist RegisterHelper(rglpszExtRegister, rglpszSymbols, TRUE); key.Close(); if (!key.Open(HKEY_CLASSES_ROOT, lpszProgID, KEY_READ)) // ProgID doesn't exist (i.e. txtfile) RegisterHelper(rglpszRegister, rglpszSymbols, TRUE); } void CWordPadApp::UpdateRegistry() { // If stuff is already initialized, don't overwrite it HKEY rtfkey; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT(".rtf"), 0, KEY_READ, &rtfkey)) { // .rtf is already registered, assume the rest are as well RegCloseKey(rtfkey); return; } USES_CONVERSION; LPOLESTR lpszClassID = NULL; CDocTemplate* pDocTemplate = &DocTemplate; // get registration info from doc template string CString strServerName; CString strLocalServerName; CString strLocalShortName; if (!pDocTemplate->GetDocString(strServerName, CDocTemplate::regFileTypeId) || strServerName.IsEmpty()) { TRACE0("Error: not enough information in DocTemplate to register OLE server.\n"); return; } if (!pDocTemplate->GetDocString(strLocalServerName, CDocTemplate::regFileTypeName)) strLocalServerName = strServerName; // use non-localized name if (!pDocTemplate->GetDocString(strLocalShortName, CDocTemplate::fileNewName)) strLocalShortName = strLocalServerName; // use long name ASSERT(strServerName.Find(' ') == -1); // no spaces allowed ::StringFromCLSID(clsid, &lpszClassID); ASSERT (lpszClassID != NULL); // get path name to server TCHAR szLongPathName[_MAX_PATH]; TCHAR szShortPathName[_MAX_PATH]; ::GetModuleFileName(AfxGetInstanceHandle(), szLongPathName, _MAX_PATH); ::GetShortPathName(szLongPathName, szShortPathName, _MAX_PATH); LPCTSTR rglpszSymbols[NUM_REG_ARGS]; rglpszSymbols[0] = OLE2CT(lpszClassID); rglpszSymbols[1] = strServerName; rglpszSymbols[2] = szShortPathName; rglpszSymbols[3] = strLocalShortName; rglpszSymbols[4] = strLocalServerName; rglpszSymbols[5] = m_pszAppName; // will usually be long, readable name rglpszSymbols[6] = NULL; if (RegisterHelper((LPCTSTR*)rglpszWordPadRegister, rglpszSymbols, FALSE)) RegisterHelper((LPCTSTR*)rglpszWordPadOverwrite, rglpszSymbols, TRUE); // RegisterExt(_T(".txt"), _T("txtfile"), IDS_TEXT_DOC, rglpszSymbols, // (LPCTSTR*)rglpszTxtExtRegister, (LPCTSTR*)rglpszTxtRegister, 3); RegisterExt(_T(".rtf"), _T("rtffile"), IDS_RICHTEXT_DOC, rglpszSymbols, (LPCTSTR*)rglpszRtfExtRegister, (LPCTSTR*)rglpszRtfRegister, 1); RegisterExt(_T(".wri"), _T("wrifile"), IDS_WRITE_DOC, rglpszSymbols, (LPCTSTR*)rglpszWriExtRegister, (LPCTSTR*)rglpszWriRegister, 2); RegisterExt(_T(".doc"), _T("WordPad.Document.1"), IDS_WINWORD6_DOC, rglpszSymbols, (LPCTSTR*)rglpszDocExtRegister, (LPCTSTR*)rglpszDocRegister, 1); // free memory for class ID ASSERT(lpszClassID != NULL); CoTaskMemFree(lpszClassID); } BOOL RegisterHelper(LPCTSTR* rglpszRegister, LPCTSTR* rglpszSymbols, BOOL bReplace) { ASSERT(rglpszRegister != NULL); ASSERT(rglpszSymbols != NULL); WCHAR szKey[256]; WCHAR szValue[256]; LPCTSTR pszValueName; BOOL bResult = TRUE; while (*rglpszRegister != NULL) { LPCTSTR lpszKey = *rglpszRegister++; if (*lpszKey == '\0') continue; LPCTSTR lpszValueName = lpszKey + lstrlen(lpszKey) + 1; LPCTSTR lpszValue = lpszValueName + lstrlen(lpszValueName) + 1; DWORD dwRes; // lpszKey is a safe format string - see REGENTRY dwRes = FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, lpszKey, NULL, NULL, szKey, ARRAYSIZE(szKey), (va_list*)rglpszSymbols); if (dwRes == 0) continue; pszValueName = lpszValueName; // lpszValue is safe format string - see REGENTRY dwRes = FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, lpszValue, NULL, NULL, szValue, ARRAYSIZE(szValue), (va_list*)rglpszSymbols); if (dwRes == 0) continue; if (!szKey[0]) { TRACE1("Warning: skipping empty key '%s'.\n", lpszKey); continue; } CKey key; VERIFY(key.Create(HKEY_CLASSES_ROOT, szKey, KEY_ALL_ACCESS)); if (!bReplace) { CString str; if (key.GetStringValue(str, pszValueName) && !str.IsEmpty()) continue; } if (!key.SetStringValue(szValue, pszValueName)) { TRACE2("Error: failed setting key '%s' to value '%s'.\n", szKey, szValue); bResult = FALSE; break; } } return bResult; } void CWordPadApp::WinHelp(DWORD dwData, UINT nCmd) { if (g_fDisableStandardHelp) { return ; } if ( (nCmd == HELP_FINDER) || (nCmd == HELP_CONTENTS) || (nCmd == HELP_INDEX) ) { ::HtmlHelpA( ::GetDesktopWindow(), "wordpad.chm", HH_DISPLAY_TOPIC, 0L ); return; } CWinApp::WinHelp(dwData, nCmd); } BOOL CWordPadApp::PreTranslateMessage(MSG* pMsg) { if (pMsg->message == WM_PAINT) return FALSE; // CWinApp::PreTranslateMessage does nothing but call base return CWinThread::PreTranslateMessage(pMsg); } void CWordPadApp::NotifyPrinterChanged(BOOL bUpdatePrinterSelection) { if (bUpdatePrinterSelection) UpdatePrinterSelection(TRUE); POSITION pos = m_listPrinterNotify.GetHeadPosition(); while (pos != NULL) { HWND hWnd = m_listPrinterNotify.GetNext(pos); ::SendMessage(hWnd, m_nPrinterChangedMsg, 0, 0); } } BOOL CWordPadApp::IsIdleMessage(MSG* pMsg) { if (pMsg->message == WM_MOUSEMOVE || pMsg->message == WM_NCMOUSEMOVE) return FALSE; return CWinApp::IsIdleMessage(pMsg); } #define DN_PADDINGCHARS 16 HGLOBAL CWordPadApp::CreateDevNames() { HGLOBAL hDev = NULL; CString strDriverName; CString strPrinterName; CString strPortName; if (!cmdInfo.m_strPrinterName.IsEmpty()) { strDriverName = cmdInfo.m_strDriverName; strPrinterName = cmdInfo.m_strPrinterName; strPortName = cmdInfo.m_strPortName; } else { PRINTDLG printdlg; DEVNAMES *devnames; if (!GetPrinterDeviceDefaults(&printdlg)) return NULL; devnames = (DEVNAMES *) ::GlobalLock(printdlg.hDevNames); if (NULL == devnames) return NULL; strDriverName = (LPTSTR) ((BYTE *) devnames) + devnames->wDriverOffset; strPrinterName = (LPTSTR) ((BYTE *) devnames) + devnames->wDeviceOffset; strPortName = (LPTSTR) ((BYTE *) devnames) + devnames->wOutputOffset; ::GlobalUnlock(printdlg.hDevNames); } DWORD cbDevNames ; int cchDriverName = strDriverName.GetLength() + 1; int cchPrinterName = strPrinterName.GetLength() + 1; int cchPortName = strPortName.GetLength() + 1; cbDevNames = cchDriverName + cchPrinterName + cchPortName + DN_PADDINGCHARS ; cbDevNames *= sizeof(TCHAR) ; cbDevNames += sizeof(DEVNAMES) ; hDev = GlobalAlloc(GPTR, cbDevNames) ; if (NULL == hDev) return NULL; LPDEVNAMES lpDev = (LPDEVNAMES)GlobalLock(hDev) ; // Sufficient memory was allocated for these strcpy's above. lpDev->wDriverOffset = sizeof(DEVNAMES) / sizeof(TCHAR) ; StringCchCopy((LPTSTR) lpDev + lpDev->wDriverOffset, cchDriverName, strDriverName) ; lpDev->wDeviceOffset = (WORD) (lpDev->wDriverOffset + strDriverName.GetLength() + 1); StringCchCopy((LPTSTR) lpDev + lpDev->wDeviceOffset, cchPrinterName, strPrinterName) ; lpDev->wOutputOffset = (WORD) (lpDev->wDeviceOffset + strPrinterName.GetLength() + 1); StringCchCopy((LPTSTR) lpDev + lpDev->wOutputOffset, cchPortName, strPortName) ; lpDev->wDefault = 0; return hDev; } //+--------------------------------------------------------------------------- // // Method: CWordPadApp::DoDeferredInitialization, static // // Synopsis: Thread entry point for low priority initialization // // Parameters: [pvWordPadApp] -- Pointer to to CWordPadApp // // Returns: Thread exit code // //--------------------------------------------------------------------------- UINT AFX_CDECL CWordPadApp::DoDeferredInitialization(LPVOID pvWordPadApp) { ASSERT(NULL != pvWordPadApp); CWordPadApp *pWordPadApp = (CWordPadApp *) pvWordPadApp; pWordPadApp->m_initialization_phase = InitializingPrinter; pWordPadApp->m_hDevNames = pWordPadApp->CreateDevNames(); pWordPadApp->m_initialization_phase = UpdatingPrinterRelatedUI; pWordPadApp->NotifyPrinterChanged( ((pWordPadApp->m_hDevNames) == NULL) ); pWordPadApp->m_initialization_phase = UpdatingRegistry; pWordPadApp->UpdateRegistry(); pWordPadApp->m_initialization_phase = InitializationComplete; return 0; } //+-------------------------------------------------------------------------- // // Method: CWordPadApp::EnsurePrinterIsInitialized // // Synopsis: Make sure the printer is done initializing // // Parameters: None // // Returns: void // // Notes: We'll only wait two minutes. If the printer takes that long // to initialize printing probably is going to be flakey anyway. // // The main purpose of doing printer initialization on a different // thread is so that it doesn't get in the way of doing real work. // On the other hand if printing is the real work we should try to // get things moving so bump it up from idle priority. // //--------------------------------------------------------------------------- void CWordPadApp::EnsurePrinterIsInitialized() { int nWaits = 0; BOOL bBumpedPriority = FALSE; if (NULL == m_pInitializationThread) { ASSERT(NULL != m_pInitializationThread); bBumpedPriority = TRUE; } while (m_initialization_phase <= InitializingPrinter && nWaits < 1200) { if (!bBumpedPriority) { m_pInitializationThread->SetThreadPriority( THREAD_PRIORITY_ABOVE_NORMAL); bBumpedPriority = TRUE; } Sleep(100); ++nWaits; } if (bBumpedPriority) m_pInitializationThread->SetThreadPriority(THREAD_PRIORITY_IDLE); } // Free with delete [] LPSTR WideToAnsiNewArray(LPCWSTR pwsz) { LPSTR psz = NULL; int cbBuf = WideCharToMultiByte(CP_ACP, 0, pwsz, -1, NULL, 0, NULL, NULL); if (cbBuf) { psz = new char[cbBuf]; if (psz) { cbBuf = WideCharToMultiByte(CP_ACP, 0, pwsz, -1, psz, cbBuf, NULL, NULL); if (!cbBuf) { // Conversion failed? delete [] psz; psz = NULL; } } } return psz; } // Free with delete [] LPWSTR AnsiToWideNewArray(LPCSTR psz) { LPWSTR pwsz = NULL; int cchBuf = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0); if (cchBuf) { pwsz = new WCHAR[cchBuf]; if (pwsz) { cchBuf = MultiByteToWideChar(CP_ACP, 0, psz, -1, pwsz, cchBuf); if (!cchBuf) { // Conversion failed? delete [] pwsz; pwsz = NULL; } } } return pwsz; }