Просмотр исходного кода

Added the ability to paste as admin, this will allow ditto to paste into applications running has admin, currently it won't paste in them

git-svn-id: svn://svn.code.sf.net/p/ditto-cp/code/trunk@686 595ec19a-5cb4-439b-94a8-42fb3063c22c
sabrogden 12 лет назад
Родитель
Сommit
fbbe806a89
14 измененных файлов с 296 добавлено и 15 удалено
  1. 57 0
      CP_Main.cpp
  2. 6 0
      CP_Main.h
  3. 4 0
      CP_Main.vcxproj
  4. 30 6
      CP_Main.vcxproj.filters
  5. 17 3
      EventThread.cpp
  6. 5 0
      EventThread.h
  7. 12 5
      ExternalWindowTracker.cpp
  8. 2 1
      Misc.cpp
  9. 10 0
      Options.cpp
  10. 3 0
      Options.h
  11. 12 0
      UAC_Helper.cpp
  12. 8 0
      UAC_Helper.h
  13. 93 0
      UAC_Thread.cpp
  14. 37 0
      UAC_Thread.h

+ 57 - 0
CP_Main.cpp

@@ -32,6 +32,7 @@ public:
 		m_bU3 = FALSE;
 		m_bU3Stop = FALSE;
 		m_bU3Install = FALSE;
+		m_uacPID = 0;
 	}
 
  	virtual void ParseParam(const TCHAR* pszParam, BOOL bFlag, BOOL bLast)
@@ -58,6 +59,16 @@ public:
   			{
   				m_bU3Install = TRUE;
   			}
+			else if(wcsncmp(pszParam, _T("uacpaste"), 8) == 0)
+			{
+				CString pidCommand(pszParam);
+				long sep = pidCommand.ReverseFind(':');
+				if(sep > -1)
+				{
+					CString pid = pidCommand.Right(pidCommand.GetLength() - sep - 1);
+					m_uacPID = ATOI(pid);
+				}
+			}
   		}
  
 		CCommandLineInfo::ParseParam(pszParam, bFlag, bLast);
@@ -68,6 +79,7 @@ public:
 	BOOL m_bU3;
 	BOOL m_bU3Stop;
 	BOOL m_bU3Install;
+	int m_uacPID;
 };
 
 CCP_MainApp theApp;
@@ -83,6 +95,7 @@ CCP_MainApp::CCP_MainApp()
 {
 	theApp.m_activeWnd.TrackActiveWnd(false);
 
+	m_pUacPasteThread = NULL;
 	m_bAppRunning = false;
 	m_bAppExiting = false;
 	m_connectOnStartup = -1;
@@ -146,6 +159,21 @@ BOOL CCP_MainApp::InitInstance()
 
 	g_Opt.LoadSettings();
 
+	if(cmdInfo.m_uacPID > 0)
+	{
+		Log(StrF(_T("Startup up ditto as admin to paste to admin windows, parent process id: %d"), cmdInfo.m_uacPID));
+
+		CString mutex;
+		mutex.Format(_T("DittoAdminPaste_%d"), cmdInfo.m_uacPID);
+		m_adminPasteMutex = CreateMutex(NULL, FALSE, mutex);
+
+		m_pUacPasteThread = new CUAC_Thread(cmdInfo.m_uacPID);
+		m_pUacPasteThread->Start();
+		m_pUacPasteThread->WaitForThreadToExit(INT_MAX);
+
+		return FALSE;
+	}
+
 	if(cmdInfo.m_strFileName.IsEmpty() == FALSE)
 	{
 		try
@@ -788,6 +816,15 @@ int CCP_MainApp::ExitInstance()
 
 	m_db.close();
 
+	if(m_pUacPasteThread != NULL)
+	{
+		if(m_pUacPasteThread->ThreadWasStarted() == false)
+		{
+			m_pUacPasteThread->FireExit();
+		}
+		delete m_pUacPasteThread;
+	}
+
 	Gdiplus::GdiplusShutdown(m_gdiplusToken);
 
 	return CWinApp::ExitInstance();
@@ -991,4 +1028,24 @@ CQPasteWnd* CCP_MainApp::QPasteWnd()
 	}
 
 	return NULL;
+}
+
+void CCP_MainApp::UACPaste()
+{
+	if(m_pUacPasteThread == NULL)
+	{
+		m_pUacPasteThread = new CUAC_Thread(GetCurrentProcessId());
+	}
+
+	m_pUacPasteThread->UACPaste();
+}
+
+bool CCP_MainApp::UACThreadRunning()
+{
+	if(m_pUacPasteThread != NULL)
+	{
+		return m_pUacPasteThread->IsRunning();
+	}
+
+	return false;
 }

