Example #1
0
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;
}
Example #2
0
STDMETHODIMP CBindStatCallback::OnObjectAvailable(REFIID riid, IUnknown *punk)
{
	ATLTRACE(_T("CBindStatCallback::OnObjectAvailable\n"));
	return E_NOTIMPL;
}
Example #3
0
STDMETHODIMP CBindStatCallback::GetPriority(LONG *pnPriority)
{
	ATLTRACE(_T("CBindStatCallback::GetPriority\n"));
	return E_NOTIMPL;
}
Example #4
0
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;
}
Example #5
0
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") );
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #10
0
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);
}
Example #11
0
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)
}
Example #12
0
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;
}
Example #13
0
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();
}
Example #14
0
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;
}
Example #15
0
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;
}
Example #16
0
void ClearResultCache()
{
    ATLTRACE(_T("Result cache before clearing(size=%u)\r\n"), ResultCache.Size());
    ResultCache.Clear();
}
Example #17
0
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;
}
Example #23
0
STDMETHODIMP CBindStatCallback::OnStopBinding(HRESULT hresult, LPCWSTR szError)
{
	ATLTRACE(_T("CBindStatCallback::OnStopBinding\n"));
	return S_OK;
}
Example #24
0
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;
}
Example #25
0
STDMETHODIMP CBindStatCallback::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
{
	ATLTRACE(_T("CBindStatCallback::OnDataAvailable\n"));
	return E_NOTIMPL;
}
Example #26
0
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;
}
Example #27
0
STDMETHODIMP CBindStatCallback::OnStartBinding(DWORD dwReserved, IBinding *pBinding)
{
	ATLTRACE(_T("CBindStatCallback::OnStartBinding\n"));
	return S_OK;
}
Example #28
0
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);
		}
	}
}
Example #29
0
STDMETHODIMP CBindStatCallback::OnLowResource(DWORD reserved)
{
	ATLTRACE(_T("CBindStatCallback::OnLowResource\n"));
	return E_NOTIMPL;
}
Example #30
0
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;
}