Console output in winforms GUI application - c#

all!
Please, help me with any advice with my problem: I build GUI WinForms application and now I want to attach console to it. I found this is not as much easy as it seems before. But I found good solution here: How do I show a console output/window in a forms application? Below the code from rag answer.
using System;
using System.Runtime.InteropServices;
namespace SomeProject
{
class GuiRedirect
{
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool AttachConsole(int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetStdHandle(StandardHandle nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetStdHandle(StandardHandle nStdHandle, IntPtr handle);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern FileType GetFileType(IntPtr handle);
private enum StandardHandle : uint
{
Input = unchecked((uint)-10),
Output = unchecked((uint)-11),
Error = unchecked((uint)-12)
}
private enum FileType : uint
{
Unknown = 0x0000,
Disk = 0x0001,
Char = 0x0002,
Pipe = 0x0003
}
private static bool IsRedirected(IntPtr handle)
{
FileType fileType = GetFileType(handle);
return (fileType == FileType.Disk) || (fileType == FileType.Pipe);
}
public static void Redirect()
{
if (IsRedirected(GetStdHandle(StandardHandle.Output)))
{
var initialiseOut = Console.Out;
}
bool errorRedirected = IsRedirected(GetStdHandle(StandardHandle.Error));
if (errorRedirected)
{
var initialiseError = Console.Error;
}
AttachConsole(-1);
if (!errorRedirected)
SetStdHandle(StandardHandle.Error, GetStdHandle(StandardHandle.Output));
}
}
This code works as charm except one downside: non-latin letters outputs to console in strange encoding (but if redirected to file, they are in right encoding). I need to redirect both StdOut and StdErr, and if I change any part of the code it stops redirecting.

Thanks to all who share their wisdom with me in comments!
SetConsoleOutputCP was the answer.
Don't forget put this to other definitions of the class.
[DllImport("kernel32.dll")]
static extern bool SetConsoleOutputCP(uint wCodePageID);
And than add call of the SetConsoleOutputCP(desired codepage); to Redirect() method.

Related

How to get the user's wallpaper

As the title
I would like the effect like UAC's background
Here is a code I found from web.
using System;
using System.Runtime.InteropServices;
namespace cleandesktop
{
internal static class Program
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SystemParametersInfo(uint uAction, uint uParam, StringBuilder lpvParam, uint init);
const uint SPI_GETDESKWALLPAPER = 0x0073;
static void Main(string[]) args
{
StringBuilder wallPaperPath = new StringBuilder(200);
if (SystemParametersInfo(SPI_GETDESKWALLPAPER, 200, wallPaperPath, 0))
{
MessageBox.Show(wallPaperPath.ToString());
}
}
}
}
This code get the path of the wallpaper picture, but this code only works when users hadn't delete their wallpaper picture.
PaintDesktop
The PaintDesktop function fills the clipping region in the specified device context with the desktop pattern or wallpaper.

Send data from c# program to c++ dll (DeskBand)

Guys I'm stuck at the final part of a functional deskband implementation for my application,
For context, I'm currently running a visual studio solution with 2 projects in them,
one is the c++ deskband dll and another is a simple c# console program.
The DeskBand code is Microsoft's DeskBand sample
Currently, I can register the dll when the console app runs by calling the "DllRegisterServer" with GetProcAddress(). After this I'll simply right-click the taskbar and enable the registered deskband.
My question comes from here on,
Once registered, let's say the OnPaint event in the Deskband implementation paints a text variable called "Hello world", What I want to do is simply send a string from c# to the running dll and make it paint "Sent from c#".
The register class:
public class Registrar
{
private IntPtr hLib;
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool FreeLibrary(IntPtr hModule);
internal delegate int PointerToMethodInvoker();
public Registrar(string filePath)
{
hLib = LoadLibrary(filePath);
if (IntPtr.Zero == hLib)
{
int errno = Marshal.GetLastWin32Error();
throw new Win32Exception(errno, "Failed to load library.");
}
}
public void RegisterComDLL()
{
CallPointerMethod("DllRegisterServer");
}
public void UnRegisterComDLL()
{
CallPointerMethod("DllUnregisterServer");
}
private void CallPointerMethod(string methodName)
{
IntPtr dllEntryPoint = GetProcAddress(hLib, methodName);
if (IntPtr.Zero == dllEntryPoint)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
PointerToMethodInvoker drs =
(PointerToMethodInvoker)Marshal.GetDelegateForFunctionPointer(dllEntryPoint,
typeof(PointerToMethodInvoker));
drs();
}
public void FreeLib()
{
if (IntPtr.Zero != hLib)
{
FreeLibrary(hLib);
hLib = IntPtr.Zero;
}
}
}
The simple console program:
static void Main(string[] args)
{
Console.WriteLine("Start");
Registrar reg = new Registrar("DeskBandDLL.dll");
if (reg != null)
{
reg.RegisterComDLL();
//send data to the registered dll to start painting new text
Console.ReadLine();
reg.UnRegisterComDLL();
reg.FreeLib();
}
}
Btw, I do know that Microsoft discontinued deskband in win11, but I really want to implement this feature for only the win10 platform and I feel like I'm close to finishing this.
And if you need the full code for clarification, I can host it on GitHub.

Import C++ dll in C# project

I have a C++ dll for monitoring printers (using FindFirstPrinterChangeNotification). I am making C# Wrapper for it:
private static class NativeMethods {
[DllImport("kernel32", SetLastError = true)]
public static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32", SetLastError = true)]
public static extern bool FreeLibrary(IntPtr hModule);
}
public string LibPath;
private IntPtr LibPtr;
private GBtMX GBtMain;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void GBtMX();
public GhostBuster() {
LibPath = AppDomain.CurrentDomain.BaseDirectory + #"\GhostBusterC.dll";
}
public string Init() {
if (!File.Exists(LibPath))
return "Incorrect path " + LibPath;
LibPtr = NativeMethods.LoadLibrary(LibPath);
if (LibPtr == IntPtr.Zero)
return "Couldn't import library. Error(GetLastWin32Error): " + Marshal.GetLastWin32Error().ToString();
IntPtr GBtMainPtr = NativeMethods.GetProcAddress(LibPtr, "tmain");
if (GBtMainPtr == IntPtr.Zero)
return "No access to GhostBuster.tmain. Error (GetLastWin32Error): " + Marshal.GetLastWin32Error().ToString();
GBtMain = (GBtMX)Marshal.GetDelegateForFunctionPointer(GBtMainPtr, typeof(GBtMX));
return "";
It returns "No access to GhostBuster.tmain. Error (GetLastWin32Error): 0".
What am i doing wrong?
Thanks in advance.
You don't specify SetLastError in your p/invoke, so that's why Marshal.GetLastWin32Error() is failing to return anything useful. The p/invoke should be
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetProcAddress(
IntPtr hModule,
[MarshalAs(UnmanagedType.LPStr)]
string lpProcName
);
Note also that it makes sense to be explicit about the marshaling of the procedure name. That is always an ANSI string, reflecting the PE format.
When you make this change I expect that the error will be ERROR_PROC_NOT_FOUND indicating that the DLL does not export anything with the name that you passed to GetProcAddress.
Check that you spelled the function name correctly. Did you get the letter case right? Is there any decoration or mangling applied when the DLL is built? Use a tool like dumpbin or Dependency Walker to check the names of the DLL's exports.

How do I see if my form is currently on top of the other ones?

Basically, how do I tell if my program is layered above all the other ones?
A fairly simple way is to P/Invoke GetForegroundWindow() and compare the HWND returned to the application's form.Handle property.
using System;
using System.Runtime.InteropServices;
namespace MyNamespace
{
class GFW
{
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
public bool IsActive(IntPtr handle)
{
IntPtr activeHandle = GetForegroundWindow();
return (activeHandle == handle);
}
}
}
Then, from your form:
if (MyNamespace.GFW.IsActive(this.Handle))
{
// Do whatever.
}
You can use:
if (GetForegroundWindow() == Process.GetCurrentProcess().MainWindowHandle)
{
//do stuff
}
WINAPI imports (at class level):
[System.Runtime.InteropServices.DllImport("user32.dll")] public static extern bool GetForegroundWindow();
Assign a property to hold the value, and add the check to the form's GotFocus event through IDE, or after InitializeComponent();
e.g.:
//.....
InitalizeComponent();
this.GotFocus += (myFocusCheck);
//...
private bool onTop = false;
private void myFocusCheck(object s, EventArgs e)
{
if(GetFore......){ onTop = true; }
}
If your window inherits form, you can check Form.Topmost property
A good solution is given by this answer to an identical question:
https://stackoverflow.com/a/7162873/386091
/// <summary>Returns true if the current application has focus, false otherwise</summary>
public static bool ApplicationIsActivated()
{
var activatedHandle = GetForegroundWindow();
if (activatedHandle == IntPtr.Zero) {
return false; // No window is currently activated
}
var procId = Process.GetCurrentProcess().Id;
int activeProcId;
GetWindowThreadProcessId(activatedHandle, out activeProcId);
return activeProcId == procId;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
The currently accepted solution by Euric doesn't work if your program shows a dialog box or has detachable windows (like if you use a windows docking framework).

Is it possible to write a windows application that gets a notification when text is selected in another windows application?

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;
}
}
}

Categories