I have some C# code that allows the user to control a LabVIEW VI from a C# Windows Forms application.
As of right now, when the user clicks on the "open dialog" button, it opens the VI in another separate, LabVIEW-styled window. What I would like, if possible, is to have that window open as a child form inside the parent.
Everything else works as far as the LabVIEW/C# interface. I just would like to have everything self-contained in one aesthetically pleasing window.
Here's Form1.cs:
using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace LabVIEW_DLL_Call
{
public partial class Form1 : Form
{
[DllImport("user32.dll", SetLastError = true)]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("SharedLib.dll", CallingConvention = CallingConvention.Cdecl)]
static extern long Launch();
[DllImport("SharedLib.dll", CallingConvention=CallingConvention.Cdecl)]
static extern long SetParams(ushort signalType, double frequency, double amplitude);
[DllImport("SharedLib.dll", CallingConvention=CallingConvention.Cdecl)]
static extern long GetData(double[] Array, long len);
[DllImport("user32.dll")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void btnLaunch_Click(object sender, EventArgs e)
{
Launch();
var hWnd = FindWindow("dialog.vi", null);
SetParent(hWnd, panel1.Handle);
}
private void btnSetParams_Click(object sender, EventArgs e)
{
SetParams((ushort)this.dropSignalType.SelectedIndex, (double)this.numFreq.Value, (double)this.numAmplitude.Value);
}
private void btnGetData_Click(object sender, EventArgs e)
{
int dataCount = 1000;
double[] results = new double[dataCount];
GetData(results, dataCount);
string txt = String.Join("\r\n", results);
this.textBox1.Text = txt;
}
}
}
Basically, what happens is that Form2 loads up within Form1, but it also generates the LabVIEW window. (And the second photo is one of the launch.vi)
That's a great start!
It could look something like this:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
private const int SWP_NOSIZE = 0x0001;
private async void btnLaunch_Click(object sender, EventArgs e)
{
bool foundIt = false;
DateTime timeOut = DateTime.Now.AddSeconds(10);
Launch();
do
{
await Task.Delay(250);
var hWnd = FindWindow(null, "dialog.vi");
if (!hWnd.Equals(IntPtr.Zero))
{
SetParent(hWnd, panel1.Handle);
SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE);
foundIt = true;
}
}
while (!foundIt && (DateTime.Now <= timeOut));
if (!foundIt)
{
MessageBox.Show("Failed to find the LabView window.");
}
}
Related
Currently, I can open & close the windows touch keyboard,
I don't know how to detect the touch keyboard is popped up or not,
so I try to get windows style value,
when I click the button at the top-right corner, to hiding the touch keyboard, please reference this image
the windows style value is the same as I did not hide the touch keyboard,
Is there any way to detect this situation?
---Test code as below -------------------------------------------------------
namespace WindowsFormsApp7
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
CloseWindowsTouchKeyboard();
}
private void btnOpen_Click(object sender, EventArgs e)
{
OpenWindowsTouchKeyboard();
}
private void btnClose_Click(object sender, EventArgs e)
{
CloseWindowsTouchKeyboard();
}
private void btnGetWindowLong_Click(object sender, EventArgs e)
{
GetWindowLong();
}
private const string IPTIP_MAIN_WINDOW_CLASS_NAME = "IPTip_Main_Window";
private const int GWL_STYLE = -16;
private const int WM_SYSCOMMAND = 274;
private const uint SC_CLOSE = 61536;
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool PostMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowLong(IntPtr hWnd, int nIndex);
public static void OpenWindowsTouchKeyboard()
{
string strFilePath = #"C:\Program Files\Common Files\microsoft shared\ink\TabTip.exe";
if (!File.Exists(strFilePath))
{
return;
}
Process.Start(strFilePath);
}
public static void CloseWindowsTouchKeyboard()
{
IntPtr TouchhWnd;
TouchhWnd = FindWindow(IPTIP_MAIN_WINDOW_CLASS_NAME, null);
if (TouchhWnd == IntPtr.Zero)
{
return;
}
PostMessage(TouchhWnd, WM_SYSCOMMAND, SC_CLOSE, 0);
}
public static void GetWindowLong()
{
IntPtr tKeyboardHandle = FindWindow(IPTIP_MAIN_WINDOW_CLASS_NAME, null);
if (tKeyboardHandle != IntPtr.Zero)
{
uint iStyle = GetWindowLong(tKeyboardHandle, GWL_STYLE);
Console.WriteLine($"iStyle: {iStyle}");
}
}
}
}
You'll need to utilize ComImport to define interfaces manually:
[ComImport, Guid("228826af-02e1-4226-a9e0-99a855e455a6")]
class ImmersiveShellBroker { }
[ComImport, Guid("9767060c-9476-42e2-8f7b-2f10fd13765c")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IImmersiveShellBroker
{
void M();
IInputHostManagerBroker GetInputHostManagerBroker();
}
[ComImport, Guid("2166ee67-71df-4476-8394-0ced2ed05274")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IInputHostManagerBroker { void GetIhmLocation(out Bounds rect, out DisplayMode mode); }
[StructLayout(LayoutKind.Sequential)]
struct Bounds { public int Left, Top, Right, Bottom; }
enum DisplayMode { None = 0, Floating = 2, Docked = 3 }
Then you can use them to check the touch keyboard display mode like so,
IImmersiveShellBroker broker = (IImmersiveShellBroker)(new ImmersiveShellBroker());
IInputHostManagerBroker inputHost = broker.GetInputHostManagerBroker();
Marshal.ReleaseComObject(broker);
// if mode != DisplayMode.None then the keyboard is open
DisplayMode mode;
inputHost.GetIhmLocation(out _, out mode);
you can also cache the inputHost somewhere, but it's not necessary.
I've currently got another process running inside a form, and I want to be able to simulate mouse clicks in that process without affecting my real mouse and without the need to have the form window active. I've only been working with c# for a few days so I'm not sure if this is even possible.
Currently I'm listening for clicks on the form itself, which works since I can see the console log "Form clicked", however I don't see any clicks occurring inside the process.
Here's the code I have so far:
public partial class Form1 : Form
{
private const int WM_LBUTTONDOWN = 0x0201;
private const int WM_LBUTTONUP = 0x0202;
public Form1()
{
InitializeComponent();
startProcess();
}
private void startProcess()
{
Process p = Process.Start("notepad.exe");
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, Handle);
}
private void formClick(object sender, EventArgs e)
{
Console.WriteLine("Form clicked");
Thread.Sleep(500);
PostMessage(FindWindow(null, "Form1"), WM_LBUTTONDOWN, new IntPtr(0x1), CreateLParam(MousePosition.X + 50, MousePosition.Y + 50));
PostMessage(FindWindow(null, "Form1"), WM_LBUTTONUP, new IntPtr(0x1), CreateLParam(MousePosition.X + 50, MousePosition.Y + 50));
}
private static IntPtr CreateLParam(int LoWord, int HiWord)
{
return (IntPtr)((HiWord << 16) | (LoWord & 0xffff));
}
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]
public static extern bool PostMessage(IntPtr hwnd, uint Msg, IntPtr wParam, IntPtr lParam);
}
I have a wpf application which is in maximized state always without showing taskbar.
Here is the code for Hiding and showing taskbar.
[DllImport("user32.dll")]
private static extern int FindWindow(string className, string windowText);
[DllImport("user32.dll")]
private static extern int ShowWindow(int hwnd, int command);
private const int SW_HIDE = 0;
private const int SW_SHOW = 1;
static int hwnd = FindWindow("Shell_TrayWnd", "");
public static new void Hide()
{
ShowWindow(hwnd, SW_HIDE);
}
public static new void Show()
{
ShowWindow(hwnd, SW_SHOW);
}
This is working fine on windows 7. But when application runs on Windows 10.. taskbar didnt show up again by calling show().
Here is the part where I am calling show()
#region Show Desktop
private void Desktop_MouseUp(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left )
{
this.WindowState = System.Windows.WindowState.Minimized;
Shell32.Shell objShel = new Shell32.Shell();
objShel.MinimizeAll();
Show();
}
}
#endregion
This works on the main display and is taken from here and converted to c#.
public static class Taskbar
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr FindWindow(
string lpClassName,
string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
private static extern int SetWindowPos(
IntPtr hWnd,
IntPtr hWndInsertAfter,
int x,
int y,
int cx,
int cy,
uint uFlags
);
[Flags]
private enum SetWindowPosFlags : uint
{
HideWindow = 128,
ShowWindow = 64
}
public static void Show()
{
var window = FindWindow("Shell_traywnd", "");
SetWindowPos(window, IntPtr.Zero, 0, 0, 0, 0, (uint) SetWindowPosFlags.ShowWindow);
}
public static void Hide()
{
var window = FindWindow("Shell_traywnd", "");
SetWindowPos(window, IntPtr.Zero, 0, 0, 0, 0, (uint)SetWindowPosFlags.HideWindow);
}
}
I've seen loads of code to launch an external application via a file, but that's not the problem. To clarify exactly the behaviour I want:
For a given filename, launch the correct process.
If there is no associated process, the proper shell dialog should prompt the user to associate one.
While the application is launched, this application needs to go to the back of the Z-order (or just behind the app that is launching) and STAY THERE.
Step 3 is what I haven't got right. I am launching Photoshop via a psd file, but while the aplash screen is shown, it flashes as my app fights for the focus. Once it starts up properly, all is well, but I don't like the flickering while the flash screen is displayed.
Here is my best attempt so far:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Romy.Core
{
internal static class Example
{
public const int SW_RESTORE = 9;
private static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
private const uint SWP_NOACTIVATE = 0x0010;
private const uint SWP_NOMOVE = 0x0002;
private const uint SWP_NOSIZE = 0x0001;
public static void SendWindowBack(IntPtr handle)
{
NativeMethods.SetWindowPos(handle, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
}
public static async void ShellExecuteFile(this IWin32Window window, string filename)
{
var p = Process.Start(new ProcessStartInfo()
{
FileName = filename,
Verb = "open",
UseShellExecute = true,
ErrorDialog = true
});
SendWindowBack(window.Handle);
try
{
await Task.Run(async () =>
{
try
{
p.WaitForInputIdle();
IntPtr handle = p.MainWindowHandle;
while (handle == IntPtr.Zero)
{
await Task.Delay(TimeSpan.FromMilliseconds(250D));
handle = p.MainWindowHandle;
}
if (handle != IntPtr.Zero)
{
if (NativeMethods.IsIconic(handle))
NativeMethods.ShowWindowAsync(handle, SW_RESTORE);
if (NativeMethods.SetForegroundWindow(handle))
NativeMethods.SetActiveWindow(handle);
}
}
catch (InvalidOperationException) { }
catch (PlatformNotSupportedException) { }
catch (NotSupportedException) { }
catch (Exception ex) { ex.Log(); }
}).TimeoutAfter(TimeSpan.FromSeconds(3D));
}
catch (TimeoutException) { }
}
[SuppressUnmanagedCodeSecurity]
internal static class NativeMethods
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool IsIconic(System.IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetForegroundWindow(System.IntPtr hWnd);
[DllImport("user32.dll")]
internal static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ShowWindowAsync(System.IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
internal static extern System.IntPtr SetActiveWindow(System.IntPtr hWnd);
}
}
}
Try removing your call to SendWindowBack and replace SetForegroundWindow with SetWindowLong. This should meet your requierment:
...(or just behind the app that is launching) and STAY THERE..
const int GWL_HWNDPARENT = (-8);
[DllImport("user32.dll", SetLastError = true)]
static extern int SetWindowLong(IntPtr childHandle, int nIndex, IntPtr parentHandle);
if (handle != IntPtr.Zero)
{
if (NativeMethods.IsIconic(handle))
NativeMethods.ShowWindowAsync(handle, SW_RESTORE);
SetWindowLong(handle, GWL_HWNDPARENT, window.Handle)
NativeMethods.SetActiveWindow(handle);
}
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");