+ 6 - 0
CP_Main.h

@@ -21,6 +21,7 @@
 #include "externalwindowtracker.h"
 #include "HotKeys.h"
 #include "DPI.h"
+#include "UAC_Thread.h"
 
 extern class CCP_MainApp theApp;
 
@@ -36,6 +37,7 @@ public:
 	CppSQLite3DB m_db;
 
 	HANDLE	m_hMutex; // for singleton app
+	HANDLE m_adminPasteMutex;
 	// track stages of startup / shutdown
 	bool	m_bAppRunning;
 	bool	m_bAppExiting;
@@ -171,6 +173,9 @@ public:
 	CDPI m_metrics;
 	ULONG_PTR m_gdiplusToken;
 
+	void UACPaste();
+	bool UACThreadRunning();
+
 public:
 	virtual BOOL InitInstance();
 	virtual int ExitInstance();
@@ -181,4 +186,5 @@ public:
 
 protected:
 	void ShowCommandLineError(CString csTitle, CString csMessage);
+	CUAC_Thread *m_pUacPasteThread;
 };

+ 4 - 0
CP_Main.vcxproj

@@ -1565,6 +1565,8 @@
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
+    <ClCompile Include="UAC_Helper.cpp" />
+    <ClCompile Include="UAC_Thread.cpp" />
     <ClCompile Include="WildCardMatch.cpp" />
     <ClCompile Include="WndEx.cpp">
       <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
@@ -1788,6 +1790,8 @@
     <ClInclude Include="sqlite\sqlite3.h" />
     <ClInclude Include="sqlite\sqlite3ext.h" />
     <ClInclude Include="ToolTipEx.h" />
+    <ClInclude Include="UAC_Helper.h" />
+    <ClInclude Include="UAC_Thread.h" />
     <ClInclude Include="WildCardMatch.h" />
     <ClInclude Include="WndEx.h" />
     <ClInclude Include="Client.h" />

+ 30 - 6
CP_Main.vcxproj.filters

@@ -337,7 +337,15 @@
     <ClCompile Include="MyDropTarget.cpp">
       <Filter>source</Filter>
     </ClCompile>
-    <ClCompile Include="ActionEnums.cpp" />
+    <ClCompile Include="UAC_Helper.cpp">
+      <Filter>source</Filter>
+    </ClCompile>
+    <ClCompile Include="UAC_Thread.cpp">
+      <Filter>source</Filter>
+    </ClCompile>
+    <ClCompile Include="ActionEnums.cpp">
+      <Filter>source</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="sqlite\CppSQLite3.h">
@@ -721,7 +729,15 @@
     <ClInclude Include="MyDropTarget.h">
       <Filter>header</Filter>
     </ClInclude>
-    <ClInclude Include="ActionEnums.h" />
+    <ClInclude Include="UAC_Thread.h">
+      <Filter>header</Filter>
+    </ClInclude>
+    <ClInclude Include="UAC_Helper.h">
+      <Filter>header</Filter>
+    </ClInclude>
+    <ClInclude Include="ActionEnums.h">
+      <Filter>header</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="CP_Main.rc">
@@ -932,10 +948,18 @@
     <None Include="res\opened_folder_32_32.png">
       <Filter>res</Filter>
     </None>
-    <None Include="res\maximize_8_8.png" />
-    <None Include="res\maximize_10_10.png" />
-    <None Include="res\maximize_12_12.png" />
-    <None Include="res\maximize_16_16.png" />
+    <None Include="res\maximize_10_10.png">
+      <Filter>res</Filter>
+    </None>
+    <None Include="res\maximize_8_8.png">
+      <Filter>res</Filter>
+    </None>
+    <None Include="res\maximize_12_12.png">
+      <Filter>res</Filter>
+    </None>
+    <None Include="res\maximize_16_16.png">
+      <Filter>res</Filter>
+    </None>
   </ItemGroup>
   <ItemGroup>
     <Filter Include="sqlite">

+ 17 - 3
EventThread.cpp

@@ -11,6 +11,7 @@ CEventThread::CEventThread(void)
 	m_waitTimeout = INFINITE;
 	m_threadRunning = false;
 	m_exitThread = false;
+	m_threadWasStarted = false;
 }
 
 CEventThread::~CEventThread(void)
@@ -36,6 +37,12 @@ void CEventThread::AddEvent(int eventId)
 	m_eventMap[handle] = eventId;
 }
 
