Ho un'app che si trova come vassoio nella barra delle applicazioni. Ho registrato un tasto di scelta rapida che quando premuto cattura la selezione del testo corrente in qualsiasi applicazione, anche nei browser Web.SendKeys Ctrl + C per applicazioni esterne (testo negli Appunti)
Il mio approccio consiste nell'inviare la combinazione di tasti {Ctlr + C} per copiare il testo. Quindi accedi agli Appunti e utilizza il testo nella mia applicazione.
Sto programmando in VB.NET ma qualsiasi aiuto in C# o anche C++ con Win32_Api sarebbe molto apprezzato.
Uso AutoHotkey e lì, ho uno script che accede al testo degli Appunti e funziona correttamente.
Pause::
clipboard = ; Start off empty to allow ClipWait to detect when the text has arrived.
Send ^c
ClipWait, 2 ; Wait for the clipboard to contain text.
if ErrorLevel
{
;Do nothing after 2 seconds timeout
return
}
Run https://translate.google.com/#auto/es/%clipboard%
return
Come AutoHotkey è open source, ho scaricato il codice e cercare di replicare il comportamento di ClipWait per quanto ho potuto.
Il mio codice funziona la maggior parte del tempo ma a volte c'è un ritardo importante. Non riesco ad accedere agli Appunti e alla funzione win32 IsClipboardFormatAvailable() continua a restituire False per un while. Questo succede quando sto provando a copiare da Google Chrome specialmente in TextBox modificabili.
Ho provato un sacco di cose diverse incluso l'uso della classe Clipboard .Net Framework. Ho letto il problema potrebbe essere che il thread che stava eseguendo i comandi non è stato impostato come STA, quindi l'ho fatto. Nella mia disperazione metto anche un timer, ma nulla risolve completamente il problema.
Ho letto anche l'opzione di mettere un gancio per monitorare gli Appunti, ma vorrei evitarlo a meno che non sia l'unico modo per farlo.
Ecco il mio codice VB.NET:
Imports System.Runtime.InteropServices
Imports System.Text
Imports System.Threading
Imports Hotkeys
Public Class Form1
Public m_HotKey As Keys = Keys.F6
Private Sub RegisterHotkeys()
Try
Dim alreaydRegistered As Boolean = False
' set the hotkey:
''---------------------------------------------------
' add an event handler for hot key pressed (or could just use Handles)
AddHandler CRegisterHotKey.HotKeyPressed, AddressOf hotKey_Pressed
Dim hkGetText As HotKey = New HotKey("hkGetText",
HotKey.GetKeySinModificadores(m_HotKey),
HotKey.FormatModificadores(m_HotKey.ToString),
"hkGetText")
Try
CRegisterHotKey.HotKeys.Add(hkGetText)
Catch ex As HotKeyAddException
alreaydRegistered = True
End Try
Catch ex As Exception
CLogFile.addError(ex)
End Try
End Sub
Private Sub hotKey_Pressed(sender As Object, e As HotKeyPressedEventArgs)
Try
Timer1.Start()
Catch ex As Exception
CLogFile.addError(ex)
End Try
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
RegisterHotkeys()
End Sub
Function copyText() As String
Dim result As String = String.Empty
Clipboard.Clear()
Console.WriteLine("Control + C")
SendKeys.SendWait("^c")
Dim Attempts As Integer = 100
Do While Attempts > 0
Try
result = GetText()
If result = String.Empty Then
Attempts -= 1
'Console.WriteLine("Attempts {0}", Attempts)
Thread.Sleep(100)
Else
Attempts = 0
End If
Catch ex As Exception
Attempts -= 1
Console.WriteLine("Attempts Exception {0}", Attempts)
Console.WriteLine(ex.ToString)
Threading.Thread.Sleep(100)
End Try
Loop
Return result
End Function
#Region "Win32"
<DllImport("User32.dll", SetLastError:=True)>
Private Shared Function IsClipboardFormatAvailable(format As UInteger) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("User32.dll", SetLastError:=True)>
Private Shared Function GetClipboardData(uFormat As UInteger) As IntPtr
End Function
<DllImport("User32.dll", SetLastError:=True)>
Private Shared Function OpenClipboard(hWndNewOwner As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("User32.dll", SetLastError:=True)>
Private Shared Function CloseClipboard() As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("Kernel32.dll", SetLastError:=True)>
Private Shared Function GlobalLock(hMem As IntPtr) As IntPtr
End Function
<DllImport("Kernel32.dll", SetLastError:=True)>
Private Shared Function GlobalUnlock(hMem As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("Kernel32.dll", SetLastError:=True)>
Private Shared Function GlobalSize(hMem As IntPtr) As Integer
End Function
Private Const CF_UNICODETEXT As UInteger = 13UI
Private Const CF_TEXT As UInteger = 1UI
#End Region
Public Shared Function GetText() As String
If Not IsClipboardFormatAvailable(CF_UNICODETEXT) AndAlso Not IsClipboardFormatAvailable(CF_TEXT) Then
Return Nothing
End If
Try
If Not OpenClipboard(IntPtr.Zero) Then
Return Nothing
End If
Dim handle As IntPtr = GetClipboardData(CF_UNICODETEXT)
If handle = IntPtr.Zero Then
Return Nothing
End If
Dim pointer As IntPtr = IntPtr.Zero
Try
pointer = GlobalLock(handle)
If pointer = IntPtr.Zero Then
Return Nothing
End If
Dim size As Integer = GlobalSize(handle)
Dim buff As Byte() = New Byte(size - 1) {}
Marshal.Copy(pointer, buff, 0, size)
Return Encoding.Unicode.GetString(buff).TrimEnd(ControlChars.NullChar)
Finally
If pointer <> IntPtr.Zero Then
GlobalUnlock(handle)
End If
End Try
Finally
CloseClipboard()
End Try
End Function
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Try
Timer1.Stop()
Dim ThreadA As Thread
ThreadA = New Thread(AddressOf Me.copyTextThread)
ThreadA.SetApartmentState(ApartmentState.STA)
ThreadA.Start()
Catch ex As Exception
CLogFile.addError(ex)
End Try
End Sub
Sub copyTextThread()
Dim result As String = copyText()
If result <> String.Empty Then
MsgBox(result)
End If
End Sub
End Class
Ho cercato anche in altre simili domande senza una soluzione definitiva al mio problema:
Send Ctrl+C to previous active window
How do I get the selected text from the focused window using native Win32 API?
perché non utilizzare l'automazione? –
Cosa intendi? Potresti essere un po 'più specifico per favore. –
Intendo l'automazione dell'interfaccia utente. Il tuo approccio distrugge gli appunti. –