I'm Running a forms application and a console application in one application.
How can i run the forms application and keep the console closed until i click a button on the form?
You need to call a couple of win32app calls most specifically allocconsole. here is an msdn post with some sample code.
You'll need to do a little P/Invoke:
Add the appropriate methods:
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 StackOverflow.Extensions;
using System.Runtime.InteropServices;
using System.IO;
using Microsoft.Win32.SafeHandles;
namespace StackOverflow
{
public partial class FormMain : Form
{
[DllImport("kernel32.dll",
EntryPoint = "GetStdHandle",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll",
EntryPoint = "AllocConsole",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern int AllocConsole();
// Some constants
private const int STD_OUTPUT_HANDLE = -11;
private const int MY_CODE_PAGE = 437;
public FormMain()
{
InitializeComponent();
}
public void PrepareConsole()
{
AllocConsole();
IntPtr stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
SafeFileHandle safeFileHandle = new SafeFileHandle(stdHandle, true);
FileStream fileStream = new FileStream(safeFileHandle, FileAccess.Write);
Encoding encoding = System.Text.Encoding.GetEncoding(MY_CODE_PAGE);
StreamWriter standardOutput = new StreamWriter(fileStream, encoding);
standardOutput.AutoFlush = true;
Console.SetOut(standardOutput);
}
private void button1_Click(object sender, EventArgs e)
{
// Console was not visible before this button click
Console.WriteLine("This text is written to the console that just popped up.");
MessageBox.Show("But we're still in a Windows Form application.");
}
}
}
Related
Where are the Windows system menu icons stored?
I'm talking about the icons on the system context menu.
I want to put them in my application.
You can get images using the LoadBitmap function.
Example (c#):
namespace GetBitmap
{
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
internal static class Program
{
private const long OBM_RESTORED = 32744;
private static void Main()
{
var hBitmap = LoadBitmap(IntPtr.Zero, OBM_RESTORED);
var image = Image.FromHbitmap(hBitmap);
image.Save(#"d:\restored.png", ImageFormat.Png);
DeleteObject(hBitmap);
}
[DllImport("user32.dll")]
private static extern IntPtr LoadBitmap(IntPtr hInstance, long resourceId);
[DllImport("gdi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeleteObject([In] IntPtr hObject);
}
}
I have been struggling with this for quite a while and could not get any answer I understand. I am new to c#.
So I am launching an application (Accpac to be specific) then I need to send the username via sendkeys/sendmessage to a child window. I've got the handle of the childwindow but I can't get it to work: IntPtr.(00020380), I get the error "Identifier expected"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Windows.Forms;
using System.Threading;
namespace myNamespace
{
class StartAccpac
{
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
public static void Main3()
{
//START ACCPAC
//Process.Start("C:\\Programs\\Accpac\\runtime\\accpac.exe");
IntPtr hwnd = IntPtr.Zero;
IntPtr hwndChild = IntPtr.Zero;
//Get a MAIN HANDLE
hwnd = FindWindow(null, "Open Company");
hwndChild = FindWindowEx(hwnd, IntPtr.(00020380), null, null); <---- ERROR
}
}
}
Your problem is here:
IntPtr.(00020380)
What you need to do is something like this:
new IntPtr(00020380)
However I suspect, being eight digits and looking at your screenshot this is a hex number so you might also want to consider:
new IntPtr(0x00020380)
Have a play with those, see what happens.
UPD: added MCVE.
This is an educational task. I have to use SendMessage() function:
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd,
uint wMsg, UIntPtr wParam, IntPtr lParam);
I have to make two different applications with GUI communicationg by messages. After getting message like "start" 1 app have to start sendinding message "Ask value" to 2 app each 5 seconds. And 2 app send to 1 app message "Send value" with some data.
1 app is WinForms program:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace Oven_Monitor
{
public partial class Form1 : Form
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetCurrentProcessId();
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, UIntPtr wParam, IntPtr lParam);
private uint askMessageID = RegisterWindowMessage("Ask value");
private uint dataMessageID = RegisterWindowMessage("Send value");
private uint registerMessageID = RegisterWindowMessage("Register sensor");
public Form1() {
InitializeComponent();
this.Text = "Really rare title";
}
public void checkSensors() {
while (true) {
SendMessage(secondAppHWnd, askMessageID, (UIntPtr)0, (IntPtr)0);
System.Threading.Thread.Sleep(500);
}
}
private IntPtr secondAppHWnd;
protected override void WndProc(ref Message m) {
if (m.Msg == registerMessageID) {
secondAppHWnd = m.LParam;
Thread tr = new Thread(checkSensors);
tr.Start();
} else if (m.Msg == dataMessageID) {
//do some stuff
}
base.WndProc(ref m);
}
}
}
2 app is console project, but it requires System.Windows.Forms referens:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace HeatSensor
{
class Program
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
static void Main(string[] args)
{
IntPtr mainAppHandle = FindWindow(null, "Really rare title");
while (mainAppHandle == IntPtr.Zero)
{
Console.ReadKey();
mainAppHandle = FindWindow(null, "Really rare title");
}
HiddenForm form = new HiddenForm(mainAppHandle);
while (true) //it's actually not infinit
{
//do some stuff
}
}
}
}
And hidden form class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace HeatSensor
{
public partial class HiddenForm : Form
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, UIntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
static private IntPtr mainAppHandle;
public HiddenForm(IntPtr mainAppHWnd)
{
InitializeComponent();
mainAppHandle = mainAppHWnd;
string title = System.DateTime.Now.ToLongDateString();
title += System.DateTime.Now.ToLongTimeString();
title += System.DateTime.Now.Ticks.ToString();
this.Text = title;
this.CreateHandle();
int currentWindowHandle = (int)FindWindow(null, title);
SendMessage(mainAppHandle, RegisterWindowMessage("Register sensor"),
(UIntPtr)0, currentWindowHandle);
}
private uint askMessageID = RegisterWindowMessage("Ask value");
private uint dataMessageID = RegisterWindowMessage("Send value");
private uint registerMessageID = RegisterWindowMessage("Register sensor");
protected override void WndProc(ref Message m)
{
if (m.Msg == askMessageID)
{
SendMessage(mainAppHandle, dataMessageID, (UIntPtr)1, (IntPtr)1);
}
base.WndProc(ref m);
}
}
}
For some reason this programs act strange. Almost everytime 2 app don't getting sended "Ask value" message, sometimes checkSensors() send 1-3 messages and stop.
What is wrong?
Both HWnd is correct.
Update: I tried to check error here:
public void checkSensors() {
while (true) {
SendMessage(secondAppHWnd, askMessageID, (UIntPtr)0, (IntPtr)0);
int error = Marshal.GetLastWin32Error();
System.Threading.Thread.Sleep(500);
}
}
And see. As SendMessage was performed, this thread was blocked (what means, SendMessage was not copleted. After i closed 2 app, thread was unblocked and i got 164 error (ERROR_MAX_THRDS_REACHED: No more threads can be created in the system.). What it's supposed to mean?
Also, added:
protected override void WndProc(ref Message m)
{
//here is all message checks
int erro2r = Marshal.GetLastWin32Error();
if (erro2r != 0) {
int j; //stop to debug here
}
base.WndProc(ref m);
}
And it just constantly return 1400 ERROR_INVALID_WINDOW_HANDLE (i don't send any messages at that moment).
So it looks totaly unclear to me.
update 2: If i call it from WndProc(), everything works:
SendMessage(secondAppHWnd, askMessageID, (UIntPtr)0, (IntPtr)0);
But i need to send this message from different thread each 5 seconds.
So, it finally works if both programs is WinForms projects. I can just run console window from 2 app and hide main window.
I have the following code which keeps returning FALSE with a value of 8 from the GetLastError() call.
8 apparently is ERROR_NOT_ENOUGH_MEMORY.
I of course have enough memory, but the process doesn't think so, can anyone enlighten me as to what could be going wrong?
The code below is all I have except for the Forms objects declarations of course, but I guess there is no need to see this as I have 2 text boxes and 1 button.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace AddConsoleAlias
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("kernel32", SetLastError = true)]
static extern bool AddConsoleAlias(string Source, string Target, string ExeName);
[DllImport("kernel32.dll")]
static extern uint GetLastError();
private void btnAddAlias_Click(object sender, EventArgs e)
{
if (AddConsoleAlias(txbSource.Text, txbTarget.Text, "cmd.exe"))
{
MessageBox.Show("Success");
}
else
{
MessageBox.Show(String.Format("Problem occured - {0}", GetLastError()));
}
}
}
}
AddConsoleAlias defines console alias. You have Windows Forms application without opened console. Console should be allocated before AddConsoleAlias invoke. To do that you can use AllocConsole function.
C# binding for this function is:
[DllImport("kernel32.dll",
EntryPoint = "AllocConsole",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern int AllocConsole();
Your modified code will look like:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("kernel32.dll",
EntryPoint = "AllocConsole",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern int AllocConsole();
[DllImport("kernel32", SetLastError = true)]
static extern bool AddConsoleAlias(string Source, string Target, string ExeName);
[DllImport("kernel32.dll")]
static extern uint GetLastError();
private void btnAddAlias_Click(object sender, EventArgs e)
{
AllocConsole();
if (AddConsoleAlias(txbSource.Text, txbTarget.Text, "cmd.exe"))
{
MessageBox.Show("Success");
}
else
{
MessageBox.Show(String.Format("Problem occured - {0}", GetLastError()));
}
}
}
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