I have two applications named app and anotherapp respectively along with one class library myadp.dll
app contains:
using myadp;
namespace app
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void bt_Click(object sender, RoutedEventArgs e)
{
Class1 c = new Class1();
tbinapp.Text = c.st;
}
}
}
anotherapp contains:
using myadp;
namespace anotherapp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void anotherbt_Click(object sender, RoutedEventArgs e)
{
Class1 ad = new Class1();
ad.st = anothertb.Text;
}
}
}
And myadp.dll contains:
namespace myadp
{
public class Class1
{
public string st = "this is from adapter ";
}
}
I am trying to pass a value from anotherapp to app using myadp as an adapter. But it is not working. I am assuming that it is not working because each application is creating a new instance of the class Class1 in myadp. Am I right? How do test this and fix it?
Finally it worked (here the adapter's readfromnotepad() is returning string that was on the edit fielt in the notepad )
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
//using System.ServiceModel.Dispatcher;
namespace finally_adapter
{
public class adapt_
{
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd);
enum GetWindow_Cmd : uint {
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, [Out] StringBuilder lParam);
[DllImport("User32.dll")]
public static extern Int32 FindWindow(String lpClassName, String lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
int len;
public string strin;
const int WM_GETTEXT = 0x000D;
StringBuilder sb = new StringBuilder(100);
IntPtr hwnd;
public adapt_()
{
}
public string readfromnotepad()
{
string lpclassname = "Edit";
string lpwindowname = "Notepad";
int temp = FindWindow(lpwindowname,null);
hwnd = (IntPtr)temp;
StringBuilder temps = new StringBuilder(100);
IntPtr edit_hwnd = GetWindow(hwnd, GetWindow_Cmd.GW_CHILD);
IntPtr msg_hwnd = SendMessage(edit_hwnd, WM_GETTEXT, (IntPtr)100, temps);
return temps.ToString();
}
}
}
You are correct in that each app is creating a new instance of Class1, however it is deeper than that. You seem to be misunderstanding a basic part of how classes work in code
Two apps which share the namespace myadp can both create the class Class1 in that namespace, however the instances of those classes are not shared between them.
Think of it as two kids who each have a set of instructions for building a lego house. Using the blocks they have, they can both build the same kind of house, but they're not the same house. If kid A builds a house, kid B does not have that house to play with, he has to build his own.
To fix your problem, you need somewhere to store the data, like a database, or a public method in one app which can be accessed by another.
Related
I'm currently trying to inject a library into a program I made(for learning purpose, it's just curiosity). I think I managed to do it, but it seems the code i did is laking of entry point maybe ?
this is the code I wrote :
I used visual studio code to generate a kind of hello-world dll
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace InjectDll
{
public class Inject
{
[DllImport("kernel32")]
static extern bool AllocConsole();
public Inject()
{
AllocConsole();
Console.WriteLine("blablabla");
}
public string test()
{
AllocConsole();
return "dll is injected";
}
}
}
I then made a basic program I where wanted to test my injection =>
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace basicProgram
{
class Program
{
static void Main(string[] args)
{
while(true){
Thread.Sleep(1000);
Console.WriteLine("Hello world");
}
}
}
}
So now I have my dll and the program i wanted to try my injection.I just had to write the injector, and this is what I did =>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace injectorTest.Inject
{
public enum DllInjectionResult
{
DllNotFound,
GameProcessNotFound,
InjectionFailed,
Success
}
class Injector
{
static readonly IntPtr INTPTR_ZERO = (IntPtr)0;
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer, uint size, int lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttribute, IntPtr dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
//[DllImport("InjectDll.dll", CallingConvention = CallingConvention.StdCall)]
private const string DLL_NAME = "hello.dll";
private Process myProcess;
private string myPath;
public Injector()
{
}
public Injector(Process myProcess)
{
this.myProcess = myProcess;
this.myPath = Path.GetDirectoryName(myProcess.MainModule.FileName);
}
private void checkDll()
{
if (!File.Exists(myPath + #"\hello.dll")) {
}
}
public DllInjectionResult inject()
{
if (!File.Exists(myPath + "\\hello.dll"))
{
return DllInjectionResult.DllNotFound;
}
Console.WriteLine("process id : " + myProcess.Id);
if (myProcess == null)
{
return DllInjectionResult.GameProcessNotFound;
}
if (!startInject((uint)myProcess.Id, myPath + "\\hello.dll"))
{
return DllInjectionResult.InjectionFailed;
}
return DllInjectionResult.Success;
}
private bool startInject(uint processId, string dllPath)
{
IntPtr handleProcess = OpenProcess((0x2 | 0x8 | 0x10 | 0x20 | 0x400), 1, processId);
if (handleProcess == INTPTR_ZERO)
{
return false;
}
IntPtr lpAddress = VirtualAllocEx(handleProcess, (IntPtr)null, (IntPtr)dllPath.Length, (0x1000 | 0x2000), 0X40);
Console.WriteLine("lpaddr: " + lpAddress);
if (lpAddress == INTPTR_ZERO)
{
return false;
}
byte[] bytes = Encoding.ASCII.GetBytes(dllPath);
if (WriteProcessMemory(handleProcess, lpAddress, bytes, (uint)bytes.Length, 0) == 0)
{
return false;
}
IntPtr lpLLAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryW");
if (lpLLAddress == INTPTR_ZERO)
{
return false;
}
var remoteThread = CreateRemoteThread(handleProcess, (IntPtr)null, INTPTR_ZERO, lpLLAddress, lpAddress, 0, (IntPtr)null);
if (remoteThread == INTPTR_ZERO)
{
return false;
}
CloseHandle(handleProcess);
return true;
}
}
}
It doesn't seems to fail i can see via ida (watching the helloworld program i tried to inject) that LoadLibraryW is trigered when I launch my injector (I then can see the path of the dll injected but it doesn't seems to trigger smthg.
It seems like I missing something (like an entry point in my dll maybe ?).
A normal C/C++ DLL will have a DllMain which gets executed when LoadLibrary is called which then passes through to a switch statement, normally we put our code inside the DLL_PROCESS_ATTACH case which will get executed on injection.
This equivalent doesn't exist in C#/CLR but you can do something tricky to make the same effect by using static constructors.
Make a class and initialize an object of that class, this will in turn call the static constructor. Something like this:
class someClass
{
//Static constructor
static someClass()
{
Console.WriteLine("injected");
}
}
Having inched slightly closer to this question-
Fixing a prompt window over the main window in a windows application using C#
I am asking this question in a hope that I will be able to fix the above. Here's it. How do get hold of a pop-up window that is thrown from an in-built function in C#.
The method is Microsoft.Office.Interop.Word.Document.CheckSpelling() and the pop-up window is the Spell-Check dialog box.
This example finds the spell checker window and closes it.
1) Find process of Word
2) Enumerate all windows belonging to this process ID
3) Get the window with the appropriate class name
4) Close that window
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Word = NetOffice.WordApi;
namespace WordSpellCheckerTest
{
class Program
{
static void Main(string[] args)
{
using (var app = new Word.Application())
{
SpellCheckerDemo(app);
}
}
private static async void SpellCheckerDemo(Word.Application app)
{
app.Visible = true;
var doc = app.Documents.Add();
doc.Words.First.InsertBefore("Here's some text that requiires speell cheking");
var process = GetProcess(app);
var task = new Task(() => CheckSpellingTask(doc));
task.Start();
//Wait for the window to open
Thread.Sleep(4000);
//I found the classname by comparing the list of windows for the process before and after opening the spell checker
//Then I checked the title to confirm
var spellCheckerWindow = WindowStuff.GetWindowsWithPID(process.Id).FirstOrDefault(w => w.ClassName == "bosa_sdm_msword");
//Do something with the window
spellCheckerWindow.Close();
//Wait for the task to finish before closing
task.Wait();
doc.Close(false);
app.Quit();
}
private static async Task CheckSpellingTask(Word.Document doc)
{
try
{
doc.CheckSpelling();
}
catch { }
}
//From my answer here: http://stackoverflow.com/questions/8673726/get-specific-window-handle-using-office-interop/41462638#41462638
private static Process GetProcess(Word.Application app)
{
var tempDocument = app.Documents.Add();
var project = tempDocument.VBProject;
var component = project.VBComponents.Add(NetOffice.VBIDEApi.Enums.vbext_ComponentType.vbext_ct_StdModule);
var codeModule = component.CodeModule;
codeModule.AddFromString("#If Win64 Then\r\n Declare PtrSafe Function GetCurrentProcessId Lib \"kernel32\" () As Long\r\n#Else\r\n Declare Function GetCurrentProcessId Lib \"kernel32\" () As Long\r\n#End If");
var result = app.Run("GetCurrentProcessId");
var process = Process.GetProcessById((int)result);
tempDocument.Close(false);
return process;
}
//Hacked together from the pInvoke pages for these WinAPI calls
public class WindowStuff
{
[DllImport("user32.dll", SetLastError = true)]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, [Out] StringBuilder lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumWindows(WindowEnumerator lpEnumFunc, ArrayList lParam);
private delegate bool WindowEnumerator(IntPtr handleWindow, ArrayList handles);
const uint WM_CLOSE = 0x0010;
const uint WM_GETTEXTLENGTH = 0x000E;
const uint WM_GETTEXT = 0x000D;
public struct Info
{
public uint Hwnd;
public uint PID;
public string ClassName;
public string Title;
public Info(IntPtr hwnd )
{
uint processID;
GetWindowThreadProcessId(hwnd, out processID);
Hwnd = (uint)hwnd;
PID = processID;
ClassName = GetClassName(hwnd);
Title = GetWindowTitle(hwnd);
}
public void Close()
{
SendMessage(new IntPtr(Hwnd), WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}
}
public static List<Info> GetWindowsWithPID(int pID)
{
return GetWindowsInner().Cast<IntPtr>().Select(hwnd => new Info(hwnd)).Where(i => i.PID == (uint)pID).ToList();
}
private static ArrayList GetWindowsInner()
{
var windowHandles = new ArrayList();
WindowEnumerator callBackPtr = GetWindowHandle;
EnumWindows(callBackPtr, windowHandles);
return windowHandles;
}
static string GetWindowTitle(IntPtr hwnd)
{
int length = (int)SendMessage(hwnd, WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
StringBuilder sb = new StringBuilder(length + 1);
SendMessage(hwnd, WM_GETTEXT, (IntPtr)sb.Capacity, sb);
return sb.ToString();
}
private static bool GetWindowHandle(IntPtr windowHandle, ArrayList windowHandles)
{
windowHandles.Add(windowHandle);
return true;
}
private static string GetClassName(IntPtr hWnd)
{
var className = new StringBuilder(256);
return GetClassName(hWnd, className, className.Capacity) != 0 ? className.ToString() : string.Empty;
}
}
}
}
This question already has answers here:
Embedding a File Explorer instance in a Windows Forms application form
(8 answers)
Closed 9 years ago.
I dont know if OpenFiledialog is the right control, but I want to open an already bookmarked filepath within my main form control. I have a program that implements this but I dont know how to go about it.
When the user clicks a button, the column on the left in the picture below will show the folder of the last opened file path. How to go about to create this. I already have the path to the folder I want to display, which controls should I use, any code will be highly appreciated
You can do it with SetParent function.
below is an example only for educational purposes!
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace WindowsFormsApplication4
{
public partial class Form1 : Form
{
public Form1()
{
this.Size = new System.Drawing.Size(800, 600);
this.TopMost = true;
this.FormBorderStyle = FormBorderStyle.FixedToolWindow;
Func<bool> run = () =>
Window.Find(hwnd =>
{
var cn = Window.GetClassName(hwnd);
var res = (cn == "CabinetWClass");
if (res)
{
this.Controls.Clear();
Window.SetParent(hwnd, this.Handle);
Window.SetWindowPos(hwnd, new IntPtr(0), -8, -30, this.Width + 10, this.Height + 37, 0x0040);
}
return res;
});
new Button { Parent = this, Text = "Start" }
.Click += (s, e) =>
{
if (run() == false)
MessageBox.Show("Open Explorer");
};
}
}
public static class Window
{
public static bool Find(Func<IntPtr, bool> fn)
{
return EnumWindows((hwnd, lp) => !fn(hwnd), 0) == 0;
}
public static string GetClassName(IntPtr hwnd)
{
var sb = new StringBuilder(1024);
GetClassName(hwnd, sb, sb.Capacity);
return sb.ToString();
}
public static uint GetProcessId(IntPtr hwnd) // {0:X8}
{
uint pid;
GetWindowThreadProcessId(hwnd, out pid);
return pid;
}
public static string GetText(IntPtr hwnd)
{
var sb = new StringBuilder(1024);
GetWindowText(hwnd, sb, sb.Capacity);
return sb.ToString();
}
delegate bool CallBackPtr(IntPtr hwnd, int lParam);
[DllImport("user32.dll")]
static extern int EnumWindows(CallBackPtr callPtr, int lPar);
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("User32", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndParent);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int W, int H, uint uFlags);
}
}
if im understanding the question you want to open windows explorer at a certain path.
its simple then, you use no control just do this:
Process.Start("Your path here");
I'm using the Sopcast activex plugin (sopocx.ocx) in one of my C# applications.
I would like to retrieve the player status ("Buffering the channel", "Playing the channel", "Channel Offline...") and the buffering percentage. Both of these informationss are displayed on the player (I tried to post a picture but I don't have enough reputation yet).
The problem is the Sopcast activex plugin doesn't provide any methods in order to retrieve these informations.
Does someone has any idea on how this could be done??
GetWindowText results in an empty string...
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace test
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
private void testToolStripMenuItem_Click(object sender, EventArgs e)
{
IntPtr hwnd = sopcast.Handle;
StringBuilder lpString = new StringBuilder(256);
GetWindowText(hwnd, lpString, 256);
MessageBox.Show(lpString.ToString());
}
private void playToolStripMenuItem_Click(object sender, EventArgs e)
{
sopcast.SetSopAddress("sop://broker.sopcast.com:3912/123456789");
sopcast.SetChannelName("Channel");
sopcast.Play();
}
}
}
You can identify Id control and get text with api windows
here a code sample (replace notepad by your application name) the most important for you is to get from your application a way to get ID control of your ocx window
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Security;
namespace Application
{
public class Program
{
public static void Main ( )
{
IntPtr hwnd = UnsafeNativeMethods.FindWindow("Notepad", null);
StringBuilder stringBuilder = new StringBuilder(256);
UnsafeNativeMethods.GetWindowText(hwnd, stringBuilder, stringBuilder.Capacity);
Console.WriteLine(stringBuilder.ToString());
}
}
[SuppressUnmanagedCodeSecurity]
internal static class UnsafeNativeMethods
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern int GetWindowText ( IntPtr hWnd, [Out] StringBuilder lpString, int nMaxCount );
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr FindWindow ( string lpClassName, string lpWindowName );
}
}
I download sopcast and try to get status using spy++:
As you see, caption is status not the channel...
so you can not get it easier
the handle you have catched is for the whole control
Sopcast draws the status text using DrawText (i found out using API Monitor http://www.rohitab.com/apimonitor). So there is no way of getting the text using conventional GetWindowText function or similar. I was able to obtain the text by hooking DrawText function. For .NET EasyHook will enable you to do this.
My scenario:
I have a winforms app that hosts the activex control and i want to obtain the status text.
public class hooklocal : EasyHook.IEntryPoint
{
[DllImport("user32.dll")]
static extern int DrawText(IntPtr hDC, string lpString, int nCount, IntPtr lpRect, uint uFormat);
[UnmanagedFunctionPointer(CallingConvention.StdCall,CharSet = CharSet.Auto,SetLastError = true)]
delegate int DDrawText(IntPtr hDC, string lpString, int nCount, IntPtr lpRect, uint uFormat);
int DrawTextH(IntPtr hDC, string lpString, int nCount, IntPtr lpRect, uint uFormat)
{
//lpString contains the status text
return DrawText(hDC, lpString, nCount, lpRect, uFormat);
}
public hooklocal()
{
try
{
var CreateHook = LocalHook.Create(
LocalHook.GetProcAddress("user32.dll", "DrawTextW"),
new DDrawText(DrawTextH),
this);
CreateHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
}
catch (Exception ExtInfo)
{
Debugger.Break();
}
}
}
To use, instantiate hooklocal class in a new thread at program startup.
EasyHook download
https://easyhook.github.io/downloads.html
I'm curious if it is possible to write a program that monitors my text selection. One possible use would be to write an editor/IDE agnostic code formatter:
Application/Service, P, is launched and somehow hooks into windows such that it gets notified when text is selected in any window.
Some other application, A, is launched.
User selects text in A.
P is notified with the text that is selected.
--> I'd be happy to get this far...
This is not possible without specific knowledge of each control/application that will be in use as they can all handle/treat it differently.
I don't think you can register any sort of hook. I think you'll need to constantly poll the "focused" or selected window.
You can probably use the Windows Automation API to do this, which is as far as I am aware superceeded the older Accesibility API:
http://msdn.microsoft.com/en-us/library/ms747327.aspx
I have used this API to automate GUI tests. I am a bit rusty with it so I don't know for sure, but I am reasonably confident you could use it for what you are trying to do. Basically the API allows you to traverse the tree of automation objects with the root at the desktop. Each automation element tends to be a windows control of some kind and different controls implement different patterns. You can also get at elements beneath the mouse cursor and possibly you can get straight to the currently selected/focused element.
After that I notice the TextPattern class for example has a GetSelection() method which is documented as "Retrieves a collection of disjoint text ranges associated with the current text selection or selections.". I bet the automation object for textboxes implement the TextPattern.
http://msdn.microsoft.com/en-us/library/system.windows.automation.textpattern.aspx
This code help you to get focused control text in focused window, i hope that helps :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace TextFocusedns
{
public partial class TextFocusedFrm : Form
{
#region APIs
[DllImport("user32.dll")]
public static extern bool GetCursorPos(out Point pt);
[DllImport("user32.dll", EntryPoint = "WindowFromPoint", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr WindowFromPoint(Point pt);
[DllImport("user32.dll", EntryPoint = "SendMessageW")]
public static extern int SendMessageW([InAttribute] System.IntPtr hWnd, int Msg, int wParam, IntPtr lParam);
public const int WM_GETTEXT = 13;
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
internal static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
internal static extern IntPtr GetFocus();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern int GetWindowThreadProcessId(int handle, out int processId);
[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
internal static extern int AttachThreadInput(int idAttach, int idAttachTo, bool fAttach);
[DllImport("kernel32.dll")]
internal static extern int GetCurrentThreadId();
[DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern int GetWindowText(IntPtr hWnd, [Out, MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpString, int nMaxCount);
#endregion
private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer() { Interval = 100, Enabled = true };
public TextFocusedFrm()
{
InitializeComponent();
}
private void TextFocusedFrm_Load(object sender, EventArgs e)
{
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
try
{
MultiLineTextBox.Text = GetTextFromFocusedControl();
}
catch (Exception exp)
{
MultiLineTextBox.Text += exp.Message;
}
}
//Get the text of the focused control
private string GetTextFromFocusedControl()
{
try
{
int activeWinPtr = GetForegroundWindow().ToInt32();
int activeThreadId = 0, processId;
activeThreadId = GetWindowThreadProcessId(activeWinPtr, out processId);
int currentThreadId = GetCurrentThreadId();
if (activeThreadId != currentThreadId)
AttachThreadInput(activeThreadId, currentThreadId, true);
IntPtr activeCtrlId = GetFocus();
return GetText(activeCtrlId);
}
catch (Exception exp)
{
return exp.Message;
}
}
//Get the text of the control at the mouse position
private string GetTextFromControlAtMousePosition()
{
try
{
Point p;
if (GetCursorPos(out p))
{
IntPtr ptr = WindowFromPoint(p);
if (ptr != IntPtr.Zero)
{
return GetText(ptr);
}
}
return "";
}
catch (Exception exp)
{
return exp.Message;
}
}
//Get the text of a control with its handle
private string GetText(IntPtr handle)
{
int maxLength = 512;
IntPtr buffer = Marshal.AllocHGlobal((maxLength + 1) * 2);
SendMessageW(handle, WM_GETTEXT, maxLength, buffer);
string w = Marshal.PtrToStringUni(buffer);
Marshal.FreeHGlobal(buffer);
return w;
}
}
}