I'm developping an application in WPF that host an Unity application.
This hosting is set by using a HwndHost class (because the unity way with the _hwndparent argument seems don(t work).
In the BuilWindowCore of my HwndHost class, I need to change the window child style using GetWindowLong and SetWindowLong.
All of these works perfectly on my developping computer. But I can't use the application on another computer.
When I just set WS_CCHILD value (without retrieving the style using GetWindowLong) ther isn't crash on all computers, but the child application not appeared correctly (Maximized etc..). That's why I think the problem is about the styling child window part.
There is my HwndHost class code:
public class UnityHwndHost : HwndHost
{
private Process _process;
private HandleRef _hwnd;
private IntPtr _unityHWND; // = IntPtr.Zero;
private const int GWL_STYLE = -16;
// Window Styles
const UInt32 WS_OVERLAPPED = 0;
const UInt32 WS_POPUP = 0x80000000;
const UInt32 WS_CHILD = 0x40000000;
const UInt32 WS_MINIMIZE = 0x20000000;
const UInt32 WS_VISIBLE = 0x10000000;
const UInt32 WS_DISABLED = 0x8000000;
const UInt32 WS_CLIPSIBLINGS = 0x4000000;
const UInt32 WS_CLIPCHILDREN = 0x2000000;
const UInt32 WS_MAXIMIZE = 0x1000000;
const UInt32 WS_CAPTION = 0xC00000; // WS_BORDER or WS_DLGFRAME
const UInt32 WS_BORDER = 0x800000;
const UInt32 WS_DLGFRAME = 0x400000;
const UInt32 WS_VSCROLL = 0x200000;
const UInt32 WS_HSCROLL = 0x100000;
const UInt32 WS_SYSMENU = 0x80000;
const UInt32 WS_THICKFRAME = 0x40000;
const UInt32 WS_GROUP = 0x20000;
const UInt32 WS_TABSTOP = 0x10000;
const UInt32 WS_MINIMIZEBOX = 0x20000;
const UInt32 WS_MAXIMIZEBOX = 0x10000;
const UInt32 WS_TILED = WS_OVERLAPPED;
const UInt32 WS_ICONIC = WS_MINIMIZE;
const UInt32 WS_SIZEBOX = WS_THICKFRAME;
// Extended Window Styles
const UInt32 WS_EX_DLGMODALFRAME = 0x0001;
const UInt32 WS_EX_NOPARENTNOTIFY = 0x0004;
const UInt32 WS_EX_TOPMOST = 0x0008;
const UInt32 WS_EX_ACCEPTFILES = 0x0010;
const UInt32 WS_EX_TRANSPARENT = 0x0020;
const UInt32 WS_EX_MDICHILD = 0x0040;
const UInt32 WS_EX_TOOLWINDOW = 0x0080;
const UInt32 WS_EX_WINDOWEDGE = 0x0100;
const UInt32 WS_EX_CLIENTEDGE = 0x0200;
const UInt32 WS_EX_CONTEXTHELP = 0x0400;
const UInt32 WS_EX_RIGHT = 0x1000;
const UInt32 WS_EX_LEFT = 0x0000;
const UInt32 WS_EX_RTLREADING = 0x2000;
const UInt32 WS_EX_LTRREADING = 0x0000;
const UInt32 WS_EX_LEFTSCROLLBAR = 0x4000;
const UInt32 WS_EX_RIGHTSCROLLBAR = 0x0000;
const UInt32 WS_EX_CONTROLPARENT = 0x10000;
const UInt32 WS_EX_STATICEDGE = 0x20000;
const UInt32 WS_EX_APPWINDOW = 0x40000;
const UInt32 WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
const UInt32 WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST);
const UInt32 WS_EX_LAYERED = 0x00080000;
const UInt32 WS_EX_NOINHERITLAYOUT = 0x00100000; // Disable inheritence of mirroring by children
const UInt32 WS_EX_LAYOUTRTL = 0x00400000; // Right to left mirroring
const UInt32 WS_EX_COMPOSITED = 0x02000000;
const UInt32 WS_EX_NOACTIVATE = 0x08000000;
private const int WM_ACTIVATE = 0x0006;
private readonly IntPtr WA_ACTIVE = new IntPtr(1);
private readonly IntPtr WA_INACTIVE = new IntPtr(0);
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, UInt32 dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
private static extern UInt32 GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32")]
private static extern IntPtr SetParent(IntPtr hWnd, IntPtr hWndParent);
internal delegate int WindowEnumProc(IntPtr hwnd, IntPtr lparam);
[DllImport("user32.dll")]
internal static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc func, IntPtr lParam);
[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern bool IsWindow(IntPtr hWnd);
#region CONSTRUCTORS
#endregion
#region METHODS
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
var context = DataContext as UltrasoundVM;
var psi = new ProcessStartInfo("UnityStandAlone.exe");
psi.Arguments = "\"" + context.Workspace.Replace('\\', '/') + "\" " + context.SelectedFlexible;
LoggerHelper.Write(GetType().FullName + "." + new StackTrace().GetFrame(0).GetMethod().Name + " : " + psi.Arguments, EventLogEntryType.Information);
psi.WindowStyle = ProcessWindowStyle.Minimized;
_process = Process.Start(psi);
_process.WaitForInputIdle();
while (_process.MainWindowHandle == IntPtr.Zero || !IsWindow(_process.MainWindowHandle))
{
Thread.Yield();
}
_unityHWND = _process.MainWindowHandle;
SetParent(_unityHWND, hwndParent.Handle);
var style = GetWindowLong(_unityHWND, GWL_STYLE);
style = style & ~WS_CAPTION & ~WS_THICKFRAME; // Removes Caption bar and the sizing border
style |= (WS_CHILD); // Must be a child window to be hosted
SetWindowLong(_unityHWND, GWL_STYLE, style);
SetWindowLong(_unityHWND, GWL_STYLE, WS_CHILD | WS_MAXIMIZE);
SendMessage(_unityHWND, WM_ACTIVATE, WA_ACTIVE, IntPtr.Zero);
_hwnd = new HandleRef(this, _unityHWND);
return _hwnd;
}
protected override void DestroyWindowCore(HandleRef hwnd)
{
SendMessage(_hwnd.Handle, WM_ACTIVATE, WA_INACTIVE, IntPtr.Zero);
_process.CloseMainWindow();
_process.WaitForExit(5000);
if (_process.HasExited == false)
{
_process.Kill();
}
_process.Close();
_process.Dispose();
_process = null;
}
#endregion
}
Notes:
Developping Computer
- OS : Windows 10 Home edition
- Unity 3D 5.5.2.f.1 free edition
Testing Computers
- OS : Windows 10 (Home edition & Pro Edition)
Of course I've tried to build the unity application with different parameters, same thing with my parent application.
OK
It seems that the problem came from my unity stand alone which was not the same between my sources and my debug folder.
Related
I have a security program for my schools. What i need,
I keep my Windows form up until I'm allowed to.
I can partially do with the following codes..
<code>
private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
private const UInt32 SWP_NOSIZE = 0x0001;
private const UInt32 SWP_NOMOVE = 0x0002;
private const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);</code>
But
the above code.
Does not work in task view(windows 10)
preview
I'm trying to put the Virtual Keyboard of Win 10 Borderless
But don't know why it's not working.
I tried with NotePad and it's working.
( I did a Debug.log to check if IntPtr is not null and in both case it return true)
Here's what I did
using UnityEngine;
using System;
using System.Runtime.InteropServices;
public class test : MonoBehaviour
{
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string className, string windowName);
[DllImport("USER32.DLL")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("USER32.DLL")]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
const int WS_BORDER = 8388608;
const int WS_DLGFRAME = 4194304;
const int WS_CAPTION = WS_BORDER | WS_DLGFRAME;
const int WS_SYSMENU = 524288;
const int WS_THICKFRAME = 262144;
const int WS_MINIMIZE = 536870912;
const int WS_MAXIMIZEBOX = 65536;
const int GWL_STYLE = -16;
const int GWL_EXSTYLE = -20;
const int WS_EX_DLGMODALFRAME = 0x1;
const int SWP_NOMOVE = 0x2;
const int SWP_NOSIZE = 0x1;
const int SWP_FRAMECHANGED = 0x20;
const uint MF_BYPOSITION = 0x400;
const uint MF_REMOVE = 0x1000;
private void Borderless() {
// IntPtr hWnd = FindWindow(null,"On-Screen Keyboard"); // <----- Not Working
IntPtr hWnd = FindWindow(null,"Untitled - NotePad"); // <----- Working
if (hWnd != IntPtr.Zero)
{
int Style = 0;
Style = GetWindowLong(hWnd, GWL_STYLE);
Style = Style & ~WS_CAPTION;
Style = Style & ~WS_SYSMENU;
Style = Style & ~WS_THICKFRAME;
Style = Style & ~WS_MINIMIZE;
Style = Style & ~WS_MAXIMIZEBOX;
SetWindowLong(hWnd, GWL_STYLE, Style);
Style = GetWindowLong(hWnd, GWL_EXSTYLE);
SetWindowLong(hWnd, GWL_EXSTYLE, Style | WS_EX_DLGMODALFRAME);
SetWindowPos(hWnd, new IntPtr(0), 50, 0, 150, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
}
else
{
Debug.LogWarning("Borderless() failed, hWnd is 0!");
}
}
void Start()
{
Borderless();
}
}
Thanks Guys ;)
Ok I get another Solution, Maybe a better one.
On-Screen Keyboard on Unity
I know it's not a real answer so if someone know why the code above is not working, I'll be glad to learn ;)
I am trying to host a .exe within my .net application (Mainly video viewing software) however certain applications do not allow me to use their menu's or some controls. Has anyone had this problem before or any idea of why it could be happening?
Here is my code to host the application:
#region Methods/Consts for Embedding a Window
[DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
private static extern long GetWindowThreadProcessId(long hWnd, long lpdwProcessId);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
private static extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true)]
private static extern long GetWindowLong(IntPtr hwnd, int nIndex);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
private static extern long SetWindowPos(IntPtr hwnd, long hWndInsertAfter, long x, long y, long cx, long cy, long wFlags);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
[DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]
private static extern bool PostMessage(IntPtr hwnd, uint Msg, int wParam, int lParam);
private const int SWP_NOOWNERZORDER = 0x200;
private const int SWP_NOREDRAW = 0x8;
private const int SWP_NOZORDER = 0x4;
private const int SWP_SHOWWINDOW = 0x0040;
private const int WS_EX_MDICHILD = 0x40;
private const int SWP_FRAMECHANGED = 0x20;
private const int SWP_NOACTIVATE = 0x10;
private const int SWP_ASYNCWINDOWPOS = 0x4000;
private const int SWP_NOMOVE = 0x2;
private const int SWP_NOSIZE = 0x1;
private const int GWL_STYLE = (-16);
private const int WS_VISIBLE = 0x10000000;
private const int WM_CLOSE = 0x10;
private const int WS_CHILD = 0x40000000;
private const int WS_MAXIMIZE = 0x01000000;
#endregion
#region Variables
private IntPtr hostedProcessHandle;
private Process hostedProcess = null;
private ProcessStartInfo hostedPSI = new ProcessStartInfo();
#endregion
//Helper method to start a process contained within the form
private void HostProcess(string processPath)
{
//Start the process located at processPath
hostedPSI.FileName = processPath;
hostedPSI.Arguments = "";
hostedPSI.WindowStyle = ProcessWindowStyle.Maximized;
hostedProcess = System.Diagnostics.Process.Start(hostedPSI);
//Stop watch is used to calculate time out period.
Stopwatch sw = new Stopwatch();
sw.Start();
//Loop to aquire application handle. Exit loop if the time out period is past.
do
{
hostedProcessHandle = hostedProcess.MainWindowHandle;
if (sw.ElapsedMilliseconds > 10000) throw new TimeoutException();
} while (hostedProcessHandle == new IntPtr(0));
//Host the process in the forms panel.
SetParent(hostedProcessHandle, this.panel1.Handle);
SetWindowLong(hostedProcessHandle, GWL_STYLE, WS_VISIBLE + WS_MAXIMIZE);
MoveWindow(hostedProcessHandle, 10, 10, this.panel1.Width - 20, this.panel1.Height - 20, true);
}
private void CloseHostedProcess()
{
hostedProcess.Kill();
}
Here is a screen shot of my test application hosting VLC, Some of the menu's and buttons as you can see are grayed out and not working:
This is not just a problem with VLC — I see this issue when hosting other applications too.
Just an update. If i right click on VLC -> Play -> Add and play a video back manually the menu bar works again. However the video controls at the bottom are still not working! They change color when rolled over but clicking them still doesn't work!
The reason I was experiencing problems seems to be because TeamViewer was running in the background. I am currently trying to find out why this causes me issues but stopping TeamViewer's process seems to rectify my problem.
I have a window in an application, and the Resize mode is set to NoResize, but if you click the top-left of the window, the menu items of "Maximize", "Minimize", and "Size" are still enabled. This only happens to my windows that has no icon but still has the close button. Meaning this problem isn't happening to my windows that do have an icon.
This is the code that is removing the icon but still keeps the red close button:
protected override void OnSourceInitialized(EventArgs e) {
IconHelper.RemoveIcon(this);
}
public static class IconHelper {
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int width, int height, uint flags);
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);
const int GWL_EXSTYLE = -20;
const int WS_EX_DLGMODALFRAME = 0x0001;
const int SWP_NOSIZE = 0x0001;
const int SWP_NOMOVE = 0x0002;
const int SWP_NOZORDER = 0x0004;
const int SWP_FRAMECHANGED = 0x0020;
const uint WM_SETICON = 0x0080;
public static void RemoveIcon(Window window) {
IntPtr hwnd = new WindowInteropHelper(window).Handle;
int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_DLGMODALFRAME);
SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
}
I would like to know why this is happening and would appreciate it if some one can fix this problem. I am using WPF and C#.
I'm opening up a new Outlook email from code in my windows application. Is there a way to give focus to the new window (instead of blinking orange behind)?
Thank you!
Try using the PInvoke:
public class MoveToForeground
{
[DllImportAttribute("User32.dll")]
private static extern int FindWindow(string ClassName, string WindowName);
[DllImport("user32.dll", EntryPoint="SetWindowPos")]
public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
const int SWP_NOMOVE = 0x0002;
const int SWP_NOSIZE = 0x0001;
const int SWP_SHOWWINDOW = 0x0040;
const int SWP_NOACTIVATE = 0x0010;
public static void DoOnProcess(string processName)
{
var process = Process.GetProcessesByName(processName);
if (process.Length > 0)
{
int hWnd = FindWindow(null, process[0].MainWindowTitle.ToString());
SetWindowPos(new IntPtr(hWnd), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
}
}
}
MoveToForeground.DoOnProcess("OUTLOOK.EXE");