// // Copyright 1997 Nicholas J. Irias. All rights reserved. // // // P4win.cpp : Defines the class behaviors for the application. // #include "stdafx.h" #include "P4win.h" #include "hlp\p4win.hh" #include "MainFrm.h" #include "Document.h" #include "DepotView.h" #include "resource.h" #include "TokenString.h" #include "NewWindowDlg.h" #include "RegKeyEx.h" #include "cmd_info.h" #include "Cmd_Login.h" #include "ImageList.h" #include #include #include "GuiClientUser.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif int global_cancel = 0; CString startingfolder; ///////////////////////////////////////////////////////////////////////////// // CP4winApp BEGIN_MESSAGE_MAP(CP4winApp, CP4GuiApp) //{{AFX_MSG_MAP(CP4winApp) ON_COMMAND(ID_NEW_WINDOW, OnNewWindow) ON_UPDATE_COMMAND_UI(ID_NEW_WINDOW, OnUpdateNewWindow) //}}AFX_MSG_MAP // Standard file based document commands ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew) ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) // Standard print setup command ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CP4winApp construction CP4winApp::CP4winApp() { EnableHtmlHelp(); m_IdleCounter = 1; m_InitialView = _T('\0'); m_WarningDialog= TRUE; m_TestFlag= FALSE; m_hNWSRVLOC = LoadLibrary(_T("NWSRVLOC.dll")); m_RevHistCount = 0; m_RevHistEnableShowIntegs = TRUE; m_viewImageList = 0; m_toolBarImageList = 0; m_RevHistLast = 0; m_bFindInChg = FALSE; DWORD dummy; TCHAR cmdLine[] = _T("P4Merge.exe"); m_P4Merge = GetFileVersionInfoSize( cmdLine, &dummy ) > 0 ? 1 : 0; if (m_P4Merge) m_P4MergeVer = MainFrame()->GetExeVersion(cmdLine); } CP4winApp::~CP4winApp() { if(m_viewImageList) { m_viewImageList->Detach(); delete m_viewImageList; } if(m_toolBarImageList) { m_toolBarImageList->Detach(); delete m_toolBarImageList; } if(m_hMutex != NULL) CloseHandle(m_hMutex); if (m_hNWSRVLOC) FreeLibrary(m_hNWSRVLOC); } ///////////////////////////////////////////////////////////////////////////// // The one and only CP4winApp object CP4winApp theApp; ///////////////////////////////////////////////////////////////////////////// // command line parsing static enum Arg { none, port, user, client, password, view, charset, selection, fileinfo, revhist, revhistcnt, submit, diff, find, icons, cr8cli, toolsimp } nextArg = none; void CP4winApp::ParseArg(LPCTSTR pArg) { // usage: [switches] // switches: // -q : disable warnings // -p port : set p4port // -u user : set p4user // -c client : set p4client // -P password : set p4password // -v view : set initial view // -C charset : set initial character set // -s selection: set initial selection // -I fileinfo : set requested file properties path // -H revhist : set requested revision history path // -m revhistcnt: set requested revision history count // -S submit : submit changelist containing filepath // -D diff : diff filepath against depot // -F find : find filepath in depot pane // -i colors : set requested icons // -( cr8cli : run new client wizard (if client doesn't exist) // -T toolsimp : import custom tools from a file if(nextArg == none) { if(lstrlen(pArg) == 2) { switch(pArg[1]) { case _T('Q'): m_TestFlag = TRUE; case _T('q'): m_WarningDialog = FALSE; return; case _T('p'): nextArg = port; return; case _T('u'): nextArg = user; return; case _T('c'): nextArg = client; return; case _T('P'): nextArg = password; return; case _T('v'): nextArg = view; return; case _T('C'): nextArg = charset; return; case _T('s'): nextArg = selection; return; case _T('I'): nextArg = fileinfo; return; case _T('H'): nextArg = revhist; return; case _T('m'): nextArg = revhistcnt; return; case _T('S'): nextArg = submit; return; case _T('D'): nextArg = diff; return; case _T('F'): nextArg = find; return; case _T('i'): nextArg = icons; return; case _T('('): nextArg = cr8cli; return; case _T('T'): nextArg = toolsimp; return; } } } else { Arg thisArg = nextArg; nextArg = none; switch(thisArg) { case port: if(lstrlen(pArg)) { GET_P4REGPTR()->SetP4Port(pArg, TRUE, FALSE, FALSE); return; } case user: if(lstrlen(pArg)) { GET_P4REGPTR()->SetP4User(pArg, TRUE, FALSE, FALSE); return; } case cr8cli: m_WarningDialog = FALSE; m_RunClientWizOnly = TRUE;; case client: if(lstrlen(pArg)) { GET_P4REGPTR()->SetP4Client(pArg, TRUE, FALSE, FALSE); return; } case password: if(lstrlen(pArg)) { GET_P4REGPTR()->SetP4Password(pArg, TRUE, FALSE, FALSE); CCmd_Login *pCmd = new CCmd_Login; // run p4 login CString portStr = GET_P4REGPTR()->GetP4Port(); // get current port pCmd->GetClient()->SetPort(portStr); // run login against cur port CString userStr = GET_P4REGPTR()->GetP4User(); // get current user pCmd->GetClient()->SetUser(userStr); // run login against cur user pCmd->Init(NULL, RUN_SYNC, LOSE_LOCK, 0); pCmd->Run(pArg); // run the login command delete pCmd; return; } case view: if(lstrlen(pArg)) { m_InitialView = (TCHAR)CharUpper((LPTSTR)(TBYTE)pArg[0]); return; } case charset: if(lstrlen(pArg)) { GET_P4REGPTR()->SetP4Charset(pArg, TRUE, FALSE, FALSE); GET_P4REGPTR()->SetP4CharsetFromCmdli(TRUE); // must follow SetP4Charset()! return; } case selection: if(lstrlen(pArg)) { m_WarningDialog = FALSE; m_ExpandPath = DemanglePath(pArg); if (m_ExpandPath.GetAt(0) != _T('/') && m_ExpandPath.GetAt(1) != _T(':') && m_ExpandPath.GetAt(0) != _T('\\')) { TCHAR buf[MAX_PATH+1]; if (GetCurrentDirectory(sizeof(buf)-1, buf)) { CString str = CString(buf) + _T('\\') + m_ExpandPath; m_ExpandPath = str; } } m_bFindInChg = TRUE; return; } case fileinfo: if(lstrlen(pArg)) { m_WarningDialog = FALSE; m_FileInfoPath = DemanglePath(pArg); return; } case revhist: if(lstrlen(pArg)) { m_WarningDialog = FALSE; m_RevHistPath = DemanglePath(pArg); return; } case revhistcnt: if(lstrlen(pArg)) { m_RevHistCount = _tstoi(pArg); return; } case submit: if(lstrlen(pArg)) { m_WarningDialog = FALSE; if (m_SubmitPath.IsEmpty()) m_SubmitPath = DemanglePath(pArg); else m_SubmitPathList.AddTail(DemanglePath(pArg)); nextArg = submit; return; } case diff: if(lstrlen(pArg)) { m_WarningDialog = FALSE; m_DiffPath = DemanglePath(pArg); return; } case toolsimp: if(lstrlen(pArg)) { m_WarningDialog = FALSE; m_ToolsImportPath = DemanglePath(pArg); return; } case icons: GET_P4REGPTR()->SetUse256colorIcons((_tstoi(pArg) == 256) ? TRUE : FALSE); return; } } if (*(pArg+1) == _T(':')) { nextArg = revhist; ParseArg(pArg); return; } ASSERT(0); m_bGoodArgs = false; } ///////////////////////////////////////////////////////////////////////////// // CP4winApp initialization BOOL CP4winApp::InitInstance() { if(!CP4GuiApp::InitInstance()) return FALSE; LoadStdProfileSettings(0); // Do NOT track MRU files // Get Perforce connect info from registry m_RegInfo.ReadRegistry(); m_bGoodArgs = true; ParseCommandLineArgs(); if(!m_bGoodArgs) { MessageBox(NULL, LoadStringResource(IDS_INVALID_COMMAND_LINE_ARGS__USAGE), LoadStringResource(IDS_P4WINUSAGE), MB_ICONEXCLAMATION); return FALSE; } /////////////////// // Test for previous instance, by attempting to open a named mutex // If an instance is already running, see if user wants to activate it m_WM_ACTIVATE= RegisterWindowMessage(_T("Activate Previous P4Win")); m_WM_SENDCMD = RegisterWindowMessage(_T("P4Win Send Command")); m_WM_RPLYCMD = RegisterWindowMessage(_T("P4Win Reply Command")); m_hMutex= OpenMutex(SYNCHRONIZE, FALSE, _T("Running P4Win Instance")); if(m_hMutex==NULL) { // This is the first instance m_hMutex= CreateMutex(NULL, FALSE, _T("Running P4Win Instance")); } else if (!m_ExpandPath.IsEmpty()) { BOOL b = FALSE; HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // max. object size P4WIN_SHARED_MEMORY_SIZE, // buffer size P4WIN_SHARED_MEMORY_NAME); // name of mapping object if (hMapFile != NULL && hMapFile != INVALID_HANDLE_VALUE) { EXPANDPATH *ep = (EXPANDPATH *)MapViewOfFile(hMapFile, // handle to mapping object FILE_MAP_ALL_ACCESS, 0, 0, P4WIN_SHARED_MEMORY_SIZE); if (ep != NULL) { TCHAR *p = ep->buf; lstrcpy(p, GET_P4REGPTR()->GetP4Port()); ep->port = p - ep->buf; p += lstrlen(p) + 1; lstrcpy(p, GET_P4REGPTR()->GetP4Client()); ep->client = p - ep->buf; p += lstrlen(p) + 1; lstrcpy(p, GET_P4REGPTR()->GetP4User()); ep->user = p - ep->buf; p += lstrlen(p) + 1; lstrcpy(p, m_ExpandPath); ep->path = p - ep->buf; ::SendMessage( HWND_BROADCAST, m_WM_SENDCMD, (WPARAM)1, (LPARAM)0 ); Sleep(500); if (ep->flag) b = TRUE; UnmapViewOfFile(ep); } CloseHandle(hMapFile); if (b) return FALSE; } } else if( m_WarningDialog ) { // See if user wants to activate previous instance // int ret = AfxMessageBox(IDS_P4WIN_IS_ALREADY_RUNNING__OPEN_THE_OLD_WINDOW, MB_YESNOCANCEL | MB_ICONEXCLAMATION ) ; // only when user picks NO do we run the app // switch( ret ) { case IDYES: ::SendMessage( HWND_BROADCAST, m_WM_ACTIVATE, 0, 0 ); case IDCANCEL: return FALSE; } } // Load up the shared image lists m_viewImageList = new CP4ViewImageList(); m_toolBarImageList = new CP4WinToolBarImageList(); if(GET_P4REGPTR()->Use256colorIcons()) { m_viewImageList->Use256ColorIcons(); m_toolBarImageList->Use256ColorIcons(); } m_viewImageList->Create(); m_toolBarImageList->Create(); // Load up the busy cursor, after reading registry cwinapp m_hBusyCursor= GET_P4REGPTR()->GetP4BusyCursor() ? ::LoadCursorFromFile(_T("P4_Busy.ani")) : NULL; if(m_hBusyCursor==NULL) m_hBusyCursor= LoadStandardCursor(IDC_WAIT); // Write our version number to the registry so P4wei knows what version we are. LPCTSTR sKey = _T("Software\\Perforce\\P4Win\\"); LPCTSTR sVersion = _T("Version"); CRegKeyEx key; if(ERROR_SUCCESS == key.Create(HKEY_CURRENT_USER, sKey, REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE)) key.SetValueString(m_appVersion, sVersion); // Register the application's document templates. Document templates // serve as the connection between documents, frame windows and views. CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CP4winDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame window RUNTIME_CLASS(CDepotView)); AddDocTemplate(pDocTemplate); int i; CString ver = ((CP4GuiApp*)AfxGetApp())->GetAppVersionString(); CString info = ver.Mid(3,3) + _T(" "); if ((i = ver.ReverseFind(_T('.'))) != -1) ver.Delete(i); #ifdef UNICODE info += _T("U"); #endif CString info_ver = info + ver; info_ver.Replace(' ', '.'); CharString cs = CharFromCString(info_ver); strcpy(m_version, cs); OnFileNew(); // Make sure our name is P4Win, not P4win or p4win if (m_pszAppName && *m_pszAppName && *(m_pszAppName+1) == '4') { TCHAR *p = (TCHAR *)m_pszAppName; *p = _totupper(*m_pszAppName); *(p+2) = _totupper(*(m_pszAppName+2)); } return TRUE; } //////////////////////////////////////////////////////////////////////////// // Set a new busy state for Perforce server BOOL CP4winApp::GetServerLock(int &key) { // Actually set busy BOOL gotLock= m_CS.GetServerLock( key); // Get and set cursor position - Windows will then generate the necessary // WM_SETCURSOR messages to get the right OnSetCursor() function called if( gotLock ) { POINT pt; if(::GetCursorPos(&pt)) ::SetCursorPos(pt.x, pt.y); } return gotLock; } void CP4winApp::ReleaseServerLock(int &key) { m_CS.ReleaseServerLock( key ); // Get and set cursor position - Windows will then generate the necessary // WM_SETCURSOR messages to get the right OnSetCursor() function called POINT pt; if(::GetCursorPos(&pt)) ::SetCursorPos(pt.x, pt.y); } //////////////////////////////////////////////////////////////////////////// // Access functions for shared image list. int CP4winApp::GetFileImageIndex(CP4FileStats *fs, BOOL IsChangesWindow) { // Start at first file int state; // What type of file is it? CString fileType = fs->GetHeadType(); int iType = ((fileType.Find(_T("text")) != -1) || (fileType.Find(_T("symlink")) != -1)) ? 0 : 1; // get base image: if(!IsChangesWindow && fs->GetHaveRev() > fs->GetHeadRev() && fs->GetMyOpenAction() == 0 ) { // A ghost file. We Have the file, but its outside the // client view. state = CP4ViewImageList::FSB_GHOST; } else if(iType) { // normal binary file state = CP4ViewImageList::FSB_BINARY; } else { // normal text file state = CP4ViewImageList::FSB_TEXT; } // lock state overlay if(fs->IsMyLock() || fs->IsMyOpenExclusive()) state |= CP4ViewImageList::FSB_YOUR_LOCK; else if(fs->IsOtherLock() || fs->IsOtherOpenExclusive()) state |= CP4ViewImageList::FSB_THEIR_LOCK; // my action overlay switch(fs->GetMyOpenAction()) { case F_ADD: case F_BRANCH: case F_IMPORT: state |= CP4ViewImageList::FSB_YOUR_ADD; break; case F_EDIT: case F_INTEGRATE: state |= CP4ViewImageList::FSB_YOUR_EDIT; break; case F_DELETE: state |= CP4ViewImageList::FSB_YOUR_DELETE; break; } // other action overlay switch(fs->GetOtherOpenAction()) { case F_ADD: case F_BRANCH: case F_IMPORT: state |= CP4ViewImageList::FSB_THEIR_ADD; break; case F_EDIT: case F_INTEGRATE: state |= CP4ViewImageList::FSB_THEIR_EDIT; break; case F_DELETE: state |= CP4ViewImageList::FSB_THEIR_DELETE; break; } // sync state overlay, depends on which view we're in if(IsChangesWindow) { if(fs->IsUnresolved()) state |= CP4ViewImageList::FSB_NOT_SYNCED; } else { if(fs->GetHaveRev()) { if(fs->GetHaveRev() >= fs->GetHeadRev() || fs->GetMyOpenAction() == F_ADD) state |= CP4ViewImageList::FSB_SYNCED; else if(fs->GetHaveRev() < fs->GetHeadRev()) state |= CP4ViewImageList::FSB_NOT_SYNCED; } } return CP4ViewImageList::GetFileIndex(state); } /* _________________________________________________________________ */ void CP4winApp::StatusAdd( LPCTSTR txt, StatusView level, bool showDialog ) { // get out if we call with garbage or an empty string // if ( txt == NULL ) return; if ( lstrlen( txt ) < 1 ) return; LPTSTR msg = new TCHAR[ lstrlen( txt ) + 1 ]; lstrcpy( msg, txt ); // don't post the message until we get a window. since i // put up messages constantly, i can easily post before a // window is up. this is cheesy, but simpler than doing an // onidle(), and after all, these are just boring status messages. // CWnd *pWnd = AfxGetApp( )->m_pMainWnd; if ( pWnd ) ::PostMessage( pWnd->m_hWnd, WM_STATUSADD, ( WPARAM ) msg, MAKELPARAM(level, showDialog ? 1 : 0)); else delete [ ] msg; } void CP4winApp::StatusAdd( CStringArray *pArray, StatusView level, bool showDialog ) { // get out if we call with garbage or an empty string // if ( pArray == NULL ) return; // don't post the message until we get a window. since i // put up messages constantly, i can easily post before a // window is up. this is cheesy, but simpler than doing an // onidle(), and after all, these are just boring status messages. // CWnd *pWnd = AfxGetApp( )->m_pMainWnd; if ( pWnd ) ::PostMessage( pWnd->m_hWnd, WM_STATUSADDARRAY, ( WPARAM ) pArray, MAKELPARAM(level, showDialog ? 1 : 0)); else delete [ ] pArray; } void CP4winApp::WinHelp(DWORD dwData, UINT nCmd) { // MFC automatically assigns help IDs for all menu commands, // dialogs and frames (see p4win.hm as produced by makehelp.bat). // For the time being, only helpIDs that come from the p4win.hh // file (sequential IDs that start at 1) will be taken as context // help. Every other help request will be sent to the help contents. // // TODO: The menu commands (0x10001 to 0x1ffff) could all have popup // context menues. But if a single menu command help id is // missing in the help file, there will be an ugly message // for the user. // // An alternative is to direct all menu command IDs to a single // topic in the help file // // Yet another option is to use the IDs in p4win.hm for everything // and then set up enough aliases so that nothing falls thru. The // robohelp help compiler warns about .hm entries that dont have // topics. if(dwData < 0x10000 && nCmd != HH_HELP_FINDER) CWinApp::HtmlHelp(dwData, HH_HELP_CONTEXT); else CWinApp::HtmlHelp(dwData, HH_HELP_FINDER); } // Spawn a helper app. For console applications, a batch file is used to ensure // that filename arguments with ebmedded spaces are passed correctly. BOOL CP4winApp::RunApp(int app, RunAppMode mode, HWND hWnd, BOOL isUnicode, RUNAPPTHREADINFO *lprati, CString &errorText, LPCTSTR arg1, LPCTSTR arg2, LPCTSTR arg3, LPCTSTR arg4, LPCTSTR arg5, LPCTSTR arg6, LPCTSTR arg7, LPCTSTR arg8, LPCTSTR arg9, LPCTSTR arg10,LPCTSTR arg11,LPCTSTR arg12, LPCTSTR arg13,LPCTSTR arg14,LPCTSTR arg15,LPCTSTR arg16, LPCTSTR arg17) { CString orgArgX; CString orgArgY; TCHAR buf1[LONGPATH*2 + 1]; TCHAR buf2[LONGPATH + 1]; TCHAR buf3[LONGPATH + 1]; TCHAR buf4[LONGPATH + 1]; TCHAR buf5[LONGPATH + 1]; int i; // Find out if we're running NT or win95 OSVERSIONINFO osVer; osVer.dwOSVersionInfoSize= sizeof(OSVERSIONINFO); GetVersionEx(&osVer); // Set up the spawn operation #ifdef UNICODE DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT; #else DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS; #endif PROCESS_INFORMATION procInfo; STARTUPINFO startInfo; TCHAR cmdTitle[255]; GetStartupInfo(&startInfo); startInfo.lpReserved= startInfo.lpDesktop= NULL; startInfo.dwFlags |= STARTF_USESHOWWINDOW; startInfo.wShowWindow = SW_SHOWNORMAL; // Find out what app we're running CString appName, appText, title; int numArgs = 0; int bInternal = 0; BOOL isConsole=FALSE; BOOL isClose=FALSE; BOOL bSquid=FALSE; switch(app) { case DIFF_APP: { orgArgX = arg4; orgArgY = arg6; // First, get the file extension, if any, and find out if // it has an associated diff for that extension appName.Empty(); CString extension = GetFilesExtension(arg2); if (!extension.CompareNoCase(_T("tmp"))) extension = GetFilesExtension(arg1); if(!extension.IsEmpty()) appName= GET_P4REGPTR()->GetAssociatedDiff(extension); if (!appName.IsEmpty()) { bInternal = 0; CString appProg = appName; if ((i = appProg.ReverseFind(_T('\\'))) > -1) appProg = appProg.Right(appProg.GetLength() - i - 1); if (appProg == _T("P4Diff.exe")) bInternal = 2; else if (!appProg.CompareNoCase(_T("Squid.exe"))) bSquid = TRUE; } else if ((bInternal = GET_P4REGPTR()->GetDiffInternal()) >= 2) { bInternal = 2; appName= _T("P4Diff.exe"); } else if (bInternal == 1) { if (m_P4Merge && (osVer.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)) { appName= _T("P4Merge.exe"); } else { bInternal = 2; appName= _T("P4Diff.exe"); } } else { appName= GET_P4REGPTR()->GetDiffApp(); CString appProg = appName; if ((i = appProg.ReverseFind(_T('\\'))) > -1) appProg = appProg.Right(appProg.GetLength() - i - 1); if (appProg == _T("P4Diff.exe")) bInternal = 2; else if (!appProg.CompareNoCase(_T("Squid.exe"))) bSquid = TRUE; else { // non-Perforce diff app may require DOS console to work correctly isConsole= GET_P4REGPTR()->GetDiffAppIsConsole(); isClose = GET_P4REGPTR()->GetDiffAppIsClose(); } } appText= LoadStringResource(IDS_APP_DIFF); title= LoadStringResource(IDS_TITLE_DIFF); numArgs=2; if (arg1!=NULL && lstrlen(arg1) > 0) { if (*(arg1+1) == _T(':')) { if (GetFileAttributes(arg1) == -1) { appText.FormatMessage(IDS_DIFF_FILENOTFOUND, arg1); AddToStatus(appText, SV_ERROR); return FALSE; } } } else { ASSERT(0); } if (arg2!=NULL && lstrlen(arg2) > 0) { if (*(arg2+1) == _T(':')) { if (GetFileAttributes(arg2) == -1) { appText.FormatMessage(IDS_DIFF_FILENOTFOUND, arg2); AddToStatus(appText, SV_ERROR); return FALSE; } } } else { ASSERT(0); } if (bInternal == 2) { ASSERT(arg7==NULL && arg8==NULL && arg9==NULL); switch (GET_P4REGPTR()->GetWhtSpFlag()) { case 1: arg7 = _T("-b"); break; case 2: arg7 = _T("-w"); break; default: arg7 = _T("-e"); break; } _stprintf(buf1, _T("%d"), -1); // Temp until implment passing context _stprintf(buf2, _T("%d"), GET_P4REGPTR()->GetTabWidth()); arg8 = buf1; arg9 = buf2; // On win/9x, we can't have a nice long command line - throw away -r and -l if (!arg3 || (osVer.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)) { arg3 = arg7; arg4 = arg8; arg5 = arg9; arg6 = NULL; numArgs=5; } else if (!arg5) { ASSERT(arg3!=NULL && lstrlen(arg3) > 0); ASSERT(arg4!=NULL && lstrlen(arg4) > 0); arg5 = arg7; arg6 = arg8; arg7 = arg9; arg8 = NULL; numArgs=7; } else numArgs=9; } else if (bInternal) { ASSERT(arg7==NULL && arg8==NULL && arg9==NULL); LPCTSTR sav1 = arg1; LPCTSTR sav2 = arg2; LPCTSTR sav4 = arg4; LPCTSTR sav6 = arg6; switch (GET_P4REGPTR()->GetWhtSpFlag()) { case 0: arg1 = _T("-dl"); break; case 1: arg1 = _T("-db"); break; case 2: arg1 = _T("-dw"); break; case 3: arg1 = _T("-da"); break; default: arg1 = _T(" "); break; } _stprintf(buf1, _T("%d"), GET_P4REGPTR()->GetTabWidth()); arg2 = _T("-tw"); arg3 = buf1; arg4 = _T("-nl"); arg5 = sav4 ? sav4 : sav1; arg6 = _T("-nr"); arg7 = sav6 ? sav6 : sav2; arg8 = sav1; arg9 = sav2; numArgs=9; } else if (bSquid) { // On win/9x, we can't have a nice long command line - throw away -r and -l if (!arg3 || (osVer.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)) { arg3 = arg4 = arg5 = arg6 = NULL; numArgs=2; } else numArgs = arg5 ? 6 : 4; } break; } case EDIT_APP: appName= GET_P4REGPTR()->GetEditApp(); appText= LoadStringResource(IDS_APP_EDITOR); title.FormatMessage(IDS_TITLE_EDITOR_s, appName); numArgs=1; isConsole= GET_P4REGPTR()->GetEditAppIsConsole(); // isClose = GET_P4REGPTR()->GetEditAppIsClose(); ASSERT(arg1!=NULL && lstrlen(arg1) > 0); ASSERT(arg2==NULL && arg3==NULL && arg4==NULL); break; case TREE_APP: #ifdef UNICODE switch(MainFrame()->HaveP4QTree()) { default: case 1: if (MainFrame()->GetP4Vver() < 20051) { DWORD ver = MainFrame()->GetP4Vver(); DWORD yr = ver / 10; DWORD pt = ver - (yr*10); CString txt; txt.FormatMessage(IDS_P4VTOOOLD, yr, pt, _T("2005.1")); AfxMessageBox(txt, MB_ICONEXCLAMATION); return FALSE; } appName= _T("p4v.exe"); startInfo.wShowWindow = SW_SHOWNORMAL; ASSERT(arg10 !=NULL && lstrlen(arg10) > 0); ASSERT(arg15==NULL); numArgs = (arg11 == NULL) ? 10 : (arg13 == NULL) ? 12 : 14; switch(numArgs) { case 10: if (WideCharToMultiByte(CP_UTF8, 0, arg10, -1, (LPSTR)buf2, sizeof(buf2), NULL, NULL) && MultiByteToWideChar(1252, 0, (LPSTR)buf2, -1, buf1, sizeof(buf1))) arg10 = buf1; break; case 12: if (WideCharToMultiByte(CP_UTF8, 0, arg12, -1, (LPSTR)buf2, sizeof(buf2), NULL, NULL) && MultiByteToWideChar(1252, 0, (LPSTR)buf2, -1, buf1, sizeof(buf1))) arg12 = buf1; break; case 14: if (WideCharToMultiByte(CP_UTF8, 0, arg14, -1, (LPSTR)buf2, sizeof(buf2), NULL, NULL) && MultiByteToWideChar(1252, 0, (LPSTR)buf2, -1, buf1, sizeof(buf1))) arg14 = buf1; break; default: ASSERT(0); break; } break; case 2: appName= _T("p4tree.exe"); startInfo.wShowWindow = SW_SHOWMAXIMIZED; ASSERT(arg9 !=NULL && lstrlen(arg9) > 0); ASSERT(arg14==NULL); numArgs = (arg10 == NULL) ? 9 : (arg12 == NULL) ? 11 : 13; break; case 3: appName= _T("P4QTree.exe"); startInfo.wShowWindow = SW_SHOWMAXIMIZED; ASSERT(arg9 !=NULL && lstrlen(arg9) > 0); ASSERT(arg14==NULL); numArgs = (arg10 == NULL) ? 9 : (arg12 == NULL) ? 11 : 13; break; } appText= LoadStringResource(IDS_APP_TREE); title.FormatMessage(IDS_TITLE_EDITOR_s, appName); // Can use the same string as the editor break; #else return FALSE; #endif case ANNOTATE_APP: #ifdef UNICODE if (MainFrame()->HaveTLV()) { if (MainFrame()->GetP4Vver() < 20051) { DWORD ver = MainFrame()->GetP4Vver(); DWORD yr = ver / 10; DWORD pt = ver - (yr*10); CString txt; txt.FormatMessage(IDS_P4VTOOOLD, yr, pt, _T("2005.1")); AfxMessageBox(txt, MB_ICONEXCLAMATION); return FALSE; } appName= _T("p4v.exe"); startInfo.wShowWindow = SW_SHOWNORMAL; ASSERT(arg10 !=NULL && lstrlen(arg10) > 0); ASSERT(arg15==NULL); numArgs = (arg11 == NULL) ? 10 : (arg13 == NULL) ? 12 : 14; switch(numArgs) { case 10: if (WideCharToMultiByte(CP_UTF8, 0, arg10, -1, (LPSTR)buf2, sizeof(buf2), NULL, NULL) && MultiByteToWideChar(1252, 0, (LPSTR)buf2, -1, buf1, sizeof(buf1))) arg10 = buf1; break; case 12: if (WideCharToMultiByte(CP_UTF8, 0, arg12, -1, (LPSTR)buf2, sizeof(buf2), NULL, NULL) && MultiByteToWideChar(1252, 0, (LPSTR)buf2, -1, buf1, sizeof(buf1))) arg12 = buf1; break; case 14: if (WideCharToMultiByte(CP_UTF8, 0, arg14, -1, (LPSTR)buf2, sizeof(buf2), NULL, NULL) && MultiByteToWideChar(1252, 0, (LPSTR)buf2, -1, buf1, sizeof(buf1))) arg14 = buf1; break; default: ASSERT(0); break; } } startInfo.wShowWindow = SW_SHOWNORMAL; appText= LoadStringResource(IDS_APP_TREE); title.FormatMessage(IDS_TITLE_EDITOR_s, appName); // Can use the same string as the editor break; #else return FALSE; #endif case MERGE_APP: { orgArgX = arg3; orgArgY = arg5; ASSERT(arg1!=NULL && lstrlen(arg1) > 0); ASSERT(arg2!=NULL && lstrlen(arg2) > 0); ASSERT(arg3!=NULL && lstrlen(arg3) > 0); ASSERT(arg4!=NULL && lstrlen(arg4) > 0); // First, get the file extension, if any, and find out if // it has an associated Merge for that extension appName.Empty(); CString extension = GetFilesExtension(arg3); if (!extension.CompareNoCase(_T("tmp"))) extension = GetFilesExtension(arg2); if (!extension.CompareNoCase(_T("tmp"))) extension = GetFilesExtension(arg1); if(!extension.IsEmpty()) appName= GET_P4REGPTR()->GetAssociatedMerge(extension); if (!appName.IsEmpty()) { numArgs=4; bInternal=0; } else { bInternal = GET_P4REGPTR()->GetMergeInternal(); switch (bInternal) { case 0: { appName= GET_P4REGPTR()->GetMergeApp(); CString appProg = appName; if ((i = appProg.ReverseFind(_T('\\'))) > -1) appProg = appProg.Right(appProg.GetLength() - i - 1); if ((appProg == _T("P4WinMrg.exe")) && (appName.Find(_T("raxis")) == -1)) bInternal = 1; else { isConsole= GET_P4REGPTR()->GetMergeAppIsConsole(); isClose = GET_P4REGPTR()->GetMergeAppIsClose(); numArgs=4; } break; } default: case 2: { if (m_P4Merge && (osVer.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)) { appName= _T("P4Merge.exe"); break; } bInternal = 1; } case 1: appName= _T("P4WinMrg.exe"); break; } } if (bInternal == 1) { BOOL bNSF = GET_P4REGPTR()->GetMergeNSF(); isConsole = isClose = FALSE; LPCTSTR svArg = arg5; arg9 = arg4; // result arg8 = arg3; // yours arg7 = arg2; // theirs arg6 = arg1; // base switch (GET_P4REGPTR()->GetMrgWhtSpFlag()) { case 1: arg5 = _T("-b"); break; case 2: arg5 = _T("-w"); break; default: arg5 = _T("-s"); break; } lstrcpy(buf4, m_bNoCRLF ? _T("-lf") : _T("-crlf")); _stprintf(buf3, _T("\"-i%d\""), GET_P4REGPTR()->GetMrgTabWidth()); if(bNSF) lstrcpy(buf2, _T("-nsf")); else { CString msg; msg.FormatMessage(IDS_WILL_REPLACE_s_IF_MERGE_ACCEPTED, arg8); // yours lstrcpy(buf2, msg); } _stprintf(buf1, _T("\"-t%s\""), svArg); arg4 = buf4; arg3 = buf3; arg2 = buf2; arg1 = buf1; numArgs=9; } else if (bInternal) { isConsole = isClose = FALSE; LPCTSTR svArg = arg5; arg17 = arg4; // result arg16 = arg3; // yours arg15 = arg2; // theirs arg14 = arg1; // base switch (GET_P4REGPTR()->GetMrgWhtSpFlag()) { case 0: arg13 = _T("-dl"); break; case 1: arg13 = _T("-db"); break; case 2: arg13 = _T("-dw"); break; case 3: arg13 = _T("-da"); break; default: arg13 = _T(" "); break; } _stprintf(buf5, _T("\"%s\""), *arg6 ? arg6 : arg14); _stprintf(buf4, _T("%d"), GET_P4REGPTR()->GetMrgTabWidth()); CString msg; msg.FormatMessage(IDS_WILL_REPLACE_s_IF_MERGE_ACCEPTED, arg16); // yours if (msg.GetAt(0) == _T('-') && msg.GetAt(1) == _T('m')) msg = msg.Mid(2); lstrcpy(buf3, msg); _stprintf(buf2, _T("\"%s\""), arg16); _stprintf(buf1, _T("\"%s\""), svArg); arg12 = m_bNoCRLF ? _T("unix") : _T("win"); arg11 = _T("-le"); arg10 = buf4; arg9 = _T("-tw"); arg8 = buf3; arg7 = _T("-nm"); arg6 = buf2; arg5 = _T("-nr"); arg4 = buf1; arg3 = _T("-nl"); arg2 = buf5; arg1 = _T("-nb"); numArgs=17; } appText= LoadStringResource(IDS_APP_MERGE); title.FormatMessage(IDS_TITLE_MERGE, appName); break; } case P4_APP: appName= _T("p4"); appText= LoadStringResource(IDS_APP_P4); title.FormatMessage(IDS_TITLE_P4, appName); ASSERT(arg1!=NULL && lstrlen(arg1) > 0); ASSERT(arg2!=NULL && lstrlen(arg2) > 0); ASSERT(arg3!=NULL && lstrlen(arg3) > 0); ASSERT(arg4!=NULL && lstrlen(arg4) > 0); ASSERT(arg5!=NULL && lstrlen(arg5) > 0); ASSERT(arg6!=NULL && lstrlen(arg6) > 0); ASSERT(arg7!=NULL && lstrlen(arg7) > 0); for (numArgs = 7; ++numArgs < 14; ) { if (numArgs == 8) { if (!arg9) break; } else if (numArgs == 9) { if (!arg10) break; } else if (numArgs == 10) { if (!arg11) break; } else if (numArgs == 11) { if (!arg12) break; } else if (numArgs == 12) { if (!arg13) break; } else if (numArgs == 13) { if (!arg14) break; } } startInfo.dwFlags = STARTF_USESHOWWINDOW; startInfo.wShowWindow = SW_SHOWNORMAL; dwCreationFlags |= CREATE_NEW_CONSOLE; break; default: ASSERT(0); return FALSE; } if(isConsole) { lstrcpy(cmdTitle, title); startInfo.lpTitle= cmdTitle; startInfo.dwXCountChars=80; startInfo.dwYCountChars=1000; startInfo.dwFlags=STARTF_USECOUNTCHARS; startInfo.cbReserved2=0; startInfo.lpReserved2=NULL; } // If we drew a blank for the appname, return the error if(appName.GetLength()==0) { errorText.FormatMessage(IDS_MISSING_APPNAME_s_s, appText, appText); return FALSE; } // Copy the arguments, and make sure args with embedded spaces have quotes // this is primitive, but it saves code in calling functions CString args[17]; args[0]=arg1; if(numArgs > 1) { args[1]=arg2; if(numArgs > 2) { args[2]=arg3; if(numArgs > 3) { args[3]=arg4; if(numArgs > 4) { args[4]=arg5; if(numArgs > 5) { args[5]=arg6; if(numArgs > 6) { args[6]=arg7; if(numArgs > 7) { args[7]=arg8; if(numArgs > 8) { args[8]=arg9; if(numArgs > 9) { args[9]=arg10; if(numArgs > 10) { args[10]=arg11; if(numArgs > 11) { args[11]=arg12; if(numArgs > 12) { args[12]=arg13; if(numArgs > 13) { args[13]=arg14; if(numArgs > 14) { args[14]=arg15; if(numArgs > 15) { args[15]=arg16; if(numArgs > 16) { args[16]=arg17; } } } } } } } } } } } } } } } } for(i=0; i= 20052) { CString charset; if (isUnicode == 16) charset = _T("utf16"); else charset = GET_P4REGPTR()->GetP4Charset(); if (charset.GetLength() > 0) appName += _T(" -C ") + charset + _T(" "); } BOOL success; TCHAR commandLine[1024]; CString tempFile; // Set up the command line CString commLine=appName; i = 0; if (app == DIFF_APP) { if (!GET_P4REGPTR()->GetDiffInternal() && GET_P4REGPTR()->GetDiffAppOptArgChk() && *(GET_P4REGPTR()->GetDiffOptArgs())) { CString optArgs = GET_P4REGPTR()->GetDiffOptArgs(); optArgs.Replace(_T("%1"), _T("%#1")); optArgs.Replace(_T("%2"), _T("%#2")); optArgs.Replace(_T("%L"), _T("%#L")); optArgs.Replace(_T("%R"), _T("%#R")); commLine += CString(_T(" ")) + optArgs; i = commLine.Replace(_T("%#1"), args[0]); i *= commLine.Replace(_T("%#2"), args[1]); commLine.Replace(_T("%#L"), orgArgX); commLine.Replace(_T("%#R"), orgArgY); _stprintf(buf2, _T("%d"), GET_P4REGPTR()->GetTabWidth()); commLine.Replace(_T("%W"), buf2); } } else if (app == MERGE_APP) { if (!GET_P4REGPTR()->GetMergeInternal() && GET_P4REGPTR()->GetMergeAppOptArgChk() && *(GET_P4REGPTR()->GetMergeOptArgs())) { CString optArgs = GET_P4REGPTR()->GetMergeOptArgs(); commLine += CString(_T(" ")) + optArgs; optArgs.Replace(_T("%1"), _T("%#1")); optArgs.Replace(_T("%2"), _T("%#2")); optArgs.Replace(_T("%3"), _T("%#3")); optArgs.Replace(_T("%4"), _T("%#4")); optArgs.Replace(_T("%T"), _T("%#T")); optArgs.Replace(_T("%Y"), _T("%#Y")); i = commLine.Replace(_T("%1"), args[0]); i *= commLine.Replace(_T("%2"), args[1]); i *= commLine.Replace(_T("%3"), args[2]); i *= commLine.Replace(_T("%4"), args[3]); orgArgY.TrimLeft(); commLine.Replace(_T("%T"), orgArgY); commLine.Replace(_T("%Y"), orgArgX); _stprintf(buf2, _T("%d"), GET_P4REGPTR()->GetMrgTabWidth()); commLine.Replace(_T("%W"), buf2); } } if (!i) { for(i=0; iGetWindowText(oldtext); AfxGetMainWnd()->SetWindowText(newtext); // Disable the main window and any topmost dialog // BOOL bReEnableMain = app == MERGE_APP; if (AfxGetMainWnd()->IsWindowEnabled()) { EnableWindow( AfxGetMainWnd()->GetSafeHwnd(), FALSE ); bReEnableMain = TRUE; } BOOL bReEnable = FALSE; // if we weren't given a topmost dialog, see if we can figure it out if (!hWnd) { CWnd *pWnd= AfxGetMainWnd()->GetForegroundWindow(); // get the foreground window if (pWnd->GetWindow(GW_OWNER) == AfxGetMainWnd()) // make sure it's ours! hWnd = pWnd->GetSafeHwnd(); } if (hWnd) { EnableWindow( hWnd, FALSE ); bReEnable = TRUE; } ::ShowWindow(MainFrame()->m_hWnd, SW_SHOWMINNOACTIVE); // Wait for the spawned app // while (WaitForSingleObject( procInfo.hProcess, 1000 ) == WAIT_TIMEOUT) { MSG msg; while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { if ( msg.message == WM_COMMAND ) // ignore all commands continue; if ( msg.message == WM_TIMER ) // Don't poll while waiting MainFrame()->WaitAWhileToPoll( ); TranslateMessage(&msg); DispatchMessage(&msg); if ( msg.message == WM_QUIT ) // get out if app is terminating break; } } CloseHandle(procInfo.hProcess); // Re-enable the windows // if (bReEnable) ::ShowWindow(hWnd, SW_RESTORE); if (bReEnableMain) { ::EnableWindow( AfxGetMainWnd()->GetSafeHwnd(), TRUE ); ::SetForegroundWindow( AfxGetMainWnd()->GetSafeHwnd() ); ::SetFocus( AfxGetMainWnd()->GetSafeHwnd() ); } if (bReEnable) { ::EnableWindow( hWnd, TRUE ); ::SetForegroundWindow( hWnd ); ::SetFocus( hWnd ); } AfxGetMainWnd()->SetWindowText(oldtext); ::ShowWindow(MainFrame()->m_hWnd, SW_RESTORE); ::SendMessage(MainFrame()->m_hWnd, m_WM_ACTIVATE, 0, 0); } else if (mode == RA_THREAD || mode == RA_THREADWAIT) { // Give the spawned program time to get initalized WaitForInputIdle(procInfo.hProcess, 1000); Sleep(1000); // And since WaitForInputIdle() is not reliable, wait some more // Now fire up the thread which will delete the temp file(s); // this thread does WaitForSingleObject(procInfo.hProcess, INFINITE) // before deleting any files. It also calls CloseHandle(procInfo.hProcess) lprati->hProcess = procInfo.hProcess; CWinThread *pTaskThread=AfxBeginThread(lprati->pfnThreadProc, (LPVOID) lprati, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL); pTaskThread->m_bAutoDelete=TRUE; // Tinker w/ priority here if reqd pTaskThread->ResumeThread(); // If the mode is RA_THREADWAIT, wait until the spawned process exits if (mode == RA_THREADWAIT) { Sleep(333); ShowWindow(m_pMainWnd->m_hWnd, SW_HIDE); WaitForSingleObject( procInfo.hProcess, INFINITE ); // Window is NOT re-shown because RA_THREADWAIT is only used // when P4Win is run with the -D [filename] flag. // P4Win will now exit since the Diff program has exited. } } else CloseHandle(procInfo.hProcess); // procInfo.hProcess was close by each of the 3 cases above, // but we still must close procInfo.hThread. CloseHandle(procInfo.hThread); // Note: checking exit codes is futile. // CMD and COMMAND return random numbers, no matter what happens } else { CString errTxt; DWORD error=GetLastError(); if(error) { LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL ); errTxt = (TCHAR *)lpMsgBuf; errTxt.TrimRight(); } else errTxt=LoadStringResource(IDS_UNKNOWN_ERROR); errorText.FormatMessage(IDS_FAILED_TO_EXECUTE_s_s_s_n, appText, appName, errTxt, error); if (commLine.GetLength() > 127) { // Find out if we're running NT or win95 OSVERSIONINFO osVer; osVer.dwOSVersionInfoSize= sizeof(OSVERSIONINFO); GetVersionEx(&osVer); BOOL brittleWare= (osVer.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); if(brittleWare) errTxt.FormatMessage(IDS_s_COMMAND_LINE_TOO_LONG_FOR_WIN9X_s_n, appText, commLine, commLine.GetLength()); else errTxt.FormatMessage(IDS_CHECK_PERFORCE_OPTIONS_s, appText); } else errTxt.FormatMessage(IDS_CHECK_PERFORCE_OPTIONS_s, appText); errorText += errTxt; } // restore previous system setting (see comment above, // at 1st call to SystemParametersInfo(), for details) if (dwLockTimeout && (mode == RA_WAIT)) SystemParametersInfo(0x2001 /*==SPI_SETFOREGROUNDLOCKTIMEOUT*/, 0, (LPVOID)dwLockTimeout, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE); if(isConsole && !tempFile.IsEmpty()) _tunlink(tempFile); return success; } // Spawn a viewer. App is referenced by name, and console apps will not be catered to. // This is a stripped down version of CP4WinApp::RunApp() BOOL CP4winApp::RunViewerApp(LPCTSTR app, LPCTSTR fileName) { if( app==NULL || lstrlen(app) == 0 || fileName==NULL || lstrlen(fileName) == 0) { // Dont ASSERT(0); since this error occurrs for any binary file w/ no associated app return FALSE; } // Set up the spawn operation PROCESS_INFORMATION procInfo; STARTUPINFO startInfo; GetStartupInfo(&startInfo); startInfo.lpReserved= startInfo.lpDesktop= NULL; startInfo.dwFlags |= STARTF_USESHOWWINDOW; startInfo.wShowWindow = SW_SHOWNORMAL; CString arg=fileName; arg.TrimRight(); arg.TrimLeft(); if(arg.Find(_T(' ')) != -1 && arg[0] != _T('\"')) { TCHAR buf[1024]; lstrcpy(buf, arg); arg.Format(_T("\"%s\""), buf); } CString appName=app; appName.TrimRight(); appName.TrimLeft(); if(appName.Find(_T(' ')) != -1 && appName[0] != _T('\"')) { TCHAR buf[1024]; lstrcpy(buf, appName); appName.Format(_T("\"%s\""), buf); } // Set up the command line CString commLine=appName; commLine+=_T(" ")+arg; BOOL success=CreateProcess( NULL, // pointer to name of executable module const_cast((LPCTSTR)commLine), // pointer to command line string NULL, NULL, // default security rot FALSE, // handle inheritance flag #ifdef UNICODE NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT, #else NORMAL_PRIORITY_CLASS, // creation flags #endif NULL, NULL, //default env and curdir &startInfo, &procInfo); if(success) { // Note: checking exit codes is futile. CMD and COMMAND return random numbers, no // matter what happens CloseHandle(procInfo.hProcess); CloseHandle(procInfo.hThread); } return success; } ///////////////////////////////////////////////////////////////////////////////// // Minor text formatting functions used throughout app, so multiline edit boxes // can translate text with embedded tabs, as generated by command line clients // Utility function to remove tabs and replace all LF's with CR-LFs CString RemoveTabs(LPCTSTR text) { SET_BUSYCURSOR(); CString out=text; // avoid billions of re-allocs by setting approx length out+=text; // then double the length of the buffer out=""; // and empty the buffer without freeing it int i=0; while(text[i] != _T('\0')) { if(text[i]!=_T('\t')) { if(text[i]==_T('\n') && text[max(0,i-1)]!=_T('\r')) out += _T("\r\n"); else out += text[i]; } i++; } // Strip off a trailing newline char if(out.GetLength() > 0 && out[out.GetLength()-1] == _T('\n')) out=out.Left(out.GetLength()-2); return out; } CString MakeCRs(LPCTSTR text) { // replace LF with CR-LF // then strip any trailing CR-LFs int size = lstrlen(text) + 1; CString out; LPTSTR pOutBuf = out.GetBufferSetLength(size); LPTSTR pOut = pOutBuf; // keep track of where any trailing CRs are located so they can be chopped // without repeatedly scanning the string (which may be very long) // this pointer points to the char following the last non-CR character LPTSTR pLastNonCR = pOut; // there will be probably be a final realloc, and this is probably a temp // string anyway, so minimize the number of reallocs rather than the size const int growBy = 4096; #ifdef UNICODE for(LPCTSTR pIn = text; *pIn != _T('\0'); pIn++) #else for(LPCTSTR pIn = text; *pIn != _T('\0'); pIn = CharNext(pIn)) #endif { // make sure there will be enough room for a character // even if it is a double byte char, or an expanded CR if(pOut - pOutBuf + 2 > size - 1) { int oldSize = pOut - pOutBuf; int nLastNonCR = pLastNonCR - pOutBuf; out.ReleaseBuffer(oldSize); size += growBy; pOutBuf = out.GetBufferSetLength(size); pOut = pOutBuf + oldSize; pLastNonCR = pOutBuf + nLastNonCR; } if(*pIn==_T('\r')) { *pOut++ = *pIn; if(pIn[1] == _T('\n')) *pOut++ = *++pIn; else pLastNonCR = pOut; } else if(*pIn==_T('\n')) { // a LF with no preceding CR, so insert a CR *pOut++ = _T('\r'); *pOut++ = _T('\n'); } else { #ifdef UNICODE *pOut++ = *pIn; #else _tccpy(pOut, pIn); pOut = CharNext(pOut); #endif pLastNonCR = pOut; } } // chop off any trailing newline chars *pLastNonCR = 0; out.ReleaseBuffer(); return out; } CString MakeLFs(LPCTSTR text) { // replace CR with CR-LF // then strip any trailing CR-LFs int size = lstrlen(text) + 1; CString out; LPTSTR pOutBuf = out.GetBufferSetLength(size); LPTSTR pOut = pOutBuf; // keep track of where any trailing CRs are located so they can be chopped // without repeatedly scanning the string (which may be very long) // this pointer points to the char following the last non-CR character LPTSTR pLastNonCR = pOut; // there will be probably be a final realloc, and this is probably a temp // string anyway, so minimize the number of reallocs rather than the size const int growBy = 4096; #ifdef UNICODE for(LPCTSTR pIn = text; *pIn != _T('\0'); pIn++) #else for(LPCTSTR pIn = text; *pIn != _T('\0'); pIn = CharNext(pIn)) #endif { // make sure there will be enough room for a character // even if it is a double byte char, or an expanded CR if(pOut - pOutBuf + 2 > size - 1) { int oldSize = pOut - pOutBuf; int nLastNonCR = pLastNonCR - pOutBuf; out.ReleaseBuffer(oldSize); size += growBy; pOutBuf = out.GetBufferSetLength(size); pOut = pOutBuf + oldSize; pLastNonCR = pOutBuf + nLastNonCR; } if(*pIn==_T('\r')) { *pOut++ = _T('\r'); *pOut++ = _T('\n'); } else { #ifdef UNICODE *pOut++ = *pIn; #else _tccpy(pOut, pIn); pOut = CharNext(pOut); #endif pLastNonCR = pOut; } } // chop off any trailing newline chars *pLastNonCR = 0; out.ReleaseBuffer(); return out; } CString UnMakeCRs(LPCTSTR text) { // remove any CR characters // then strip any trailing LFs int size = lstrlen(text) + 1; CString out; LPTSTR pOut = out.GetBufferSetLength(size); // keep track of where any trailing LFs are located so they can be chopped // without repeatedly scanning the string (which may be very long) // this pointer points to the char following the last non-LF character LPTSTR pLastNonLF = pOut; #ifdef UNICODE for(LPCTSTR pIn = text; *pIn != _T('\0'); pIn++) #else for(LPCTSTR pIn = text; *pIn != _T('\0'); pIn = CharNext(pIn)) #endif { if(*pIn != _T('\r')) { if(*pIn == _T('\n')) *pOut++ = *pIn; else { #ifdef UNICODE *pOut++ = *pIn; #else _tccpy(pOut, pIn); pOut = CharNext(pOut); #endif pLastNonLF = pOut; } } } // chop off any trailing newline chars *pLastNonLF = 0; out.ReleaseBuffer(); return out; } CString PadCRs(LPCTSTR text) { CString out; // Replace CR and TABs with spaces. This allows multi-line descriptions // to be displayed on a single line int len=lstrlen(text); LPCTSTR ptr=text; LPTSTR ptrout=out.GetBuffer(len); LPTSTR ptrstart = ptrout; for(int i=0; i ptrstart) && (*(ptrout-1) != _T(' '))) *ptrout++ = _T(' '); ptr++; } else { *ptrout++ = *ptr++; } } *ptrout=_T('\0'); out.ReleaseBuffer(); return out; } CString WrapDesc(LPCTSTR text, int maxcol) { int count = 0; int size = lstrlen(text) + 1; CString out; CString savestr; LPTSTR pOut = out.GetBufferSetLength(size*2); LPTSTR pLastWhite = pOut; LPTSTR pLWnext = pOut; LPTSTR pBgnLine = pOut; LPTSTR p; for(LPCTSTR pIn = text; *pIn != _T('\0'); ) { if ((*pIn == _T('\r')) || (*pIn == _T('\n'))) { count = 0; pLastWhite = pBgnLine = pOut; } if (*pIn <= _T(' ')) pLWnext = pOut; #ifdef UNICODE *pOut++ = *pIn++; #else _tccpy(pOut, pIn); pOut = CharNext(pOut); pIn = CharNext(pIn); #endif if ((++count > maxcol) && (pLastWhite != pBgnLine) && (*pIn != _T('\r')) && (*pIn != _T('\n'))) { *pOut = _T('\0'); #ifdef UNICODE pLastWhite++; #else pLastWhite = CharNext(pLastWhite); #endif savestr = pLastWhite; *pLastWhite++ = _T('\r'); *pLastWhite++ = _T('\n'); lstrcpy(pLastWhite, savestr); pOut = pLastWhite + lstrlen(pLastWhite); pLWnext = pBgnLine = pLastWhite; for (count = 0, p = pBgnLine; p < pOut; ) { #ifdef UNICODE p++; #else p = CharNext(p); #endif if ((*p == _T('\r')) || (*p == _T('\n'))) { count = 0; pBgnLine = p; } else count++; if (*p <= _T(' ') && *p) pLWnext = p; } } pLastWhite = pLWnext; } *pOut = _T('\0'); out.ReleaseBuffer(); return out; } ///////////////////////////////////////////////// // Utility functions to perform string comparisons according // to the case-sensitivity of the server int Compare(LPCTSTR str1, LPCTSTR str2) { // If server level not set, we also dont know if server is nocase ASSERT(GET_SERVERLEVEL()); if(IS_NOCASE()) return _tcsicmp(str1, str2); else return _tcscmp(str1, str2); } int nCompare(LPCTSTR str1, LPCTSTR str2, int n) { // If server level not set, we also dont know if server is nocase ASSERT(GET_SERVERLEVEL()); if(IS_NOCASE()) return _tcsnicmp(str1, str2, n); else return _tcsncmp(str1, str2, n); } int nCommon(LPCTSTR str1, LPCTSTR str2) { // If server level not set, we also dont know if server is nocase ASSERT(GET_SERVERLEVEL()); int commonLength=0; LPCTSTR ptr1= str1; LPCTSTR ptr2= str2; if(IS_NOCASE()) while( (TBYTE)CharUpper((LPTSTR)(TBYTE)*ptr1) == (TBYTE)CharUpper((LPTSTR)(TBYTE)*ptr2) && *ptr1 != _T('\0') && *ptr2 != _T('\0')) { commonLength++; ptr1++; ptr2++; } else while( *ptr1 == *ptr2 && *ptr1 != _T('\0') && *ptr2 != _T('\0')) { commonLength++; ptr1++; ptr2++; } return commonLength; } void TrimRightMBCS(CString &str, TCHAR *chars) { #ifdef UNICODE str.TrimRight(chars); #else int len; LPTSTR pBuf = str.GetBuffer(len = str.GetLength()); TCHAR *pchBgn = (TCHAR *)pBuf; TCHAR *pchLst = _tcsdec(pchBgn, pchBgn + len); BOOL b = TRUE; while (b) { b = FALSE; for (TCHAR *pchChk = chars; *pchChk; pchChk = _tcsinc(pchChk)) { if (*pchChk == *pchLst) { *pchLst = _T('\0'); pchLst = _tcsdec(pchBgn, pchLst); b = TRUE; break; } } } str.ReleaseBuffer(-1); #endif } // This functions assumes that oldchar and newchar are the same width! // Since this is used to replace \ with /, this works fine. void ReplaceMBCS(CString &str, TCHAR oldchar, TCHAR newchar) { #ifdef UNICODE str.Replace(oldchar, newchar); #else #ifdef _DEBUG TCHAR oldbuf[8]; TCHAR newbuf[8]; memset(oldbuf, _T('\0'), sizeof(oldbuf)); memset(newbuf, _T('\0'), sizeof(newbuf)); oldbuf[0] = oldchar; newbuf[0] = newchar; ASSERT(lstrlen(oldbuf) == lstrlen(newbuf)); #endif LPTSTR pBuf = str.GetBuffer(str.GetLength()); for (TCHAR *pch = (TCHAR *)pBuf; *pch; pch = _tcsinc(pch)) { if (*pch == oldchar) *pch = newchar; } str.ReleaseBuffer(-1); #endif } int FindMBCS(CString &str, TCHAR findchar, int skip /*=0*/) { #ifdef UNICODE return str.Find(findchar, skip); #else ASSERT(skip >= 0); int i; LPTSTR pBuf = str.GetBuffer(str.GetLength()); TCHAR *pchBgn = (TCHAR *)pBuf; TCHAR *pch; for (i=-1, pch=pchBgn; *pch; pch = _tcsinc(pch)) { if (skip) { skip--; } else if (*pch == findchar) { i = pch - pchBgn; break; } } str.ReleaseBuffer(-1); return i; #endif } int ReverseFindMBCS(CString &str, TCHAR findchar) { #ifdef UNICODE return str.ReverseFind(findchar); #else int len; LPTSTR pBuf = str.GetBuffer(len = str.GetLength()); TCHAR *pchBgn = (TCHAR *)pBuf; TCHAR *pchLst = _tcsdec(pchBgn, pchBgn + len); while (pchBgn < pchLst) { if (*pchLst == findchar) break; pchLst = _tcsdec(pchBgn, pchLst); } if (pchBgn < pchLst) len = pchLst - pchBgn; else len = *pchBgn == findchar ? 0 : -1; str.ReleaseBuffer(-1); return len; #endif } // Function to get a file's extension CString GetFilesExtension(LPCTSTR filename) { CString extension = filename; int slash= extension.ReverseFind(_T('\\')); if(slash != -1) extension=extension.Mid(slash+1); int dot= extension.ReverseFind(_T('.')); if(dot == -1) extension.Empty(); else extension=extension.Mid(dot+1); return extension; } // Function to compare 2 path&filenames in MS // TreeView order - which is definitely weird // (see comment below). This means x.ext comes // before x-y.ext even tho - comes before . int fCompare(LPCTSTR str1, LPCTSTR str2, BOOL ext1st/*=FALSE*/) { CString bas1 = str1; CString bas2 = str2; // Since we do our own sorting when we are in "sort by extension" // we don't have to do stupid win32 stuff if (ext1st) { int rc; CString ext1 = GetFilesExtension(str1); CString ext2 = GetFilesExtension(str2); if ((rc = ext1.CompareNoCase(ext2)) == 0) rc = bas1.CompareNoCase(bas2); return rc; } // In general, the Win32 sort order is this: // Non-alpha-numeric (punctuation) characters in ASCII or ANSI order // Numeric characters in numeric order // Alphabetic characters in case-insensitive alphabetic order // For Win32 it is the same, with two exceptions: // the hyphen or minus (-) symbol and the single-quote or apostrophe ( ' ). // These two characters are ignored when sorting strings because they are // allowed to be embedded in English-language words. For example, "its" and // "it's" and "co-op" and "coop." The presence of these characters embedded // in words causes certain searches to break incorrectly, so they are changed // to be treated just like other diacritical marks embedded in text strings; // that is, they're ignored. These rather remarkable words are from // ms-help://MS.VSCC/MS.MSDNVS/dnaskdr/html/drgui49.htm and // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaskdr/html/drgui49.asp bas1.Remove(_T('\'')); bas1.Remove(_T('-')); bas2.Remove(_T('\'')); bas2.Remove(_T('-')); return bas1.CompareNoCase(bas2); } /**********************************************************************/ void CopyTextToClipboard(LPCTSTR txt) { if( lstrlen(txt) > 0 ) { COleDataSource *pSource= new COleDataSource(); HGLOBAL hText= ::GlobalAlloc(GMEM_SHARE, (lstrlen(txt)+1)*sizeof(TCHAR)); LPTSTR pStr= (LPTSTR) ::GlobalLock( hText ); lstrcpy( pStr, txt ); ::GlobalUnlock( hText ); #ifdef UNICODE pSource->CacheGlobalData( CF_UNICODETEXT, hText ); #else pSource->CacheGlobalData( CF_TEXT, hText ); #endif pSource->SetClipboard(); } } /**********************************************************************/ void CP4winApp::OnUpdateNewWindow(CCmdUI* pCmdUI) { pCmdUI->Enable(MainFrame()->IsModlessUp() ? FALSE : !SERVER_BUSY()); } void CP4winApp::OnNewWindow() { if (MainFrame()->IsModlessUp()) return; CNewWindowDlg newWindowDlg; newWindowDlg.DoModal(); } void CP4winApp::GetFileType(const CString &itemStr, int &BaseType, int &StoreType, BOOL &TypeK, BOOL &TypeW, BOOL &TypeX, BOOL &TypeO, BOOL &TypeM, BOOL &TypeL, BOOL &TypeS, int &NbrRevs, BOOL &Unknown) { TypeS = FALSE; // shortcut for file not in depot if(itemStr.Find(_T(" <")) == -1) { BaseType = -1; StoreType = -1; Unknown = FALSE; return; } int plus; TCHAR c; if (itemStr.Find(_T(" ')) && c) { switch (c) { case _T('x'): TypeX = TRUE; break; case _T('w'): TypeW = TRUE; break; case _T('k'): TypeK = TRUE; break; case _T('o'): TypeO = TRUE; TypeK = TRUE; break; case _T('m'): TypeM = TRUE; break; case _T('l'): TypeL = TRUE; break; case _T('C'): StoreType = 1; break; case _T('D'): StoreType = 2; break; case _T('F'): StoreType = 3; break; case _T('S'): TypeS = TRUE; if (_istdigit(itemStr.GetAt(plus+1))) { CString str = itemStr.Mid(plus+1); NbrRevs = (int)_tstof(str); if (NbrRevs < 1) NbrRevs = 1; while (_istdigit(itemStr.GetAt(++plus))) ; plus--; } else NbrRevs = 1; break; default: Unknown = TRUE; break; } } } else if (itemStr.Find(_T(" ")) != -1) { BaseType = 0; TypeX = TRUE; } else if (itemStr.Find(_T(" ")) != -1) { BaseType = 0; TypeK = TRUE; } else if (itemStr.Find(_T(" ")) != -1) { BaseType = 0; TypeX = TRUE; TypeK = TRUE; } else if (itemStr.Find(_T(" ")) != -1) { BaseType = 1; TypeX = TRUE; } else if (itemStr.Find(_T(" ")) != -1) { BaseType = 0; StoreType = 1; } else if (itemStr.Find(_T(" ")) != -1) { BaseType = 0; StoreType = 2; TypeX = TRUE; } else if (itemStr.Find(_T(" ")) != -1) { BaseType = 0; StoreType = 3; } else if (itemStr.Find(_T(" ")) != -1) { BaseType = 0; TypeS = TypeX = TRUE; } else if (itemStr.Find(_T(" ")) != -1) { BaseType = 1; StoreType = 3; } else if (itemStr.Find(_T(" ")) != -1) { BaseType = 1; TypeS = TypeW = TRUE; } else if ((itemStr.Find(_T(" ")) != -1) || (itemStr.Find(_T(" ")) != -1)) { BaseType = 1; TypeS = TypeW = TypeX = TRUE; } else if (itemStr.Find(_T(" ")) != -1) { BaseType = 5; TypeX = TRUE; } } /* _________________________________________________________________ */ LPCTSTR CP4winApp::GetClientSpecField( LPCTSTR fieldname, LPCTSTR spectext ) { static CString field; int start, end; field.Empty(); CString spec= spectext; int lgth = spec.GetLength(); for( start=end=0; spec[end] && end < lgth; end++) { if( spec[end] == _T('\n') ) { CString line= spec.Mid( start, end-start+1 ); start= end+1; if( line.Find(fieldname) == 0 ) { int i; if ((i = line.Find(_T('\t'))) != -1) { field = line.Mid( line.Find(_T('\t')) + 1 ); } else if ((i = spec.Find(_T("\n\n"), start)) != -1) { field = spec.Mid(start, i-start); field.TrimLeft(); } field.TrimRight(); break; } } } return field; } void AddToStatus(LPCTSTR txt, StatusView level, bool showDialog) { if(AfxGetThread() == (CWinThread*) AfxGetApp()) MainFrame()->AddToStatusLog(txt, level, showDialog); else TheApp()->StatusAdd(txt, level, showDialog); } BOOL CP4winApp::OnIdle(LONG lCount) { // if lCount is 0, this is the first call since going idle // therefore set a new idle flag so that the toolbar button // activate-or-not functions will process the selection list again // // We use += 2 to keep m_IdleCounter odd so that it will never // roll over and become 0 - which is our flag to indicate that // we are Not in the idle loop. // if (!lCount) m_IdleCounter += 2; m_IdleFlag = m_IdleCounter; BOOL rc = CP4GuiApp::OnIdle(lCount); m_IdleFlag = 0; return rc; } BOOL CP4winApp::CallP4RevisionTree(CString filepath) { CString errorText; CString client = GET_P4REGPTR()->GetP4Client(); CString port = GET_P4REGPTR()->GetP4Port(); CString user = GET_P4REGPTR()->GetP4User(); CString password= GET_P4REGPTR()->GetP4UserPassword(); CString charset = GET_P4REGPTR()->GetP4Charset(); CString winhandle; winhandle.Format(_T("%d"), MainFrame()->m_hWnd); CString cmd; cmd.Format(_T("\"tree %s\""), filepath); int i = 0; LPCTSTR argptr[10]; if (password.GetLength() > 0) { argptr[i++] = _T("-P"); argptr[i++] = password; } if (charset.GetLength() > 0) { argptr[i++] = _T("-C"); argptr[i++] = charset; } if(MainFrame()->HaveP4QTree()) { argptr[i++] = _T("-win"); argptr[i++] = winhandle; argptr[i++] = _T("-cmd"); argptr[i++] = cmd; } else { argptr[i++] = _T("-j"); argptr[i++] = filepath; } while (i < 10) argptr[i++] = NULL; if (!TheApp()->RunApp(TREE_APP, RA_NOWAIT, AfxGetApp( )->m_pMainWnd->m_hWnd, FALSE, NULL, errorText, _T("-p"), port, _T("-c"), client, _T("-u"), user, argptr[0], argptr[1], argptr[2], argptr[3], argptr[4], argptr[5], argptr[6], argptr[7], argptr[8])) { AddToStatus( LoadStringResource(IDS_UNABLETORUNREVTREE), SV_WARNING ); return FALSE; } return TRUE; } BOOL CP4winApp::CallP4A(CString annpath, CString logpath, int revnbr) { CString errorText; CString rev; CString client = GET_P4REGPTR()->GetP4Client(); CString port = GET_P4REGPTR()->GetP4Port(); CString user = GET_P4REGPTR()->GetP4User(); CString password= GET_P4REGPTR()->GetP4UserPassword(); CString charset = GET_P4REGPTR()->GetP4Charset(); CString winhandle; winhandle.Format(_T("%d"), MainFrame()->m_hWnd); int i = 0; LPCTSTR argptr[10]; if (password.GetLength() > 0) { argptr[i++] = _T("-P"); argptr[i++] = password; } if (charset.GetLength() > 0) { argptr[i++] = _T("-C"); argptr[i++] = charset; } if (MainFrame()->HaveTLV()) { argptr[i++] = _T("-win"); argptr[i++] = winhandle; argptr[i++] = _T("-cmd"); CString cmd; cmd.Format(_T("\"%s %s\""), (GET_P4REGPTR()->GetTLVIncInteg() && MainFrame()->GetP4Vver() >= 20052) ? _T("annotate -i") : _T("annotate"), annpath); // command passed to V argptr[i++] = cmd; while (i < 10) argptr[i++] = NULL; if (!TheApp()->RunApp(ANNOTATE_APP, RA_NOWAIT, AfxGetApp( )->m_pMainWnd->m_hWnd, FALSE, NULL, errorText, _T("-p"), port, _T("-c"), client, _T("-u"), user, argptr[0], argptr[1], argptr[2], argptr[3], argptr[4], argptr[5], argptr[6], argptr[7], argptr[8])) { AddToStatus( LoadStringResource(IDS_UNABLETORUNP4A), SV_WARNING ); return FALSE; } } return TRUE; } // Since client roots are entered by the user, // they can appear in all sorts of weird shapes and forms. // So always use this routune to set m_ClientRoot // and clean up any messes afterwards. BOOL CP4winApp::Set_m_ClientRoot(LPCTSTR clientroot) { m_ClientRoot = clientroot; // handle client with multiple roots // by running p4 info to get the real root int i; if ((i = m_ClientRoot.FindOneOf(_T("\r\n\t"))) != -1) { BOOL b = FALSE; CCmd_Info cmd; cmd.Init( NULL, RUN_SYNC ); if( cmd.Run( ) && !cmd.GetError() ) { CP4Info const &info = cmd.GetInfo(); if (!info.m_ClientRoot.IsEmpty( )) { m_ClientRoot = info.m_ClientRoot; b = TRUE; } } if (!b) m_ClientRoot = m_ClientRoot.Left(i); } m_ClientRoot.Replace(_T('/'), _T('\\')); m_ClientRoot.TrimLeft(_T('\"')); m_ClientRoot.TrimRight(_T("\"\\")); switch(m_ClientRoot.GetLength()) { case 0: m_ClientRoot = _T("\\"); break; case 1: ASSERT(0); return FALSE; case 2: if (m_ClientRoot.GetAt(1) == _T(':')) m_ClientRoot += _T('\\'); break; } return TRUE; } BOOL CP4winApp::Set_m_ClientSubOpts(LPCTSTR clientSubOpts) { m_ClientSubOpts = 0; if (clientSubOpts) { if (_tcsstr(clientSubOpts, _T("revert"))) m_ClientSubOpts = REVERTUNCHANGED; else if (_tcsstr(clientSubOpts, _T("leave"))) m_ClientSubOpts = LEAVEUNCHANGED; else if (_tcsstr(clientSubOpts, _T("submit"))) m_ClientSubOpts = SUBMITUNCHANGED; if (m_ClientSubOpts && _tcsstr(clientSubOpts, _T("reopen"))) m_ClientSubOpts += REOPEN_MASK; } return m_ClientSubOpts > 0; } BOOL CP4winApp::digestIsSame(CP4FileStats *fs, BOOL retIfNotExist/*=FALSE*/, void *clientPtr/*=NULL*/) { if (fs->GetDigest().IsEmpty()) // prior to 2005.1, we don't have the digest; return TRUE; // so revert to old behavior Error e; CP4Command *pcmd = NULL; CGuiClient *client = (CGuiClient *)clientPtr; if (!client) { pcmd = new CP4Command; client = pcmd->GetClient(); client->SetTrans(); client->Init(&e); if( e.Test() ) { delete pcmd; return FALSE; } } FileSysType ft; if (fs->IsTextFile()) ft = (fs->GetHeadType().Find(_T("unicode")) != -1) ? FST_UNICODE : (fs->GetHeadType().Find(_T("utf16")) != -1) ? FST_UTF16 : FST_TEXT; else if (fs->GetHeadType().Find(_T("apple")) != -1) ft = FST_APPLETEXT; else if (fs->GetHeadType().Find(_T("resource")) != -1) ft = FST_RESOURCE; else if (fs->GetHeadType().Find(_T("symlink")) != -1) ft = FST_SYMLINK; else ft = FST_BINARY; FileSys *f = FileSys::Create( ft ); if( e.Test() ) { if (pcmd) delete pcmd; return FALSE; } StrBuf clientPath; clientPath << CharFromCString(fs->GetFullClientPath()); f->Set(clientPath); StrBuf md5; f->Digest(&md5, &e); delete f; if (pcmd) delete pcmd; if( e.Test() ) return retIfNotExist; return CharToCString(md5.Value()) == fs->GetDigest(); } BOOL CP4winApp::localDigest(CP4FileStats *fs, CString *digest, BOOL retIfNotExist/*=FALSE*/, void *clientPtr/*=NULL*/) { Error e; CP4Command *pcmd = NULL; CGuiClient *client = (CGuiClient *)clientPtr; *digest = _T(""); if (!client) { pcmd = new CP4Command; client = pcmd->GetClient(); client->SetTrans(); client->Init(&e); if( e.Test() ) { delete pcmd; return FALSE; } } FileSysType ft; if (fs->IsTextFile()) ft = (fs->GetHeadType().Find(_T("unicode")) != -1) ? FST_UNICODE : (fs->GetHeadType().Find(_T("utf16")) != -1) ? FST_UTF16 : FST_TEXT; else if (fs->GetHeadType().Find(_T("apple")) != -1) ft = FST_APPLETEXT; else if (fs->GetHeadType().Find(_T("resource")) != -1) ft = FST_RESOURCE; else if (fs->GetHeadType().Find(_T("symlink")) != -1) ft = FST_SYMLINK; else ft = FST_BINARY; FileSys *f = FileSys::Create( ft ); if( e.Test() ) { if (pcmd) delete pcmd; return FALSE; } StrBuf clientPath; clientPath << CharFromCString(fs->GetFullClientPath()); f->Set(clientPath); StrBuf md5; f->Digest(&md5, &e); delete f; if (pcmd) delete pcmd; if( e.Test() ) return retIfNotExist; *digest = CharToCString(md5.Value()); return TRUE; } /********************************************************************/ int GetNbrNL(const CString *str) { int i = 0; int n = 0; while ((i = str->Find(_T('\n'), i)) != -1) { n++; i++; } return n; } CImageList * CP4winApp::GetImageList() { return m_viewImageList; } void CP4winApp::OnSysColorChange() { // Make sure image lists gets a new background color m_viewImageList->OnSysColorChange(::GetSysColor(COLOR_WINDOW)); m_toolBarImageList->OnSysColorChange(::GetSysColor(COLOR_3DFACE)); } // Use the shell to display a "Choose Directory" dialog box for the user. CString CP4winApp::BrowseForFolder(HWND hWnd, LPCTSTR startat, LPCTSTR lpszTitle, UINT nFlags) { startingfolder = startat; CString strResult = _T(""); LPMALLOC lpMalloc; // pointer to IMalloc if (::SHGetMalloc(&lpMalloc) != NOERROR) return strResult; // failed to get allocator TCHAR szDisplayName[_MAX_PATH]; TCHAR szBuffer[_MAX_PATH]; BROWSEINFO browseInfo; browseInfo.hwndOwner = hWnd; browseInfo.pidlRoot = NULL; // set root at Desktop browseInfo.pszDisplayName = szDisplayName; browseInfo.lpszTitle = lpszTitle; // passed in browseInfo.ulFlags = nFlags; // also passed in browseInfo.lpfn = BrowseCallbackProc; // callback func browseInfo.lParam = 0; // not used LPITEMIDLIST lpItemIDList; if ((lpItemIDList = ::SHBrowseForFolder(&browseInfo)) != NULL) { // Get the path of the selected folder from the item ID list. if (::SHGetPathFromIDList(lpItemIDList, szBuffer)) { // At this point, szBuffer contains the path the user chose. if (szBuffer[0] == '\0') { // SHGetPathFromIDList failed, or // SHBrowseForFolder failed. AfxMessageBox(IDS_FAILED_GET_DIRECTORY, MB_ICONSTOP|MB_OK); } else { // We have a path in szBuffer - Prepare to return it. strResult = szBuffer; } } else { // The thing referred to by lpItemIDList // might not have been a file system object. // For whatever reason, SHGetPathFromIDList // didn't work! AfxMessageBox(IDS_FAILED_GET_DIRECTORY, MB_ICONSTOP|MB_OK); } } // cleanup lpMalloc->Free(lpItemIDList); lpMalloc->Release(); return strResult; } INT CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) { switch(uMsg) { case BFFM_INITIALIZED: // WParam is TRUE since we are passing a path. // It would be FALSE if we were passing a pidl. SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)startingfolder.GetBuffer()); break; } return 0; } CString DemanglePath(LPCTSTR path) { // expand short filenames to long filenames StrBuf demangled; NtDemanglePath(const_cast((const char *)CharFromCString(path)), &demangled); return CharToCString(demangled.Text()); } CString FormatError(Error *e, int flags) { StrBuf buf; e->Fmt( &buf, flags ) ; return CharToCString(buf.Text()); } int FindNoCase(CString str, CString substr, int offset/*=0*/) { str.MakeLower(); substr.MakeLower(); return str.Find(substr, offset); }