+void CEventThread::AddEvent(int eventId, CString name)
+{
+	HANDLE handle = CreateEvent(NULL, FALSE, FALSE, name);
+	m_eventMap[handle] = eventId;
+}
+
 bool CEventThread::FireEvent(int eventId)
 {
 	//Log(StrF(_T("Begin FireEvent, eventId: %d"), eventId));
@@ -102,6 +109,11 @@ void CEventThread::Start(void *param)
 	}
 }
 
+void CEventThread::WaitForThreadToExit(int waitTime)
+{
+	WaitForSingleObject(m_hEvt, waitTime);
+}
+
 void CEventThread::Stop(int waitTime) 
 {
 	Log(_T("Start of CEventThread::Stop(int waitTime) "));
@@ -131,6 +143,7 @@ void CEventThread::RunThread()
 	Log(_T("Start of CEventThread::RunThread()"));
 
 	m_threadRunning = true;
+	m_threadWasStarted = true;
 	HANDLE *pHandleArray = new HANDLE[m_eventMap.size()];
 
 	int indexPos = 0;
@@ -143,7 +156,7 @@ void CEventThread::RunThread()
 	SetEvent(m_hEvt);
 	ResetEvent(m_hEvt);
 
-	while(true)
+	while(m_exitThread == false)
 	{
 		DWORD event = WaitForMultipleObjects((DWORD)m_eventMap.size(), pHandleArray, FALSE, m_waitTimeout);
 
@@ -173,8 +186,7 @@ void CEventThread::RunThread()
 			HANDLE firedHandle = pHandleArray[event - WAIT_OBJECT_0];
 			int eventId = m_eventMap[firedHandle];
 			if(eventId == EXIT_EVENT)
-			{
-				SetEvent(m_hEvt);
+			{				
 				break;
 			}
 			else
@@ -186,6 +198,8 @@ void CEventThread::RunThread()
 		}
 	}
 
+	SetEvent(m_hEvt);
+
 	Log(_T("End of CEventThread::RunThread()"));
 
 	m_threadRunning = false;

+ 5 - 0
EventThread.h

@@ -25,6 +25,7 @@ protected:
 	EventMapType m_eventMap;
 	bool m_exitThread;
 	bool m_threadRunning;
+	bool m_threadWasStarted;
 	void *m_param;
 	int m_waitTimeout;
 
@@ -32,8 +33,12 @@ public:
 	void Start(void *param = NULL);
 	void Stop(int waitTime = 5000); 
 	void AddEvent(int eventId);
+	void AddEvent(int eventId, CString name);
 	bool FireEvent(int eventId);
 	bool IsCancelled() { return m_exitThread; }
+	void CancelThread() { m_exitThread = true; }
 	bool IsRunning() { return m_threadRunning; }
+	bool ThreadWasStarted() { return m_threadWasStarted; }
+	void WaitForThreadToExit(int waitTime);
 };
 

+ 12 - 5
ExternalWindowTracker.cpp

@@ -245,11 +245,18 @@ void ExternalWindowTracker::SendPaste(bool activateTarget)
 	m_dittoHasFocus = false;
 	Log(StrF(_T("Sending paste to app %s key stroke: %s, SeDelay: %d"), csPasteToApp, csPasteString, delay));
 
-	Sleep(delay);
-
-	send.SetKeyDownDelay(max(50, delay));
-
-	send.SendKeys(csPasteString, true);
+	if(g_Opt.GetPasteAsAdmin() &&
+		theApp.UACThreadRunning() == false)
+	{
+		Log(StrF(_T("Passing paste off to uac aware app")));
+		theApp.UACPaste();
+	}
+	else
+	{
+		Sleep(delay);
+		send.SetKeyDownDelay(max(50, delay));
+		send.SendKeys(csPasteString, true);
+	}
 
 	Log(_T("Post sending paste"));
 }

+ 2 - 1
Misc.cpp

@@ -947,4 +947,5 @@ void DeleteReceivedFiles(CString csDir)
 			DeleteFile(Find.GetFilePath());
 		}
 	}
-}
+}
+

+ 10 - 0
Options.cpp

@@ -2065,4 +2065,14 @@ void CGetSetOptions::SetShowScrollBar(BOOL val)
 BOOL CGetSetOptions::GetShowScrollBar()
 {
 	return GetProfileLong(_T("ShowScrollBar"), 0);
+}
+
+void CGetSetOptions::SetPasteAsAdmin(BOOL val)
+{
+	SetProfileLong(_T("PasteAsAdmin"), val);
+}
+
+BOOL CGetSetOptions::GetPasteAsAdmin()
+{
+	return GetProfileLong(_T("PasteAsAdmin"), 0);
 }

+ 3 - 0
Options.h

@@ -436,6 +436,9 @@ public:
 	static void		SetShowScrollBar(BOOL val);
 	static BOOL		GetShowScrollBar();
 	static BOOL		m_showScrollBar;
