SEXP R_export2dataset(SEXP path, SEXP dataframe, SEXP shape, SEXP shape_info) { std::wstring dataset_name; tools::copy_to(path, dataset_name); struct _cleanup { typedef std::vector<cols_base*> c_type; std::vector<std::wstring> name; c_type c; ~_cleanup() { for (size_t i = 0, n = c.size(); i < n; i++) delete c[i]; } }cols; shape_extractor extractor; bool isShape = extractor.init(shape, shape_info) == S_OK; tools::getNames(dataframe, cols.name); R_xlen_t nlen = 0; ATLTRACE("dataframe type:%s", Rf_type2char(TYPEOF(dataframe))); if (Rf_isVectorList(dataframe)) { size_t k = tools::size(dataframe); ATLASSERT(cols.name.size() == k); cols.name.resize(k); for (size_t i = 0; i < k; i++) { nlen = std::max(nlen, tools::size(VECTOR_ELT(dataframe, i))); if (cols.name[i].empty()) cols.name[i] = L"data"; } } else { if (Rf_isNull(dataframe)) nlen = extractor.size(); else return showError<false>("unsupported datat type"), R_NilValue; } if (nlen == 0) return showError<false>("nothing to save: 0 length"), R_NilValue; if (isShape && nlen != extractor.size() ) Rf_warning("length of shape != data.frame length"); //return showError<false>("length of shape != data.frame"), R_NilValue; std::unique_ptr<arcobject::cursor> acur(arcobject::create_insert_cursor(dataset_name, extractor.geometry_info())); if (acur.get() == NULL) return showError<true>(), R_NilValue; arcobject::cursor* cur = acur.get(); for (size_t i = 0; i < cols.name.size(); i++) { ATLASSERT(!cols.name[i].empty()); SEXP it = VECTOR_ELT(dataframe, i); bool skip = false; if (isShape)//if(gt == esriGeometryPolygon || gt == esriGeometryLine) { skip = cols.name[i] == L"Shape_Area"; skip = !skip ? cols.name[i] == L"Shape_Length" : true; } if (!skip) { cols_base* item = setup_field(cur, it, cols.name[i]); if (!item) Rf_warning("unsupported data.field column type");//return showError<false>(L"unsupported data.field column type"), R_NilValue; else cols.c.push_back(item); } } if (!cur->begin()) return showError<true>(), R_NilValue; for (R_xlen_t i = 0; i < nlen; i++) { //ATLTRACE("\n"); for (const auto &c : cols.c) { if (c->pos < 0) continue; CComVariant val; c->get(i, val); if (!cur->setValue(c->pos, val)) return showError<true>("insert row value failed"), R_NilValue; } if (isShape) { if (extractor.isPoints()) cur->set_point(extractor.getPoint(i)); else cur->set_shape(extractor.getShape(i)); } if (!cur->next()) return showError<true>("insert row failed"), R_NilValue; } cur->commit(); return R_NilValue; }
STDMETHODIMP CBindStatCallback::OnObjectAvailable(REFIID riid, IUnknown *punk) { ATLTRACE(_T("CBindStatCallback::OnObjectAvailable\n")); return E_NOTIMPL; }
STDMETHODIMP CBindStatCallback::GetPriority(LONG *pnPriority) { ATLTRACE(_T("CBindStatCallback::GetPriority\n")); return E_NOTIMPL; }
int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int /*nCmdShow*/ = SW_SHOWDEFAULT) { int nRet = 0; // Return code CErrorReportDlg dlgErrorReport; // Error Report dialog CResendDlg dlgResend; // Resend dialog // Get command line parameters. LPCWSTR szCommandLine = GetCommandLineW(); // Split command line. int argc = 0; LPWSTR* argv = CommandLineToArgvW(szCommandLine, &argc); // Check parameter count. if(argc!=2) return 1; // No arguments passed, exit. if(_tcscmp(argv[1], _T("/terminate"))==0) { // User wants us to find and terminate all instances of CrashSender.exe return CErrorReportSender::TerminateAllCrashSenderProcesses(); } // Extract file mapping name from command line arg. CString sFileMappingName = CString(argv[1]); // Create the sender model that will collect crash report data // and send error report(s). CErrorReportSender* pSender = CErrorReportSender::GetInstance(); // Init the sender object BOOL bInit = pSender->Init(sFileMappingName.GetBuffer(0)); if(!bInit) { // Failed to init return 0; } // Determine what to do next // (either run in GUI more or run in silent mode). if(!pSender->GetCrashInfo()->m_bSilentMode) { // GUI mode. // Create message loop. CMessageLoop theLoop; _Module.AddMessageLoop(&theLoop); if(!pSender->GetCrashInfo()->m_bSendRecentReports) { // Create "Error Report" dialog if(dlgErrorReport.Create(NULL) == NULL) { ATLTRACE(_T("Error report dialog creation failed!\n")); return 1; } } else { // Create "Send Error Reports" dialog. if(dlgResend.Create(NULL) == NULL) { ATLTRACE(_T("Resend dialog creation failed!\n")); return 1; } } // Process window messages. nRet = theLoop.Run(); _Module.RemoveMessageLoop(); } else { // Silent (non-GUI mode). // Run the sender and wait until it exits. pSender->Run(); pSender->WaitForCompletion(); // Get return status nRet = pSender->GetStatus(); } // Delete sender object. delete pSender; // Exit. return nRet; }
STDMETHODIMP CBindStatCallback::GetBindInfo(DWORD *pgrfBINDF, BINDINFO *pbindInfo) { ATLTRACE(_T("CBindStatCallback::GetBindInfo\n")); return E_NOTIMPL; }
DDEClientTransactionManager::DDEClientTransactionManager(void) : m_env(NULL) , m_idInst(0) { ATLTRACE( _T("DDEClientTransactionManager::DDEClientTransactionManager();\n") ); }
int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int /*nCmdShow*/ = SW_SHOWDEFAULT) { LPCWSTR szCommandLine = GetCommandLineW(); int argc = 0; LPWSTR* argv = CommandLineToArgvW(szCommandLine, &argc); // Read the crash info passed by CrashRpt.dll to CrashSender.exe if(argc!=2) return 1; // No arguments passed // Read crash info CString sFileName = CString(argv[1]); int nInit = g_CrashInfo.Init(sFileName); if(nInit!=0) { MessageBox(NULL, _T("Couldn't initialize!"), _T("CrashSender.exe"), MB_ICONERROR); return 1; } if(!g_CrashInfo.m_bSendRecentReports) { // Do the crash info collection work assynchronously g_ErrorReportSender.DoWork(COLLECT_CRASH_INFO); } // Check window mirroring settings CString sRTL = Utility::GetINIString(g_CrashInfo.m_sLangFileName, _T("Settings"), _T("RTLReading")); if(sRTL.CompareNoCase(_T("1"))==0) { SetProcessDefaultLayout(LAYOUT_RTL); } CMessageLoop theLoop; _Module.AddMessageLoop(&theLoop); if(!g_CrashInfo.m_bSendRecentReports) { if(dlgErrorReport.Create(NULL) == NULL) { ATLTRACE(_T("Main dialog creation failed!\n")); return 0; } } else { // check if another instance of CrashSender.exe is running ::CreateMutex( NULL, FALSE,_T("Local\\43773530-129a-4298-88f2-20eea3e4a59b")); if (::GetLastError() == ERROR_ALREADY_EXISTS) { // Another CrashSender.exe already tries to resend recent reports; exit. return 0; } if(g_CrashInfo.GetReportCount()==0) return 0; // There are no reports for us to send // Check if it is ok to remind user now if(!g_CrashInfo.IsRemindNowOK()) return 0; if(dlgResend.Create(NULL) == NULL) { ATLTRACE(_T("Resend dialog creation failed!\n")); return 0; } } int nRet = theLoop.Run(); // Wait until the worker thread is exited g_ErrorReportSender.WaitForCompletion(); nRet = g_ErrorReportSender.GetGlobalStatus(); _Module.RemoveMessageLoop(); return nRet; }
bool CPathWatcher::AddPath(const CTGitPath& path) { AutoLocker lock(m_critSec); for (int i=0; i<watchedPaths.GetCount(); ++i) { if (watchedPaths[i].IsAncestorOf(path)) return false; // already watched (recursively) } // now check if with the new path we might have a new root CTGitPath newroot; for (int i=0; i<watchedPaths.GetCount(); ++i) { const CString& watched = watchedPaths[i].GetWinPathString(); const CString& sPath = path.GetWinPathString(); int minlen = min(sPath.GetLength(), watched.GetLength()); int len = 0; for (len = 0; len < minlen; ++len) { if (watched.GetAt(len) != sPath.GetAt(len)) { if ((len > 1)&&(len < minlen)) { if (sPath.GetAt(len)=='\\') { newroot = CTGitPath(sPath.Left(len)); } else if (watched.GetAt(len)=='\\') { newroot = CTGitPath(watched.Left(len)); } } break; } } if (len == minlen) { if (sPath.GetLength() == minlen) { if (watched.GetLength() > minlen) { if (watched.GetAt(len)=='\\') { newroot = path; } else if (sPath.GetLength() == 3 && sPath[1] == ':') { newroot = path; } } } else { if (sPath.GetLength() > minlen) { if (sPath.GetAt(len)=='\\') { newroot = CTGitPath(watched); } else if (watched.GetLength() == 3 && watched[1] == ':') { newroot = CTGitPath(watched); } } } } } if (!newroot.IsEmpty()) { ATLTRACE(_T("add path to watch %s\n"), newroot.GetWinPath()); watchedPaths.AddPath(newroot); watchedPaths.RemoveChildren(); m_hCompPort.CloseHandle(); return true; } ATLTRACE(_T("add path to watch %s\n"), path.GetWinPath()); watchedPaths.AddPath(path); m_hCompPort.CloseHandle(); return true; }
DWORD __stdcall CInjection::Initialize(LPVOID lpParameter ) { USES_CONVERSION; HMODULE hInstance = (HMODULE)lpParameter; // get the current directory CString strCurrentDir = CUtility::GetCurrentDirectory(); // dbghelp.dll { CString strDbgHelpDll; strDbgHelpDll.Format( _T("%s%s"), strCurrentDir, DBG_HELP_DLL); HMODULE hModule = ::LoadLibrary(strDbgHelpDll); if( hModule == NULL || !CPdbHelper::Initialize(hModule) ) { s_nStatus = Status_Error_DbgHelpNotFound; SetEvent( s_hEvent ); return FALSE; } } // find the JIT module g_hJitModule = GetModuleHandleA("clrjit.dll"); if( !g_hJitModule ) g_hJitModule = GetModuleHandleA("mscorjit.dll"); if( g_hJitModule == NULL ) { s_nStatus = Status_Error_JITNotFound; SetEvent( s_hEvent ); return FALSE; } // find the CLR module g_hClrModule = GetModuleHandleA("clr.dll"); if( !g_hClrModule ) g_hClrModule = GetModuleHandleA("mscorwks.dll"); if( g_hClrModule == NULL || !DetermineDotNetVersion() ) { s_nStatus = Status_Error_CLRNotFound; SetEvent( s_hEvent ); return FALSE; } // try to quick load the symbol address base on the binary hash if( !CSymbolAddressCache::TryCache() ) { // get the pdb directory CString strDestPath(strCurrentDir); { strDestPath.AppendFormat( _T("PDB_symbols\\") ); ::CreateDirectory(strDestPath, NULL); } // copy the JIT dll { TCHAR tszFilename[MAX_PATH] = {0}; GetModuleFileName( g_hJitModule, tszFilename, MAX_PATH); ::CopyFile( tszFilename, strDestPath + CUtility::GetFileName(tszFilename), FALSE); } // copy the CLR dll { TCHAR tszFilename[MAX_PATH] = {0}; GetModuleFileName( g_hClrModule, tszFilename, MAX_PATH); ::CopyFile( tszFilename, strDestPath + CUtility::GetFileName(tszFilename), FALSE); } // Set Environment Variable { CString strVariable; strVariable.Format( _T("symsrv*symsrv.dll*%s*http://msdl.microsoft.com/download/symbols"), strDestPath); SetEnvironmentVariable( _T("_NT_SYMBOL_PATH"), strVariable.GetBuffer()); strVariable.ReleaseBuffer(); } if( !SearchMethodAddresses(T2W(strDestPath.GetBuffer())) ) { // download the pdb // symchk.exe /if "C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorjit.dll" /s srv*G:\HookDotNet*http://msdl.microsoft.com/download/symbols CString strCmd; strCmd.Format( _T("\"%s%s\" /if \"%s*.dll\" /s symsrv*symsrv.dll*%s*http://msdl.microsoft.com/download/symbols") , strCurrentDir , SYMCHK_EXE , strDestPath , strDestPath ); ATLTRACE( _T("\n%s"), strCmd); STARTUPINFO si = { sizeof(si) }; si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; PROCESS_INFORMATION pi = {0}; BOOL bRet = CreateProcess( NULL , strCmd.GetBuffer() , NULL , NULL , FALSE , 0 , NULL , strCurrentDir , &si , &pi ); strCmd.ReleaseBuffer(); if( !bRet ) { s_nStatus = Status_Error_DownloadPDBFailed; SetEvent( s_hEvent ); return FALSE; } WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); // find all the pdb files if( !SearchMethodAddresses(NULL) ) SearchMethodAddresses(NULL, FALSE); } // cache the address offset according to the binary hash if( ICorJitCompiler::s_pfnComplieMethod ) { CSymbolAddressCache::GenerateJitCache(); }; if( MethodDesc::IsInitialized() && LoadedMethodDescIterator::IsInitialized() ) { CSymbolAddressCache::GenerateClrCache(); } } HookApi(); SetEvent( s_hEvent ); return TRUE; }
VOID CAboutDialog::OnCheckUpdate(UINT /* wNotifyCode */, int /* wID */, HWND /* hWndCtl */) { NDUPDATE_SYSTEM_INFO sysInfo = {0}; NDUPDATE_UPDATE_INFO_V2 updateInfo = {0}; sysInfo.dwLanguageSet = 0; sysInfo.dwPlatform = NDAS_PLATFORM_WIN2K; sysInfo.dwVendor = 0; VS_FIXEDFILEINFO vffi = {0}; BOOL fSuccess = pGetModuleVerFileInfo(vffi); if (!fSuccess) { // // This is a fallback // ATLASSERT(FALSE); sysInfo.ProductVersion.wMajor = 3; sysInfo.ProductVersion.wMinor = 10; sysInfo.ProductVersion.wBuild = 0; sysInfo.ProductVersion.wPrivate = 0; } else { sysInfo.ProductVersion.wMajor = HIWORD(vffi.dwProductVersionMS); sysInfo.ProductVersion.wMinor = LOWORD(vffi.dwProductVersionMS); sysInfo.ProductVersion.wBuild = HIWORD(vffi.dwProductVersionLS); sysInfo.ProductVersion.wPrivate = LOWORD(vffi.dwProductVersionLS); } TCHAR szUpdateBaseURL[NDUPDATE_MAX_URL] = {0}; fSuccess = pGetAppConfigValue( _T("UpdateURL"), szUpdateBaseURL, NDUPDATE_MAX_URL); if (!fSuccess) { HRESULT hr = ::StringCchCopy( szUpdateBaseURL, NDUPDATE_MAX_URL, _T("http://updates.ximeta.com/update/")); ATLASSERT(SUCCEEDED(hr)); } AutoHModule hUpdateDLL = ::LoadLibrary(_T("ndupdate.dll")); if (NULL == (HMODULE)hUpdateDLL) { return; } typedef BOOL (WINAPI* NDUPDATE_NdasUpdateDoUpdate)(HWND, LPCTSTR, PNDUPDATE_SYSTEM_INFO); NDUPDATE_NdasUpdateDoUpdate pfnDoUpdate = (NDUPDATE_NdasUpdateDoUpdate) ::GetProcAddress(hUpdateDLL, "NdasUpdateDoUpdate"); LCID lcid = ::GetThreadLocale(); fSuccess = ::SetThreadLocale(MAKELCID(_CurrentUILangID,SORT_DEFAULT)); ATLASSERT(fSuccess); fSuccess = pfnDoUpdate(m_hWnd, szUpdateBaseURL, &sysInfo); if (!fSuccess) { ATLTRACE(_T("Update function failed: %08X"), ::GetLastError()); } fSuccess = ::SetThreadLocale(lcid); ATLASSERT(fSuccess); }
void CPathWatcher::WorkerThread() { DWORD numBytes; CDirWatchInfo * pdi = NULL; LPOVERLAPPED lpOverlapped; WCHAR buf[MAX_PATH*4] = {0}; while (m_bRunning) { if (watchedPaths.GetCount()) { if (!GetQueuedCompletionStatus(m_hCompPort, &numBytes, (PULONG_PTR) &pdi, &lpOverlapped, INFINITE)) { // Error retrieving changes // Clear the list of watched objects and recreate that list if (!m_bRunning) return; { AutoLocker lock(m_critSec); ClearInfoMap(); } DWORD lasterr = GetLastError(); if ((m_hCompPort)&&(lasterr!=ERROR_SUCCESS)&&(lasterr!=ERROR_INVALID_HANDLE)) { m_hCompPort.CloseHandle(); } // Since we pass m_hCompPort to CreateIoCompletionPort, we // have to set this to NULL to have that API create a new // handle. m_hCompPort = NULL; for (int i=0; i<watchedPaths.GetCount(); ++i) { CAutoFile hDir = CreateFile(watchedPaths[i].GetWinPath(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, //security attributes OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | //required privileges: SE_BACKUP_NAME and SE_RESTORE_NAME. FILE_FLAG_OVERLAPPED, NULL); if (!hDir) { // this could happen if a watched folder has been removed/renamed m_hCompPort.CloseHandle(); AutoLocker lock(m_critSec); watchedPaths.RemovePath(watchedPaths[i]); i--; if (i<0) i=0; break; } CDirWatchInfo * pDirInfo = new CDirWatchInfo(hDir, watchedPaths[i]); hDir.Detach(); // the new CDirWatchInfo object owns the handle now m_hCompPort = CreateIoCompletionPort(pDirInfo->m_hDir, m_hCompPort, (ULONG_PTR)pDirInfo, 0); if (m_hCompPort == NULL) { AutoLocker lock(m_critSec); ClearInfoMap(); delete pDirInfo; pDirInfo = NULL; watchedPaths.RemovePath(watchedPaths[i]); i--; if (i<0) i=0; break; } if (!ReadDirectoryChangesW(pDirInfo->m_hDir, pDirInfo->m_Buffer, READ_DIR_CHANGE_BUFFER_SIZE, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, &numBytes,// not used &pDirInfo->m_Overlapped, NULL)) //no completion routine! { AutoLocker lock(m_critSec); ClearInfoMap(); delete pDirInfo; pDirInfo = NULL; watchedPaths.RemovePath(watchedPaths[i]); i--; if (i<0) i=0; break; } AutoLocker lock(m_critSec); watchInfoMap[pDirInfo->m_hDir] = pDirInfo; ATLTRACE(_T("watching path %s\n"), pDirInfo->m_DirName.GetWinPath()); } } else { if (!m_bRunning) return; // NOTE: the longer this code takes to execute until ReadDirectoryChangesW // is called again, the higher the chance that we miss some // changes in the file system! if (pdi) { if (numBytes == 0) { goto continuewatching; } PFILE_NOTIFY_INFORMATION pnotify = (PFILE_NOTIFY_INFORMATION)pdi->m_Buffer; if ((ULONG_PTR)pnotify - (ULONG_PTR)pdi->m_Buffer > READ_DIR_CHANGE_BUFFER_SIZE) goto continuewatching; DWORD nOffset = pnotify->NextEntryOffset; do { nOffset = pnotify->NextEntryOffset; SecureZeroMemory(buf, MAX_PATH*4*sizeof(TCHAR)); _tcsncpy_s(buf, MAX_PATH*4, pdi->m_DirPath, MAX_PATH*4); errno_t err = _tcsncat_s(buf+pdi->m_DirPath.GetLength(), (MAX_PATH*4)-pdi->m_DirPath.GetLength(), pnotify->FileName, _TRUNCATE); if (err == STRUNCATE) { pnotify = (PFILE_NOTIFY_INFORMATION)((LPBYTE)pnotify + nOffset); continue; } buf[min(MAX_PATH*4-1, pdi->m_DirPath.GetLength()+(pnotify->FileNameLength/sizeof(WCHAR)))] = 0; pnotify = (PFILE_NOTIFY_INFORMATION)((LPBYTE)pnotify + nOffset); ATLTRACE(_T("change notification: %s\n"), buf); m_changedPaths.AddPath(CTGitPath(buf)); if ((ULONG_PTR)pnotify - (ULONG_PTR)pdi->m_Buffer > READ_DIR_CHANGE_BUFFER_SIZE) break; } while (nOffset); continuewatching: SecureZeroMemory(pdi->m_Buffer, sizeof(pdi->m_Buffer)); SecureZeroMemory(&pdi->m_Overlapped, sizeof(OVERLAPPED)); if (!ReadDirectoryChangesW(pdi->m_hDir, pdi->m_Buffer, READ_DIR_CHANGE_BUFFER_SIZE, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, &numBytes,// not used &pdi->m_Overlapped, NULL)) //no completion routine! { // Since the call to ReadDirectoryChangesW failed, just // wait a while. We don't want to have this thread // running using 100% CPU if something goes completely // wrong. Sleep(200); } } } }// if (watchedPaths.GetCount()) else Sleep(200); }// while (m_bRunning) }
bool CRemoteCacheLink::GetStatusFromRemoteCache(const CTGitPath& Path, TGITCacheResponse* pReturnedStatus, bool bRecursive) { if(!EnsurePipeOpen()) { // We've failed to open the pipe - try and start the cache // but only if the last try to start the cache was a certain time // ago. If we just try over and over again without a small pause // in between, the explorer is rendered unusable! // Failing to start the cache can have different reasons: missing exe, // missing registry key, corrupt exe, ... if (((long)GetTickCount() - m_lastTimeout) < 0) return false; STARTUPINFO startup; PROCESS_INFORMATION process; memset(&startup, 0, sizeof(startup)); startup.cb = sizeof(startup); memset(&process, 0, sizeof(process)); CString sCachePath = CPathUtils::GetAppDirectory(g_hmodThisDll) + _T("TGitCache.exe"); #ifndef _WIN64 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); LPFN_ISWOW64PROCESS fnIsWow64Process; fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")),"IsWow64Process"); if (NULL != fnIsWow64Process) { BOOL bIsWow64 = false; if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) { bIsWow64 = false; } if (bIsWow64) { CRegString tgitinstalled64 = CRegString(_T("Software\\TortoiseGit\\CachePath"), _T(""), false, HKEY_LOCAL_MACHINE, KEY_WOW64_64KEY); if (!CString(tgitinstalled64).IsEmpty()) sCachePath = tgitinstalled64; } } if (!CCreateProcessHelper::CreateProcessDetached(sCachePath, NULL)) { ATLTRACE("Failed to start x64 cache\n"); CString sCachePath = CPathUtils::GetAppDirectory(g_hmodThisDll) + _T("TGitCache.exe"); if (!CCreateProcessHelper::CreateProcessDetached(sCachePath, NULL)) { // It's not appropriate to do a message box here, because there may be hundreds of calls ATLTRACE("Failed to start cache\n"); return false; } } #else if (!CCreateProcessHelper::CreateProcessDetached(sCachePath, NULL)) { // It's not appropriate to do a message box here, because there may be hundreds of calls ATLTRACE("Failed to start cache\n"); return false; } #endif CloseHandle(process.hThread); CloseHandle(process.hProcess); sCachePath.ReleaseBuffer(); // Wait for the cache to open long endTime = (long)GetTickCount()+1000; while(!EnsurePipeOpen()) { if(((long)GetTickCount() - endTime) > 0) { m_lastTimeout = (long)GetTickCount()+10000; return false; } } } AutoLocker lock(m_critSec); DWORD nBytesRead; TGITCacheRequest request; request.flags = TGITCACHE_FLAGS_NONOTIFICATIONS; if(bRecursive) { request.flags |= TGITCACHE_FLAGS_RECUSIVE_STATUS; } wcsncpy_s(request.path, MAX_PATH+1, Path.GetWinPath(), MAX_PATH); SecureZeroMemory(&m_Overlapped, sizeof(OVERLAPPED)); m_Overlapped.hEvent = m_hEvent; // Do the transaction in overlapped mode. // That way, if anything happens which might block this call // we still can get out of it. We NEVER MUST BLOCK THE SHELL! // A blocked shell is a very bad user impression, because users // who don't know why it's blocked might find the only solution // to such a problem is a reboot and therefore they might lose // valuable data. // One particular situation where the shell could hang is when // the cache crashes and our crash report dialog comes up. // Sure, it would be better to have no situations where the shell // even can get blocked, but the timeout of 10 seconds is long enough // so that users still recognize that something might be wrong and // report back to us so we can investigate further. BOOL fSuccess = TransactNamedPipe(m_hPipe, &request, sizeof(request), pReturnedStatus, sizeof(*pReturnedStatus), &nBytesRead, &m_Overlapped); if (!fSuccess) { if (GetLastError()!=ERROR_IO_PENDING) { //OutputDebugStringA("TortoiseShell: TransactNamedPipe failed\n"); ClosePipe(); return false; } // TransactNamedPipe is working in an overlapped operation. // Wait for it to finish DWORD dwWait = WaitForSingleObject(m_hEvent, 10000); if (dwWait == WAIT_OBJECT_0) { fSuccess = GetOverlappedResult(m_hPipe, &m_Overlapped, &nBytesRead, FALSE); } else { // the cache didn't respond! fSuccess = FALSE; } } if (fSuccess) { return true; } ClosePipe(); return false; }
void CShellUpdater::WorkerThread() { HANDLE hWaitHandles[2]; hWaitHandles[0] = m_hTerminationEvent; hWaitHandles[1] = m_hWakeEvent; for(;;) { DWORD waitResult = WaitForMultipleObjects(_countof(hWaitHandles), hWaitHandles, FALSE, INFINITE); // exit event/working loop if the first event (m_hTerminationEvent) // has been signaled or if one of the events has been abandoned // (i.e. ~CShellUpdater() is being executed) if(waitResult == WAIT_OBJECT_0 || waitResult == WAIT_ABANDONED_0 || waitResult == WAIT_ABANDONED_0+1) { // Termination event break; } // wait some time before we notify the shell Sleep(50); for(;;) { CTGitPath workingPath; if (!m_bRunning) return; Sleep(0); { AutoLocker lock(m_critSec); if(m_pathsToUpdate.empty()) { // Nothing left to do break; } if(m_bItemsAddedSinceLastUpdate) { m_pathsToUpdate.erase(std::unique(m_pathsToUpdate.begin(), m_pathsToUpdate.end(), &CTGitPath::PredLeftEquivalentToRight), m_pathsToUpdate.end()); m_bItemsAddedSinceLastUpdate = false; } workingPath = m_pathsToUpdate.front(); m_pathsToUpdate.pop_front(); } if (workingPath.IsEmpty()) continue; ATLTRACE(_T("Update notifications for: %s\n"), workingPath.GetWinPath()); if (workingPath.IsDirectory()) { // check if the path is monitored by the watcher. If it isn't, then we have to invalidate the cache // for that path and add it to the watcher. if (!CGitStatusCache::Instance().IsPathWatched(workingPath)) { if (workingPath.HasAdminDir()) CGitStatusCache::Instance().AddPathToWatch(workingPath); } // first send a notification about a sub folder change, so explorer doesn't discard // the folder notification. Since we only know for sure that the subversion admin // dir is present, we send a notification for that folder. CString admindir = workingPath.GetWinPathString() + _T("\\") + g_GitAdminDir.GetAdminDirName(); if(::PathFileExists(admindir)) SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, (LPCTSTR)admindir, NULL); SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, workingPath.GetWinPath(), NULL); // Sending an UPDATEDIR notification somehow overwrites/deletes the UPDATEITEM message. And without // that message, the folder overlays in the current view don't get updated without hitting F5. // Drawback is, without UPDATEDIR, the left tree view isn't always updated... SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, workingPath.GetWinPath(), NULL); } else SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, workingPath.GetWinPath(), NULL); } } _endthread(); }
BOOL CMainFrame::RefreshStatus() { // lock ActivateUI(FALSE); m_viewTreeList.GetTreeControl().DeleteAllItems(); ClearDevices(); // retrieve all the device & unit device information if(!NdasEnumDevices( EnumDevicesCallBack, reinterpret_cast<LPVOID>(&m_listDevices))) return FALSE; m_wndRefreshProgress.ShowWindow(SW_SHOW); m_wndRefreshProgress.SetRange32(0, m_listDevices.size()); m_wndRefreshProgress.SetStep(1); m_wndRefreshProgress.SetPos(0); // initialize all the unit devices for(NBNdasDevicePtrList::iterator itDevice = m_listDevices.begin(); itDevice != m_listDevices.end(); itDevice++) { if(!(*itDevice)->UnitDevicesInitialize()) { // add single empty device ATLTRACE(_T("Device not connected : %s\n"), (*itDevice)->GetName()); // m_wndRefreshProgress.ShowWindow(SW_HIDE); // return FALSE; } m_wndRefreshProgress.StepIt(); } // create logical devices CNBUnitDevice *pUnitDevice; CNBLogicalDevice *pLogicalDevice; m_wndRefreshProgress.SetPos(0); for(NBNdasDevicePtrList::iterator itDevice = m_listDevices.begin(); itDevice != m_listDevices.end(); itDevice++) { /* if(0 == (*itDevice)->UnitDevicesCount()) { // suppose to be disconnected pLogicalDevice = new CNBLogicalDevice(); pLogicalDevice->SetEmpty(); m_listLogicalDevices.push_back(pLogicalDevice); ATLTRACE(_T("new CNBLogicalDevice(%p) : empty\n"), pLogicalDevice); } */ for(UINT32 i = 0; i < (*itDevice)->UnitDevicesCount(); i++) { // find logical device which has this unit device as member pLogicalDevice = NULL; pUnitDevice = (*(*itDevice))[i]; ATLASSERT(pUnitDevice); if(!pUnitDevice) return FALSE; for(NBLogicalDevicePtrList::iterator itLogicalDevice = m_listLogicalDevices.begin(); itLogicalDevice != m_listLogicalDevices.end(); itLogicalDevice++) { if((*itLogicalDevice)->IsMember(pUnitDevice)) { // add to this logical device pLogicalDevice = *itLogicalDevice; ATLTRACE(_T("use CNBLogicalDevice(%p) : %s\n"), pLogicalDevice, pUnitDevice->GetName()); break; } } if(NULL == pLogicalDevice) { // create new logical device pLogicalDevice = new CNBLogicalDevice(); m_listLogicalDevices.push_back(pLogicalDevice); ATLTRACE(_T("new CNBLogicalDevice(%p) : %s\n"), pLogicalDevice, pUnitDevice->GetName()); } if(!pLogicalDevice->UnitDeviceAdd(pUnitDevice)) { m_wndRefreshProgress.ShowWindow(SW_HIDE); return FALSE; } } m_wndRefreshProgress.StepIt(); } m_viewTreeList.SetDevices(&m_listLogicalDevices); m_wndRefreshProgress.ShowWindow(SW_HIDE); ActivateUI(TRUE); return TRUE; }
bool SetupInternetConnection(LPCTSTR url) { int iNetwork; HRESULT hResult = E_FAIL; DWORD dwStatus; // cleanup the old connection if(NULL != hConnection) { hResult=ConnMgrConnectionStatus(hConnection,&dwStatus); if( SUCCEEDED(hResult) ) { ATLTRACE(L"Internet connection exist, use it\n"); if( dwStatus & CONNMGR_STATUS_CONNECTED ) return true; } ConnMgrReleaseConnection(hConnection, FALSE); ATLTRACE(L"Internet connection droped, open new one\n"); hConnection = NULL; } // get the right network to connect to iNetwork = 0; //CONNMGR_DESTINATION_INFO DestInfo; GUID pguid; if( FAILED( ConnMgrMapURL(url, &pguid, NULL) ) ) return false; //while( SUCCEEDED(ConnMgrEnumDestinations(iNetwork++, &DestInfo))) { ATLTRACE(L"Try establish Internet connection \n"); // actually try to establish the connection CONNMGR_CONNECTIONINFO ConnInfo; ZeroMemory(&ConnInfo, sizeof(ConnInfo)); ConnInfo.cbSize = sizeof(ConnInfo); ConnInfo.dwParams = CONNMGR_PARAM_GUIDDESTNET; ConnInfo.dwPriority = CONNMGR_PRIORITY_HIPRIBKGND;//CONNMGR_PRIORITY_USERBACKGROUND; #if ( _WIN32_WCE >= 0x500 ) ConnInfo.dwFlags = CONNMGR_FLAG_NO_ERROR_MSGS; #endif ConnInfo.guidDestNet = pguid; hResult = ConnMgrEstablishConnection(&ConnInfo, &hConnection); // check to see if the attempt failed int count = 0; while(SUCCEEDED(hResult) && count++ < 60 ) { ATLTRACE(L"Wait for connect (%d).\n",count); DWORD dwResult = WaitForSingleObject( hConnection, 1000); if (dwResult == (WAIT_OBJECT_0)) { hResult=ConnMgrConnectionStatus(hConnection,&dwStatus); if( SUCCEEDED(hResult) ) { if( dwStatus & CONNMGR_STATUS_CONNECTED ) { ATLTRACE(L"Connected\n"); return true; } if( dwStatus & CONNMGR_STATUS_WAITINGCONNECTION ) { continue; } break; } } } } ATLTRACE(L"Failed to connect\n"); return false; }
void ClearResultCache() { ATLTRACE(_T("Result cache before clearing(size=%u)\r\n"), ResultCache.Size()); ResultCache.Clear(); }
char* remote_data(LPWSTR verb, char* url, char* body, size_t body_size, bool bGetHeaders, bool bGetRawData = false, bool bCheckSession = false, DWORD* pdwDataSize = NULL) { char *cstr = NULL; char *session = NULL; std::string data = ""; //CAtlStringA data; char sBuf[1024]; DWORD dwBytesRead = 0; LPWSTR urlw; HINTERNET hInet, hConnection, hRequest; LPTSTR pszFunction = NULL; if ( url==NULL || strlen(url)==0 ) return NULL; urlw = wce_mbtowc(url); hInet = hConnection = hRequest = NULL; do { // Don't make a connection attempt if there is no session session = get_db_session(load_source_url()); if ( bCheckSession && !session && !strstr(url, "clientcreate") ) { break; } if (session) free(session); if( !SetupInternetConnection(urlw) ) { break; } hInet = InternetOpen(_T("rhodes-wm"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, NULL ); if ( !hInet ) { pszFunction = L"InternetOpen"; break; } DWORD lpdwBufferLength = sizeof(sBuf)/sizeof(wchar_t); if ( !InternetCanonicalizeUrl(urlw, (LPWSTR)sBuf, &lpdwBufferLength, 0) ) { pszFunction = L"InternetCanonicalizeUrl"; break; } ATLTRACE(L"Connecting to url: %s\n",(LPWSTR)sBuf); URL_COMPONENTS uri; alloc_url_components(&uri,url); if( !InternetCrackUrl((LPWSTR)sBuf,lpdwBufferLength,0,&uri) ) { pszFunction = L"InternetCrackUrl"; free_url_components(&uri); break; } hConnection = InternetConnect( hInet, uri.lpszHostName, uri.nPort, _T("anonymous"), NULL, INTERNET_SERVICE_HTTP, 0, 0 ); if ( !hConnection ) { pszFunction = L"InternetConnect"; free_url_components(&uri); break; } wsprintf((LPWSTR)sBuf,L"%s%s",uri.lpszUrlPath,uri.lpszExtraInfo); hRequest = HttpOpenRequest( hConnection, verb, (LPWSTR)sBuf, NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_NO_CACHE_WRITE, NULL ); if ( !hRequest ) { pszFunction = L"HttpOpenRequest"; free_url_components(&uri); break; } free_url_components(&uri); //Send data if ( HttpSendRequest( hRequest, NULL, 0, body, body_size) ) { wchar_t res[10]; DWORD dwLen = 10; DWORD nIndex = 0; bool bOk = false; if( HttpQueryInfo(hRequest,HTTP_QUERY_STATUS_CODE,res,&dwLen,&nIndex) ){ if ( wcscmp(res,L"200") == 0 ) bOk = true; else { bOk = false; // If we're unauthorized, delete any cookies that might have been // stored so we don't reuse them later if ( wcscmp(res,L"401") == 0 ) delete_winmo_session(load_source_url()); } } if ( bOk ){ if ( bGetHeaders ){ DWORD dwSize = 0; HttpQueryInfo(hRequest, HTTP_QUERY_RAW_HEADERS, NULL, &dwSize, NULL); if( dwSize != 0 ) { cstr = new char [dwSize+1]; // Call HttpQueryInfo again to get the headers. bOk = (bool) HttpQueryInfoA(hRequest, HTTP_QUERY_RAW_HEADERS, (LPVOID) cstr, &dwSize, NULL); } }else{ BOOL bRead = InternetReadFile(hRequest, &sBuf, sizeof(sBuf), &dwBytesRead); while (bRead && (dwBytesRead > 0)) { data.append(sBuf, dwBytesRead); //data.Append(sBuf, dwBytesRead); bRead = InternetReadFile(hRequest, &sBuf, sizeof(sBuf), &dwBytesRead); } if ( bGetRawData && pdwDataSize ){ cstr = new char [*pdwDataSize]; memcpy (cstr, data.c_str(), *pdwDataSize); } else { //make a copy of recieved data cstr = new char [data.size()+1]; strcpy (cstr, data.c_str()); //cstr = new char [data.GetLength()+1]; //strcpy (cstr, data.GetString()); } } } } else { pszFunction = L"HttpOpenRequest"; } } while(0); if (pszFunction) { ErrorMessage(pszFunction); } if(hRequest) InternetCloseHandle(hRequest); if(hConnection) InternetCloseHandle(hConnection); if(hInet) InternetCloseHandle(hInet); free(urlw); return cstr; }
STDMETHODIMP CXMLHttpRequest::send(VARIANT varBody) { ATLTRACE(_T("CXMLHttpRequest::send\n")); if (V_VT(&varBody) != VT_BSTR && V_VT(&varBody) != VT_DISPATCH && V_VT(&varBody) != (VT_ARRAY | VT_VARIANT) && V_VT(&varBody) != (VT_ARRAY | VT_UI1) && V_VT(&varBody) != VT_UNKNOWN) return E_INVALIDARG; // do not start another thread if there is another active if (NULL != m_hThread) { DWORD exitCode = 0; BOOL rc = ::GetExitCodeThread(m_hThread, &exitCode); if (!rc || STILL_ACTIVE == exitCode) return E_PENDING; ::CloseHandle(m_hThread); m_hThread = NULL; } HRESULT hr = S_OK; m_bSuccess = true; m_bAbort = false; delete [] m_pBody; m_pBody = NULL; m_lBodyLength = 0; delete [] m_pResponseBody; m_pResponseBody = NULL; m_lResponseBodyLength = 0; m_dwStatus = 0; m_StatusText = _T(""); m_ResponseHeaders = _T(""); if (V_VT(&varBody) == VT_BSTR) { _bstr_t body = V_BSTR(&varBody); m_lBodyLength = body.length() + 1; m_pBody = new BYTE[m_lBodyLength]; memset(m_pBody,0,m_lBodyLength); memcpy(m_pBody,static_cast<char*> (body),body.length()); } else if (V_VT(&varBody) == VT_UNKNOWN) { CComQIPtr<IStream,&IID_IStream> pS(V_UNKNOWN(&varBody)); if (!pS) return E_INVALIDARG; CComBSTR b; hr = b.ReadFromStream(pS); if (S_OK != hr) return hr; _bstr_t body = b; m_lBodyLength = body.length() + 1; m_pBody = new BYTE[m_lBodyLength]; memset(m_pBody,0,m_lBodyLength); memcpy(m_pBody,static_cast<char*> (body),body.length()); } else if (V_VT(&varBody) == VT_DISPATCH) { CComQIPtr<IXMLDOMDocument,&IID_IXMLDOMDocument> pDoc(V_DISPATCH(&varBody)); if (!pDoc) return E_INVALIDARG; BSTR b = NULL; hr = pDoc->get_xml(&b); if (S_OK != hr) return hr; _bstr_t body = b; ::SysFreeString(b); m_lBodyLength = body.length() + 1; m_pBody = new BYTE[m_lBodyLength]; memset(m_pBody,0,m_lBodyLength); memcpy(m_pBody,static_cast<char*> (body),body.length()); } else if (V_VT(&varBody) == (VT_ARRAY | VT_VARIANT)) { SAFEARRAY *pArray = reinterpret_cast<SAFEARRAY *> (varBody.byref); if (NULL == pArray) return E_INVALIDARG; long lLBoundVar = 0; long lUBoundVar = 0; UINT dims = ::SafeArrayGetDim(pArray); if (dims == 0) return E_INVALIDARG; hr = ::SafeArrayGetLBound(pArray, dims, &lLBoundVar); if (S_OK != hr) return hr; hr = ::SafeArrayGetUBound(pArray, dims, &lUBoundVar); if (S_OK != hr) return hr; if (lUBoundVar >= lLBoundVar) { VARIANT *pIndex = NULL; hr = ::SafeArrayAccessData(pArray, reinterpret_cast<void **> (&pIndex)); if (S_OK != hr) return hr; m_lBodyLength = lUBoundVar-lLBoundVar+1; m_pBody = new BYTE[m_lBodyLength]; for (long i = 0; i <= lUBoundVar-lLBoundVar; ++i) { VARIANT var = pIndex[i]; if (V_VT(&var) != VT_UI1) { hr = E_INVALIDARG; break; } m_pBody[i] = V_UI1(&var); } ::SafeArrayUnaccessData(pArray); if (S_OK != hr) { delete [] m_pBody; m_pBody = NULL; m_lBodyLength = 0; return hr; } } } else if (V_VT(&varBody) == (VT_ARRAY | VT_UI1)) { SAFEARRAY *pArray = reinterpret_cast<SAFEARRAY *> (varBody.byref); if (NULL == pArray) return E_INVALIDARG; long lLBoundVar = 0; long lUBoundVar = 0; UINT dims = ::SafeArrayGetDim(pArray); if (dims == 0) return E_INVALIDARG; hr = ::SafeArrayGetLBound(pArray, dims, &lLBoundVar); if (S_OK != hr) return hr; hr = ::SafeArrayGetUBound(pArray, dims, &lUBoundVar); if (S_OK != hr) return hr; if (lUBoundVar >= lLBoundVar) { BYTE *pIndex = NULL; hr = ::SafeArrayAccessData(pArray, reinterpret_cast<void **> (&pIndex)); if (S_OK != hr) return hr; m_lBodyLength = lUBoundVar-lLBoundVar+1; m_pBody = new BYTE[m_lBodyLength]; for (long i = 0; i <= lUBoundVar-lLBoundVar; ++i) m_pBody[i] = pIndex[i]; ::SafeArrayUnaccessData(pArray); } } m_HwndParent = GetParentWindow(); UINT nthreadID = 0; m_hThread = reinterpret_cast<HANDLE> (_beginthreadex(NULL, 0, CXMLHttpRequest::SendThread, (void *) this, 0, &nthreadID)); if (NULL == m_hThread) return E_FAIL; if (m_bAsync) return S_OK; bool bWait = true; while (bWait) { DWORD dwEvt = MsgWaitForMultipleObjects(1,&m_hThread,FALSE,INFINITE,QS_ALLINPUT); switch(dwEvt) { case WAIT_OBJECT_0: bWait = false; break; case WAIT_OBJECT_0 + 1: { MSG msg; while(::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { if (WM_CLOSE == msg.message || WM_QUIT == msg.message) { bWait = false; m_bAbort = true; break; } else { PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); TranslateMessage(&msg); DispatchMessage(&msg); } } break; } default: m_bAbort = true; bWait = false; break; } } return S_OK; }
DDEClientTransactionManager::~DDEClientTransactionManager(void) { ATLTRACE( _T("DDEClientTransactionManager::~DDEClientTransactionManager();\n") ); }
UINT APIENTRY CXMLHttpRequest::SendThread(void *pParm) { ATLTRACE(_T("CXMLHttpRequest::SendThread\n")); CXMLHttpRequest *pCtx = reinterpret_cast<CXMLHttpRequest *> (pParm); if (NULL == pCtx) return 0; HINTERNET hOpen = NULL; HINTERNET hConnect = NULL; HINTERNET hRequest = NULL; hOpen = InternetOpen(_T("XMLHTTP/1.0"),INTERNET_OPEN_TYPE_PRECONFIG, NULL,NULL,0); if (NULL == hOpen) { DWORD res = GetLastError(); pCtx->m_Error = CXMLHttpRequest::GetErrorMsg(res); pCtx->m_bSuccess = false; } if (!pCtx->m_bAbort && pCtx->m_bSuccess) { if (INTERNET_INVALID_STATUS_CALLBACK == InternetSetStatusCallback(hOpen, CXMLHttpRequest::InternetStatusCallback)) { pCtx->m_Error = _T("Invalid Internet Status Callback function."); pCtx->m_bSuccess = false; } } bool bPromptForAuthentication = true; if (!pCtx->m_bAbort && pCtx->m_bSuccess) { LPTSTR lpszUserName = NULL; LPTSTR lpszPassword = NULL; if (pCtx->m_User.length() > 0) { bPromptForAuthentication = false; lpszUserName = pCtx->m_User; if (pCtx->m_Password.length() > 0) lpszPassword = pCtx->m_Password; } hConnect = InternetConnect(hOpen,pCtx->m_HostName,pCtx->m_Port,lpszUserName,lpszPassword, INTERNET_SERVICE_HTTP,0,reinterpret_cast<DWORD> (pCtx)); if (NULL == hConnect) { DWORD res = GetLastError(); pCtx->m_Error = CXMLHttpRequest::GetErrorMsg(res); pCtx->m_bSuccess = false; } } if (!pCtx->m_bAbort && pCtx->m_bSuccess) { DWORD dwFlags = (443 == pCtx->m_Port) ? INTERNET_FLAG_SECURE : 0; dwFlags |= INTERNET_FLAG_NO_CACHE_WRITE; hRequest = HttpOpenRequest(hConnect,pCtx->m_Method, pCtx->m_URLPath,NULL,NULL,NULL, dwFlags,reinterpret_cast<DWORD> (pCtx)); if (NULL == hRequest) { DWORD res = GetLastError(); pCtx->m_bSuccess = false; pCtx->m_Error = CXMLHttpRequest::GetErrorMsg(res); } } BOOL rc = TRUE; if (!pCtx->m_bAbort && pCtx->m_bSuccess && pCtx->m_RequestHeaderMap.GetSize() > 0) { _bstr_t requestHeaders; for (int i = 0 ; i < pCtx->m_RequestHeaderMap.GetSize(); ++i) { requestHeaders += pCtx->m_RequestHeaderMap.GetKeyAt(i); requestHeaders += _T(": "); requestHeaders += pCtx->m_RequestHeaderMap.GetValueAt(i); requestHeaders += _T("\r\n"); } rc = HttpAddRequestHeaders(hRequest,requestHeaders,-1,HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); if (!rc) { DWORD res = GetLastError(); pCtx->m_bSuccess = false; pCtx->m_Error = CXMLHttpRequest::GetErrorMsg(res); } } DWORD dwLen = 0; DWORD dwError = ERROR_SUCCESS; do { if (!pCtx->m_bAbort && pCtx->m_bSuccess) { rc = HttpSendRequest(hRequest,NULL,0,pCtx->m_pBody,pCtx->m_lBodyLength); if (!rc) { DWORD res = GetLastError(); pCtx->m_bSuccess = false; pCtx->m_Error = CXMLHttpRequest::GetErrorMsg(res); break; } } if (!pCtx->m_bAbort && pCtx->m_bSuccess) { dwLen = sizeof(DWORD); rc = HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &pCtx->m_dwStatus,&dwLen,NULL); if (!rc) { DWORD res = GetLastError(); pCtx->m_bSuccess = false; pCtx->m_Error = CXMLHttpRequest::GetErrorMsg(res); break; } } if (!pCtx->m_bAbort && pCtx->m_bSuccess && bPromptForAuthentication && (HTTP_STATUS_PROXY_AUTH_REQ == pCtx->m_dwStatus || HTTP_STATUS_DENIED == pCtx->m_dwStatus)) dwError = InternetErrorDlg(pCtx->m_HwndParent, hRequest, ERROR_INTERNET_INCORRECT_PASSWORD, FLAGS_ERROR_UI_FILTER_FOR_ERRORS | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS | FLAGS_ERROR_UI_FLAGS_GENERATE_DATA, NULL); else break; } while (ERROR_INTERNET_FORCE_RETRY == dwError && !pCtx->m_bAbort && pCtx->m_bSuccess); if (!pCtx->m_bAbort && pCtx->m_bSuccess) { dwLen = 1024; TCHAR *pBuff = new TCHAR[dwLen]; rc = HttpQueryInfo(hRequest,HTTP_QUERY_RAW_HEADERS_CRLF,pBuff,&dwLen,NULL); if (!rc) { DWORD res = GetLastError(); if (ERROR_INSUFFICIENT_BUFFER == res) { delete [] pBuff; pBuff = new TCHAR[dwLen]; rc = HttpQueryInfo(hRequest,HTTP_QUERY_RAW_HEADERS_CRLF,pBuff,&dwLen,NULL); if (!rc) { res = GetLastError(); pCtx->m_bSuccess = false; pCtx->m_Error = CXMLHttpRequest::GetErrorMsg(res); } } else { pCtx->m_bSuccess = false; pCtx->m_Error = CXMLHttpRequest::GetErrorMsg(res); } } if (rc) pCtx->m_ResponseHeaders = pBuff; delete [] pBuff; } if (!pCtx->m_bAbort && pCtx->m_bSuccess) { dwLen = 1024; TCHAR *pBuff = new TCHAR[dwLen]; rc = HttpQueryInfo(hRequest,HTTP_QUERY_STATUS_TEXT,pBuff,&dwLen,NULL); if (!rc) { DWORD res = GetLastError(); if (ERROR_INSUFFICIENT_BUFFER == res) { delete [] pBuff; pBuff = new TCHAR[dwLen]; rc = HttpQueryInfo(hRequest,HTTP_QUERY_STATUS_TEXT,pBuff,&dwLen,NULL); if (!rc) _tcscpy(pBuff,_T("Unknown")); } else _tcscpy(pBuff,_T("Unknown")); } pCtx->m_StatusText = pBuff; delete [] pBuff; if (HTTP_STATUS_OK != pCtx->m_dwStatus) { TCHAR errBuff[MAX_PATH] = _T(""); wsprintf(errBuff,_T("HTTP Status Code: %d, Reason: "),pCtx->m_dwStatus); pCtx->m_Error = errBuff; pCtx->m_Error += pCtx->m_StatusText; pCtx->m_bSuccess = false; } } if (!pCtx->m_bAbort && pCtx->m_bSuccess) { PBYTE buffer[255]; DWORD dwRead = 0; delete [] pCtx->m_pResponseBody; pCtx->m_pResponseBody = NULL; pCtx->m_lResponseBodyLength = 0; while (rc = InternetReadFile(hRequest,buffer,255,&dwRead)) { if (!rc || pCtx->m_bAbort || 0 == dwRead) break; PBYTE tmp = new BYTE[pCtx->m_lResponseBodyLength + dwRead]; if (pCtx->m_pResponseBody) { memcpy(tmp,pCtx->m_pResponseBody,pCtx->m_lResponseBodyLength); delete [] pCtx->m_pResponseBody; } memcpy(tmp+pCtx->m_lResponseBodyLength,buffer,dwRead); pCtx->m_pResponseBody = tmp; pCtx->m_lResponseBodyLength += dwRead; } if (!rc) { DWORD res = GetLastError(); pCtx->m_Error = _T("Error reading response: ") + CXMLHttpRequest::GetErrorMsg(res); pCtx->m_bSuccess = false; } } if (hRequest != NULL) InternetCloseHandle(hRequest); if (hConnect != NULL) InternetCloseHandle(hConnect); if (hOpen) InternetCloseHandle(hOpen); if (!pCtx->m_bAbort && pCtx->m_bAsync) ::PostMessage(pCtx->m_hWnd,MSG_READY_STATE_CHANGE,4,0); return 0; }
void CFolderCrawler::WorkerThread() { HANDLE hWaitHandles[2]; hWaitHandles[0] = m_hTerminationEvent; hWaitHandles[1] = m_hWakeEvent; CTGitPath workingPath; bool bFirstRunAfterWakeup = false; DWORD currentTicks = 0; // Quick check if we're on Vista OSVERSIONINFOEX inf; SecureZeroMemory(&inf, sizeof(OSVERSIONINFOEX)); inf.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); GetVersionEx((OSVERSIONINFO *)&inf); WORD fullver = MAKEWORD(inf.dwMinorVersion, inf.dwMajorVersion); for(;;) { bool bRecursive = !!(DWORD)CRegStdDWORD(_T("Software\\TortoiseGit\\RecursiveOverlay"), TRUE); if (fullver >= 0x0600) { SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END); } DWORD waitResult = WaitForMultipleObjects(_countof(hWaitHandles), hWaitHandles, FALSE, INFINITE); // exit event/working loop if the first event (m_hTerminationEvent) // has been signaled or if one of the events has been abandoned // (i.e. ~CFolderCrawler() is being executed) if(m_bRun == false || waitResult == WAIT_OBJECT_0 || waitResult == WAIT_ABANDONED_0 || waitResult == WAIT_ABANDONED_0+1) { // Termination event break; } if (fullver >= 0x0600) { SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN); } // If we get here, we've been woken up by something being added to the queue. // However, it's important that we don't do our crawling while // the shell is still asking for items bFirstRunAfterWakeup = true; for(;;) { if (!m_bRun) break; // Any locks today? if (CGitStatusCache::Instance().m_bClearMemory) { CGitStatusCache::Instance().WaitToWrite(); CGitStatusCache::Instance().ClearCache(); CGitStatusCache::Instance().Done(); CGitStatusCache::Instance().m_bClearMemory = false; } if(m_lCrawlInhibitSet > 0) { // We're in crawl hold-off ATLTRACE("Crawl hold-off\n"); Sleep(50); continue; } if (bFirstRunAfterWakeup) { Sleep(20); ATLTRACE("Crawl bFirstRunAfterWakeup\n"); bFirstRunAfterWakeup = false; continue; } if ((m_blockReleasesAt < GetTickCount())&&(!m_blockedPath.IsEmpty())) { ATLTRACE(_T("Crawl stop blocking path %s\n"), m_blockedPath.GetWinPath()); m_blockedPath.Reset(); } if ((m_foldersToUpdate.empty())&&(m_pathsToUpdate.empty())) { // Nothing left to do break; } currentTicks = GetTickCount(); if (!m_pathsToUpdate.empty()) { { AutoLocker lock(m_critSec); m_bPathsAddedSinceLastCrawl = false; workingPath = m_pathsToUpdate.front(); //m_pathsToUpdateUnique.erase (workingPath); m_pathsToUpdate.pop_front(); if ((DWORD(workingPath.GetCustomData()) >= currentTicks) || ((!m_blockedPath.IsEmpty())&&(m_blockedPath.IsAncestorOf(workingPath)))) { // move the path to the end of the list //m_pathsToUpdateUnique.insert (workingPath); m_pathsToUpdate.push_back(workingPath); if (m_pathsToUpdate.size() < 3) Sleep(50); continue; } } // don't crawl paths that are excluded if (!CGitStatusCache::Instance().IsPathAllowed(workingPath)) continue; // check if the changed path is inside an .git folder CString projectroot; if ((workingPath.HasAdminDir(&projectroot)&&workingPath.IsDirectory()) || workingPath.IsAdminDir()) { // we don't crawl for paths changed in a tmp folder inside an .git folder. // Because we also get notifications for those even if we just ask for the status! // And changes there don't affect the file status at all, so it's safe // to ignore notifications on those paths. if (workingPath.IsAdminDir()) { // TODO: add git specific filters here. is there really any change besides index file in .git // that is relevant for overlays? /*CString lowerpath = workingPath.GetWinPathString(); lowerpath.MakeLower(); if (lowerpath.Find(_T("\\tmp\\"))>0) continue; if (lowerpath.Find(_T("\\tmp")) == (lowerpath.GetLength()-4)) continue; if (lowerpath.Find(_T("\\log"))>0) continue;*/ // Here's a little problem: // the lock file is also created for fetching the status // and not just when committing. // If we could find out why the lock file was changed // we could decide to crawl the folder again or not. // But for now, we have to crawl the parent folder // no matter what. //if (lowerpath.Find(_T("\\lock"))>0) // continue; } else if (!workingPath.Exists()) { CGitStatusCache::Instance().WaitToWrite(); CGitStatusCache::Instance().RemoveCacheForPath(workingPath); CGitStatusCache::Instance().Done(); continue; } do { workingPath = workingPath.GetContainingDirectory(); } while(workingPath.IsAdminDir()); ATLTRACE(_T("Invalidating and refreshing folder: %s\n"), workingPath.GetWinPath()); { AutoLocker print(critSec); _stprintf_s(szCurrentCrawledPath[nCurrentCrawledpathIndex], MAX_CRAWLEDPATHSLEN, _T("Invalidating and refreshing folder: %s"), workingPath.GetWinPath()); nCurrentCrawledpathIndex++; if (nCurrentCrawledpathIndex >= MAX_CRAWLEDPATHS) nCurrentCrawledpathIndex = 0; } InvalidateRect(hWnd, NULL, FALSE); CGitStatusCache::Instance().WaitToRead(); // Invalidate the cache of this folder, to make sure its status is fetched again. CCachedDirectory * pCachedDir = CGitStatusCache::Instance().GetDirectoryCacheEntry(workingPath); if (pCachedDir) { git_wc_status_kind status = pCachedDir->GetCurrentFullStatus(); pCachedDir->Invalidate(); if (workingPath.Exists()) { pCachedDir->RefreshStatus(bRecursive); // if the previous status wasn't normal and now it is, then // send a notification too. // We do this here because GetCurrentFullStatus() doesn't send // notifications for 'normal' status - if it would, we'd get tons // of notifications when crawling a working copy not yet in the cache. if ((status != git_wc_status_normal)&&(pCachedDir->GetCurrentFullStatus() != status)) { CGitStatusCache::Instance().UpdateShell(workingPath); ATLTRACE(_T("shell update in crawler for %s\n"), workingPath.GetWinPath()); } } else { CGitStatusCache::Instance().Done(); CGitStatusCache::Instance().WaitToWrite(); CGitStatusCache::Instance().RemoveCacheForPath(workingPath); } } CGitStatusCache::Instance().Done(); //In case that svn_client_stat() modified a file and we got //a notification about that in the directory watcher, //remove that here again - this is to prevent an endless loop AutoLocker lock(m_critSec); m_pathsToUpdate.erase(std::remove(m_pathsToUpdate.begin(), m_pathsToUpdate.end(), workingPath), m_pathsToUpdate.end()); } else if (workingPath.HasAdminDir()) { if (!workingPath.Exists()) { CGitStatusCache::Instance().WaitToWrite(); CGitStatusCache::Instance().RemoveCacheForPath(workingPath); CGitStatusCache::Instance().Done(); continue; } if (!workingPath.Exists()) continue; ATLTRACE(_T("Updating path: %s\n"), workingPath.GetWinPath()); { AutoLocker print(critSec); _stprintf_s(szCurrentCrawledPath[nCurrentCrawledpathIndex], MAX_CRAWLEDPATHSLEN, _T("Updating path: %s"), workingPath.GetWinPath()); nCurrentCrawledpathIndex++; if (nCurrentCrawledpathIndex >= MAX_CRAWLEDPATHS) nCurrentCrawledpathIndex = 0; } InvalidateRect(hWnd, NULL, FALSE); // HasAdminDir() already checks if the path points to a dir DWORD flags = TGITCACHE_FLAGS_FOLDERISKNOWN; flags |= (workingPath.IsDirectory() ? TGITCACHE_FLAGS_ISFOLDER : 0); flags |= (bRecursive ? TGITCACHE_FLAGS_RECUSIVE_STATUS : 0); CGitStatusCache::Instance().WaitToRead(); // Invalidate the cache of folders manually. The cache of files is invalidated // automatically if the status is asked for it and the file times don't match // anymore, so we don't need to manually invalidate those. if (workingPath.IsDirectory()) { CCachedDirectory * cachedDir = CGitStatusCache::Instance().GetDirectoryCacheEntry(workingPath); if (cachedDir) cachedDir->Invalidate(); } CStatusCacheEntry ce = CGitStatusCache::Instance().GetStatusForPath(workingPath, flags); if (ce.GetEffectiveStatus() > git_wc_status_unversioned) { CGitStatusCache::Instance().UpdateShell(workingPath); ATLTRACE(_T("shell update in folder crawler for %s\n"), workingPath.GetWinPath()); } CGitStatusCache::Instance().Done(); AutoLocker lock(m_critSec); m_pathsToUpdate.erase(std::remove(m_pathsToUpdate.begin(), m_pathsToUpdate.end(), workingPath), m_pathsToUpdate.end()); } else { if (!workingPath.Exists()) { CGitStatusCache::Instance().WaitToWrite(); CGitStatusCache::Instance().RemoveCacheForPath(workingPath); CGitStatusCache::Instance().Done(); } } } else if (!m_foldersToUpdate.empty()) { { AutoLocker lock(m_critSec); m_bItemsAddedSinceLastCrawl = false; // create a new CTSVNPath object to make sure the cached flags are requested again. // without this, a missing file/folder is still treated as missing even if it is available // now when crawling. CTGitPath& folderToUpdate = m_foldersToUpdate.front(); workingPath = CTGitPath(folderToUpdate.GetWinPath()); workingPath.SetCustomData(folderToUpdate.GetCustomData()); m_foldersToUpdate.pop_front(); if ((DWORD(workingPath.GetCustomData()) >= currentTicks) || ((!m_blockedPath.IsEmpty())&&(m_blockedPath.IsAncestorOf(workingPath)))) { // move the path to the end of the list m_foldersToUpdate.push_back (workingPath); if (m_foldersToUpdate.size() < 3) Sleep(50); continue; } } if (DWORD(workingPath.GetCustomData()) >= currentTicks) { Sleep(50); continue; } if ((!m_blockedPath.IsEmpty())&&(m_blockedPath.IsAncestorOf(workingPath))) continue; if (!CGitStatusCache::Instance().IsPathAllowed(workingPath)) continue; ATLTRACE(_T("Crawling folder: %s\n"), workingPath.GetWinPath()); { AutoLocker print(critSec); _stprintf_s(szCurrentCrawledPath[nCurrentCrawledpathIndex], MAX_CRAWLEDPATHSLEN, _T("Crawling folder: %s"), workingPath.GetWinPath()); nCurrentCrawledpathIndex++; if (nCurrentCrawledpathIndex >= MAX_CRAWLEDPATHS) nCurrentCrawledpathIndex = 0; } InvalidateRect(hWnd, NULL, FALSE); CGitStatusCache::Instance().WaitToRead(); // Now, we need to visit this folder, to make sure that we know its 'most important' status CCachedDirectory * cachedDir = CGitStatusCache::Instance().GetDirectoryCacheEntry(workingPath.GetDirectory()); // check if the path is monitored by the watcher. If it isn't, then we have to invalidate the cache // for that path and add it to the watcher. if (!CGitStatusCache::Instance().IsPathWatched(workingPath)) { if (workingPath.HasAdminDir()) { ATLTRACE(_T("Add watch path %s\n"), workingPath.GetWinPath()); CGitStatusCache::Instance().AddPathToWatch(workingPath); } if (cachedDir) cachedDir->Invalidate(); else { CGitStatusCache::Instance().Done(); CGitStatusCache::Instance().WaitToWrite(); CGitStatusCache::Instance().RemoveCacheForPath(workingPath); } } if (cachedDir) cachedDir->RefreshStatus(bRecursive); #if 0 // While refreshing the status, we could get another crawl request for the same folder. // This can happen if the crawled folder has a lower status than one of the child folders // (recursively). To avoid double crawlings, remove such a crawl request here AutoLocker lock(m_critSec); if (m_bItemsAddedSinceLastCrawl) { if (m_foldersToUpdate.back().IsEquivalentToWithoutCase(workingPath)) { m_foldersToUpdate.pop_back(); m_bItemsAddedSinceLastCrawl = false; } } #endif CGitStatusCache::Instance().Done(); } } } _endthread(); }
STDMETHODIMP CXMLHttpRequest::abort() { ATLTRACE(_T("CXMLHttpRequest::abort\n")); m_bAbort = true; return S_OK; }
STDMETHODIMP CBindStatCallback::OnStopBinding(HRESULT hresult, LPCWSTR szError) { ATLTRACE(_T("CBindStatCallback::OnStopBinding\n")); return S_OK; }
bool CCacheDlg::EnsurePipeOpen() { if(m_hPipe != INVALID_HANDLE_VALUE) { return true; } m_hPipe = CreateFile( GetCachePipeName(), // pipe name GENERIC_READ | // read and write access GENERIC_WRITE, 0, // no sharing NULL, // default security attributes OPEN_EXISTING, // opens existing pipe FILE_FLAG_OVERLAPPED, // default attributes NULL); // no template file if (m_hPipe == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PIPE_BUSY) { // TSVNCache is running but is busy connecting a different client. // Do not give up immediately but wait for a few milliseconds until // the server has created the next pipe instance if (WaitNamedPipe(GetCachePipeName(), 50)) { m_hPipe = CreateFile( GetCachePipeName(), // pipe name GENERIC_READ | // read and write access GENERIC_WRITE, 0, // no sharing NULL, // default security attributes OPEN_EXISTING, // opens existing pipe FILE_FLAG_OVERLAPPED, // default attributes NULL); // no template file } } if (m_hPipe != INVALID_HANDLE_VALUE) { // The pipe connected; change to message-read mode. DWORD dwMode; dwMode = PIPE_READMODE_MESSAGE; if(!SetNamedPipeHandleState( m_hPipe, // pipe handle &dwMode, // new pipe mode NULL, // don't set maximum bytes NULL)) // don't set maximum time { ATLTRACE("SetNamedPipeHandleState failed"); CloseHandle(m_hPipe); m_hPipe = INVALID_HANDLE_VALUE; return false; } // create an unnamed (=local) manual reset event for use in the overlapped structure m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (m_hEvent) return true; ATLTRACE("CreateEvent failed"); ClosePipe(); return false; } return false; }
STDMETHODIMP CBindStatCallback::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed) { ATLTRACE(_T("CBindStatCallback::OnDataAvailable\n")); return E_NOTIMPL; }
bool CCacheDlg::GetStatusFromRemoteCache(const CTGitPath& Path, bool bRecursive) { if(!EnsurePipeOpen()) { STARTUPINFO startup; PROCESS_INFORMATION process; memset(&startup, 0, sizeof(startup)); startup.cb = sizeof(startup); memset(&process, 0, sizeof(process)); CString sCachePath = _T("TGitCache.exe"); if (CreateProcess(sCachePath.GetBuffer(sCachePath.GetLength()+1), _T(""), NULL, NULL, FALSE, 0, 0, 0, &startup, &process)==0) { // It's not appropriate to do a message box here, because there may be hundreds of calls sCachePath.ReleaseBuffer(); ATLTRACE("Failed to start cache\n"); return false; } sCachePath.ReleaseBuffer(); // Wait for the cache to open long endTime = (long)GetTickCount()+1000; while(!EnsurePipeOpen()) { if(((long)GetTickCount() - endTime) > 0) { return false; } } } DWORD nBytesRead; TGITCacheRequest request; request.flags = TGITCACHE_FLAGS_NONOTIFICATIONS; if(bRecursive) { request.flags |= TGITCACHE_FLAGS_RECUSIVE_STATUS; } wcsncpy(request.path, Path.GetWinPath(), MAX_PATH); ZeroMemory(&m_Overlapped, sizeof(OVERLAPPED)); m_Overlapped.hEvent = m_hEvent; // Do the transaction in overlapped mode. // That way, if anything happens which might block this call // we still can get out of it. We NEVER MUST BLOCK THE SHELL! // A blocked shell is a very bad user impression, because users // who don't know why it's blocked might find the only solution // to such a problem is a reboot and therefore they might loose // valuable data. // Sure, it would be better to have no situations where the shell // even can get blocked, but the timeout of 5 seconds is long enough // so that users still recognize that something might be wrong and // report back to us so we can investigate further. TGITCacheResponse ReturnedStatus; BOOL fSuccess = TransactNamedPipe(m_hPipe, &request, sizeof(request), &ReturnedStatus, sizeof(ReturnedStatus), &nBytesRead, &m_Overlapped); if (!fSuccess) { if (GetLastError()!=ERROR_IO_PENDING) { ClosePipe(); return false; } // TransactNamedPipe is working in an overlapped operation. // Wait for it to finish DWORD dwWait = WaitForSingleObject(m_hEvent, INFINITE); if (dwWait == WAIT_OBJECT_0) { fSuccess = GetOverlappedResult(m_hPipe, &m_Overlapped, &nBytesRead, FALSE); return TRUE; } else fSuccess = FALSE; } ClosePipe(); return false; }
STDMETHODIMP CBindStatCallback::OnStartBinding(DWORD dwReserved, IBinding *pBinding) { ATLTRACE(_T("CBindStatCallback::OnStartBinding\n")); return S_OK; }
void CCacheDlg::RemoveFromCache(const CString& path) { // if we use the external cache, we tell the cache directly that something // has changed, without the detour via the shell. HANDLE hPipe = CreateFile( GetCacheCommandPipeName(), // pipe name GENERIC_READ | // read and write access GENERIC_WRITE, 0, // no sharing NULL, // default security attributes OPEN_EXISTING, // opens existing pipe FILE_FLAG_OVERLAPPED, // default attributes NULL); // no template file if (hPipe != INVALID_HANDLE_VALUE) { // The pipe connected; change to message-read mode. DWORD dwMode; dwMode = PIPE_READMODE_MESSAGE; if(SetNamedPipeHandleState( hPipe, // pipe handle &dwMode, // new pipe mode NULL, // don't set maximum bytes NULL)) // don't set maximum time { DWORD cbWritten; TGITCacheCommand cmd; cmd.command = TGITCACHECOMMAND_CRAWL; wcsncpy(cmd.path, path, MAX_PATH); BOOL fSuccess = WriteFile( hPipe, // handle to pipe &cmd, // buffer to write from sizeof(cmd), // number of bytes to write &cbWritten, // number of bytes written NULL); // not overlapped I/O if (! fSuccess || sizeof(cmd) != cbWritten) { DisconnectNamedPipe(hPipe); CloseHandle(hPipe); hPipe = INVALID_HANDLE_VALUE; } if (hPipe != INVALID_HANDLE_VALUE) { // now tell the cache we don't need it's command thread anymore DWORD cbWritten; TGITCacheCommand cmd; cmd.command = TGITCACHECOMMAND_END; WriteFile( hPipe, // handle to pipe &cmd, // buffer to write from sizeof(cmd), // number of bytes to write &cbWritten, // number of bytes written NULL); // not overlapped I/O DisconnectNamedPipe(hPipe); CloseHandle(hPipe); hPipe = INVALID_HANDLE_VALUE; } } else { ATLTRACE("SetNamedPipeHandleState failed"); CloseHandle(hPipe); } } }
STDMETHODIMP CBindStatCallback::OnLowResource(DWORD reserved) { ATLTRACE(_T("CBindStatCallback::OnLowResource\n")); return E_NOTIMPL; }
STDMETHODIMP CShellExt::IsMemberOf(LPCWSTR pwszPath, DWORD /*dwAttrib*/) { PreserveChdir preserveChdir; git_wc_status_kind status = git_wc_status_none; bool readonlyoverlay = false; bool lockedoverlay = false; if (pwszPath == NULL) return S_FALSE; const TCHAR* pPath = pwszPath; // the shell sometimes asks overlays for invalid paths, e.g. for network // printers (in that case the path is "0", at least for me here). if (_tcslen(pPath)<2) return S_FALSE; // since the shell calls each and every overlay handler with the same filepath // we use a small 'fast' cache of just one path here. // To make sure that cache expires, clear it as soon as one handler is used. AutoLocker lock(g_csGlobalCOMGuard); if (_tcscmp(pPath, g_filepath.c_str())==0) { status = g_filestatus; readonlyoverlay = g_readonlyoverlay; lockedoverlay = g_lockedoverlay; } else { if (!g_ShellCache.IsPathAllowed(pPath)) { int drivenumber = -1; if ((m_State == FileStateVersioned) && g_ShellCache.ShowExcludedAsNormal() && ((drivenumber=PathGetDriveNumber(pPath))!=0)&&(drivenumber!=1) && PathIsDirectory(pPath) && g_ShellCache.HasSVNAdminDir(pPath, true)) { return S_OK; } return S_FALSE; } switch (g_ShellCache.GetCacheType()) { case ShellCache::exe: { CTGitPath tpath(pPath); if(!tpath.HasAdminDir()) { status = git_wc_status_none; break; } if(tpath.IsAdminDir()) { status = git_wc_status_none; break; } TSVNCacheResponse itemStatus; SecureZeroMemory(&itemStatus, sizeof(itemStatus)); if (m_remoteCacheLink.GetStatusFromRemoteCache(tpath, &itemStatus, true)) { status = GitStatus::GetMoreImportant(itemStatus.m_status.text_status, itemStatus.m_status.prop_status); /* if ((itemStatus.m_kind == git_node_file)&&(status == git_wc_status_normal)&&((itemStatus.m_needslock && itemStatus.m_owner[0]==0)||(itemStatus.m_readonly))) readonlyoverlay = true; if (itemStatus.m_owner[0]!=0) lockedoverlay = true;*/ } } break; case ShellCache::dll: case ShellCache::dllFull: { // Look in our caches for this item const FileStatusCacheEntry * s = m_CachedStatus.GetCachedItem(CTGitPath(pPath)); if (s) { status = s->status; } else { // No cached status available // since the dwAttrib param of the IsMemberOf() function does not // have the SFGAO_FOLDER flag set at all (it's 0 for files and folders!) // we have to check if the path is a folder ourselves :( if (PathIsDirectory(pPath)) { if (g_ShellCache.HasSVNAdminDir(pPath, TRUE)) { if ((!g_ShellCache.IsRecursive()) && (!g_ShellCache.IsFolderOverlay())) { status = git_wc_status_normal; } else { const FileStatusCacheEntry * s = m_CachedStatus.GetFullStatus(CTGitPath(pPath), TRUE); status = s->status; // GitFolderStatus does not list unversioned files/dir so they would always end up as normal below // so let's assume file/dir is unversioned if not found in cache /*// sub-dirs that are empty (or contain no versioned files) are reported as unversioned (and should be kept as such) if (status != git_wc_status_unversioned) { // if get status fails then display status as 'normal' on folder (since it contains .git) // TODO: works for svn since each folder has .svn, not sure if git needs additinoal processing status = GitStatus::GetMoreImportant(git_wc_status_normal, status); }*/ } } else { status = git_wc_status_none; } } else { const FileStatusCacheEntry * s = m_CachedStatus.GetFullStatus(CTGitPath(pPath), FALSE); status = s->status; } } #if 0 if ((s)&&(status == git_wc_status_normal)&&(s->needslock)&&(s->owner[0]==0)) readonlyoverlay = true; if ((s)&&(s->owner[0]!=0)) lockedoverlay = true; #endif } break; default: case ShellCache::none: { // no cache means we only show a 'versioned' overlay on folders // with an admin directory if (PathIsDirectory(pPath)) { if (g_ShellCache.HasSVNAdminDir(pPath, TRUE)) { status = git_wc_status_normal; } else { status = git_wc_status_none; } } else { status = git_wc_status_none; } } break; } ATLTRACE(_T("Status %d for file %s\n"), status, pwszPath); } g_filepath.clear(); g_filepath = pPath; g_filestatus = status; g_readonlyoverlay = readonlyoverlay; g_lockedoverlay = lockedoverlay; //the priority system of the shell doesn't seem to work as expected (or as I expected): //as it seems that if one handler returns S_OK then that handler is used, no matter //if other handlers would return S_OK too (they're never called on my machine!) //So we return S_OK for ONLY ONE handler! switch (status) { // note: we can show other overlays if due to lack of enough free overlay // slots some of our overlays aren't loaded. But we assume that // at least the 'normal' and 'modified' overlay are available. case git_wc_status_none: return S_FALSE; case git_wc_status_unversioned: if (g_ShellCache.ShowUnversionedOverlay() && g_unversionedovlloaded && (m_State == FileStateUnversionedOverlay)) { g_filepath.clear(); return S_OK; } return S_FALSE; case git_wc_status_ignored: if (g_ShellCache.ShowIgnoredOverlay() && g_ignoredovlloaded && (m_State == FileStateIgnoredOverlay)) { g_filepath.clear(); return S_OK; } return S_FALSE; case git_wc_status_normal: case git_wc_status_external: case git_wc_status_incomplete: if ((readonlyoverlay)&&(g_readonlyovlloaded)) { if (m_State == FileStateReadOnly) { g_filepath.clear(); return S_OK; } else return S_FALSE; } else if ((lockedoverlay)&&(g_lockedovlloaded)) { if (m_State == FileStateLockedOverlay) { g_filepath.clear(); return S_OK; } else return S_FALSE; } else if (m_State == FileStateVersioned) { g_filepath.clear(); return S_OK; } else return S_FALSE; case git_wc_status_missing: case git_wc_status_deleted: if (g_deletedovlloaded) { if (m_State == FileStateDeleted) { g_filepath.clear(); return S_OK; } else return S_FALSE; } else { // the 'deleted' overlay isn't available (due to lack of enough // overlay slots). So just show the 'modified' overlay instead. if (m_State == FileStateModified) { g_filepath.clear(); return S_OK; } else return S_FALSE; } case git_wc_status_replaced: case git_wc_status_modified: if (m_State == FileStateModified) { g_filepath.clear(); return S_OK; } else return S_FALSE; case git_wc_status_merged: if (m_State == FileStateReadOnly) { g_filepath.clear(); return S_OK; } else return S_FALSE; case git_wc_status_added: if (g_addedovlloaded) { if (m_State== FileStateAddedOverlay) { g_filepath.clear(); return S_OK; } else return S_FALSE; } else { // the 'added' overlay isn't available (due to lack of enough // overlay slots). So just show the 'modified' overlay instead. if (m_State == FileStateModified) { g_filepath.clear(); return S_OK; } else return S_FALSE; } case git_wc_status_conflicted: case git_wc_status_obstructed: if (g_conflictedovlloaded) { if (m_State == FileStateConflict) { g_filepath.clear(); return S_OK; } else return S_FALSE; } else { // the 'conflicted' overlay isn't available (due to lack of enough // overlay slots). So just show the 'modified' overlay instead. if (m_State == FileStateModified) { g_filepath.clear(); return S_OK; } else return S_FALSE; } default: return S_FALSE; } // switch (status) //return S_FALSE; }