// // 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 <mapi.h> #include <winver.h> #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<numArgs; i++) { args[i].TrimRight(); args[i].TrimLeft(); if(args[i].Find(_T(' ')) != -1 && args[i][0] != _T('\"')) { TCHAR buf[1024]; lstrcpy(buf, args[i]); args[i].Format(_T("\"%s\""), buf); } } appName.TrimRight(); appName.TrimLeft(); if(appName.Find(_T(' ')) != -1 && appName[0] != _T('\"')) { TCHAR buf[1024]; lstrcpy(buf, appName); appName.Format(_T("\"%s\""), buf); } // Pass the P4CHARSET to P4Merge.exe if its version is 2005.2 or later and have Unicode files CString appFileName; if ((i = appName.ReverseFind(_T('\\'))) != -1) appFileName = appName.Mid(i+1); else appFileName = appName; if (isUnicode && !appFileName.CollateNoCase(_T("P4Merge.exe")) && m_P4MergeVer >= 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; i<numArgs; i++) commLine+=_T(" ")+args[i]; } /* We have to do nasty things with the system settings to fool win/2k/xp/98 into bringing the correct window to the foreground after a spawn with wait finishes. Starting with Windows 98 & Windows 2000 the OS restricts which processes can set the foreground window. A process can set the foreground window only if certain conditions are met - none of which can be met after a spawn with wait finishes. Therefore change the system setting that controls this new, useless behavior to disable it before the spawn is done; then restore the previous settings after the correct window has been brought to the foreground. Furthermore we have to use the actual value of SPI_*ETFOREGROUNDLOCKTIMEOUT rather than the defines because they are not defined on NT. */ DWORD dwLockTimeout = 0; SystemParametersInfo(0x2000 /*==SPI_GETFOREGROUNDLOCKTIMEOUT*/, NULL, &dwLockTimeout, NULL); if (dwLockTimeout && (mode == RA_WAIT)) SystemParametersInfo(0x2001 /*==SPI_SETFOREGROUNDLOCKTIMEOUT*/, 0, (LPVOID)0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE); if(isConsole) { // Win95 command shell does not have a scrollable screen buffer, // so pipe diff results to more by using a batch file if((osVer.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) && (app == DIFF_APP)) { TCHAR tempPath[LONGPATH]; HANDLE h=0; commLine+=_T(" | more"); if(GetTempPath(LONGPATH, tempPath) == 0) { errorText.FormatMessage(IDS_COULD_NOT_RUN_s_TEMP_COMMAND_PATH_ERROR, appText); if (dwLockTimeout && (mode == RA_WAIT)) SystemParametersInfo(0x2001 /*==SPI_SETFOREGROUNDLOCKTIMEOUT*/, 0, (LPVOID)dwLockTimeout, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE); return FALSE; } for(i=0; i<100; i++) { tempFile.Format(_T("%sP4W%05ld.BAT"), tempPath, i); h=CreateFile(tempFile, GENERIC_WRITE, 0, 0, CREATE_NEW, 0, 0); if(h != INVALID_HANDLE_VALUE) break; } if(i==100) { errorText.FormatMessage(IDS_COULD_NOT_RUN_s_COULD_NOT_OPEN_TEMP_COMMAND_FILE, appText); if (dwLockTimeout && (mode == RA_WAIT)) SystemParametersInfo(0x2001 /*==SPI_SETFOREGROUNDLOCKTIMEOUT*/, 0, (LPVOID)dwLockTimeout, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE); return FALSE; } DWORD numWrite; if(!WriteFile(h, commLine, lstrlen(commLine), &numWrite, 0)) { CloseHandle(h); errorText.FormatMessage(IDS_COULD_NOT_RUN_s_COULD_NOT_WRITE_TEMP_COMMAND_FILE, appText); if (dwLockTimeout && (mode == RA_WAIT)) SystemParametersInfo(0x2001 /*==SPI_SETFOREGROUNDLOCKTIMEOUT*/, 0, (LPVOID)dwLockTimeout, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE); return FALSE; } CloseHandle(h); commLine = tempFile; } else { TCHAR cmd[MAX_PATH+1]; GetEnvironmentVariable(_T("ComSpec"), cmd, MAX_PATH); commLine = (CString)cmd + (isClose ? _T(" /c start /wait ") : _T(" /k ")) + commLine; } lstrcpy(commandLine, commLine); SetLastError(0); success=CreateProcess( NULL, // pointer to name of executable module commandLine, // pointer to command line string NULL, NULL, // default security rot FALSE, // handle inheritance flag dwCreationFlags | CREATE_NEW_CONSOLE, // creation flags NULL, NULL, //default env and curdir &startInfo, &procInfo); } else { SetLastError(0); lstrcpy(commandLine, commLine); success=CreateProcess( NULL, // pointer to name of executable module commandLine, // pointer to command line string NULL, NULL, // default security rot FALSE, // handle inheritance flag dwCreationFlags, // creation flags NULL, // env NULL, //default dir &startInfo, &procInfo); } if(success) { if(mode == RA_WAIT) { CString oldtext; CString newtext; newtext.FormatMessage(IDS_WAITING_FOR_s_TO_FINISH, appName); // Let the user know what we aren't responding // AfxGetMainWnd()->GetWindowText(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<LPTSTR>((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<len; i++) { if ((*ptr==_T('\r')) || (*ptr==_T('\n')) || (*ptr==_T('\t'))) { if ((ptrout > 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(" <text")) != -1) BaseType = 0; else if (itemStr.Find(_T(" <binary")) != -1) BaseType = 1; else if (itemStr.Find(_T(" <symlink")) != -1) BaseType = 2; else if (itemStr.Find(_T(" <resource")) != -1) BaseType = 3; else if (itemStr.Find(_T(" <apple")) != -1) BaseType = 4; else if (itemStr.Find(_T(" <unicode")) != -1) BaseType = 5; else if (itemStr.Find(_T(" <utf16")) != -1) BaseType = 6; StoreType = 0; Unknown = FALSE; if ((plus = itemStr.Find(_T("+"), itemStr.Find(_T(" <")))) != -1) { while (((c = itemStr.GetAt(++plus)) != _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(" <xtext>")) != -1) { BaseType = 0; TypeX = TRUE; } else if (itemStr.Find(_T(" <ktext>")) != -1) { BaseType = 0; TypeK = TRUE; } else if (itemStr.Find(_T(" <kxtext>")) != -1) { BaseType = 0; TypeX = TRUE; TypeK = TRUE; } else if (itemStr.Find(_T(" <xbinary>")) != -1) { BaseType = 1; TypeX = TRUE; } else if (itemStr.Find(_T(" <ctext>")) != -1) { BaseType = 0; StoreType = 1; } else if (itemStr.Find(_T(" <cxtext>")) != -1) { BaseType = 0; StoreType = 2; TypeX = TRUE; } else if (itemStr.Find(_T(" <ltext>")) != -1) { BaseType = 0; StoreType = 3; } else if (itemStr.Find(_T(" <lxtext>")) != -1) { BaseType = 0; TypeS = TypeX = TRUE; } else if (itemStr.Find(_T(" <ubinary>")) != -1) { BaseType = 1; StoreType = 3; } else if (itemStr.Find(_T(" <tempobj>")) != -1) { BaseType = 1; TypeS = TypeW = TRUE; } else if ((itemStr.Find(_T(" <xtempobj>")) != -1) || (itemStr.Find(_T(" <tempxobj>")) != -1)) { BaseType = 1; TypeS = TypeW = TypeX = TRUE; } else if (itemStr.Find(_T(" <xunicode>")) != -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<char*>((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); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 19924 | YourUncleBob |
Populate -o //guest/perforce_software/p4win/... //guest/YourUncleBob/p4win/..... |
||
//guest/perforce_software/p4win/main/gui/P4win.cpp | |||||
#1 | 16169 | perforce_software | Move files to follow new path scheme for branches. | ||
//guest/perforce_software/p4win/gui/P4win.cpp | |||||
#1 | 8562 | Matt Attaway |
These feet never stop running. Initial commit of the P4Win source code. To the best of our knowledge this compiles and runs using the 2013.3 P4 API and VS 2010. Expect a few changes as we refine the build process. Please post any build issues to the forums. |