+
+	static void		SetPasteAsAdmin(BOOL val);
+	static BOOL		GetPasteAsAdmin();
 };
 
 // global for easy access and for initialization of fast access variables

+ 12 - 0
UAC_Helper.cpp

@@ -0,0 +1,12 @@
+#include "stdafx.h"
+#include "UAC_Helper.h"
+
+
+CUAC_Helper::CUAC_Helper(void)
+{
+}
+
+
+CUAC_Helper::~CUAC_Helper(void)
+{
+}

+ 8 - 0
UAC_Helper.h

@@ -0,0 +1,8 @@
+#pragma once
+class CUAC_Helper
+{
+public:
+	CUAC_Helper(void);
+	~CUAC_Helper(void);
+};
+

+ 93 - 0
UAC_Thread.cpp

@@ -0,0 +1,93 @@
+#include "stdafx.h"
+#include "UAC_Thread.h"
+
+#include "Misc.h"
+#include "Options.h"
+#include "QPasteWnd.h"
+#include "cp_main.h"
+
+CUAC_Thread::CUAC_Thread(int processId)
+{
+	m_processId = processId;
+
+	AddEvent(UAC_PASTE, StrF(_T("Global\\UAC_PASTE_%d"), m_processId));
+	AddEvent(UAC_EXIT, StrF(_T("Global\\UAC_EXIT_%d"), m_processId));
+
+	m_waitTimeout = 30000;
+}
+
+CUAC_Thread::~CUAC_Thread(void)
+{
+}
+
+
+void CUAC_Thread::OnTimeOut(void *param)
+{
+}
+
+void CUAC_Thread::OnEvent(int eventId, void *param)
+{
+	DWORD startTick = GetTickCount();
+	Log(StrF(_T("Start of OnEvent, eventId: %s"), EnumName((eUacThreadEvents)eventId)));
+
+	switch((eUacThreadEvents)eventId)
+	{
+	case UAC_PASTE:
+		theApp.m_activeWnd.SendPaste(false);
+		break; 
+	case UAC_EXIT:
+		this->CancelThread();
+		break;
+	}
+
+	DWORD length = GetTickCount() - startTick;
+	Log(StrF(_T("End of OnEvent, eventId: %s, Time: %d(ms)"), EnumName((eUacThreadEvents)eventId), length));
+}
+
+CString CUAC_Thread::EnumName(eUacThreadEvents e)
+{
+	switch(e)
+	{
+	case UAC_PASTE:
+		return _T("Paste Elevated");
+	case UAC_EXIT:
+		return _T("Save Startup Elevated");
+	}
+
+	return _T("");
+}
+
+void CUAC_Thread::UACPaste()
+{
+	CString mutexName;
+	mutexName.Format(_T("DittoAdminPaste_%d"), GetCurrentProcessId());
+
+	HANDLE mutex = CreateMutex(NULL, FALSE, mutexName);
+	DWORD dwError = GetLastError();
+	if(dwError == ERROR_ALREADY_EXISTS)
+	{
+	}
+	else
+	{
+		wchar_t szPath[MAX_PATH];
+		if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)))
+		{
+			// Launch itself as administrator.
+			SHELLEXECUTEINFO sei = { sizeof(sei) };
+			sei.lpVerb = L"runas";
+			sei.lpFile = szPath;
+			CString csParam;
+			csParam.Format(_T("/uacpaste:%d"), GetCurrentProcessId());
+			sei.lpParameters = csParam;
+			sei.nShow = SW_NORMAL;
+
+			if (!ShellExecuteEx(&sei))
+			{
+			}
+		}
+	}
+
+	FirePaste();
+
+	CloseHandle(mutex);
+}

+ 37 - 0
UAC_Thread.h

@@ -0,0 +1,37 @@
+#pragma once
+
+#include "EventThread.h"
+
+class CUAC_Thread : public CEventThread
+{
+public:
+	CUAC_Thread(int processId);
+	~CUAC_Thread(void);
+
+	enum eUacThreadEvents
+	{
+		UAC_PASTE, 
+		UAC_EXIT,
+
+		eUacThreadEvents_COUNT  //must be last
+	};
+
+	int m_processId;
+
+	void FirePaste()
+	{
+		FireEvent(UAC_PASTE);
+	}
+	void FireExit()
+	{
+		FireEvent(UAC_EXIT);
+	}
+
+	void UACPaste();
+
+private:
+	virtual void OnEvent(int eventId, void *param);
+	virtual void OnTimeOut(void *param);
+	CString EnumName(eUacThreadEvents e);
+};
+