728x90
※Unity 빌드 파일을 Wpf 빌드파일에 넣어야 실행된다.
MainWindow.cs에 _process.StartInfo.FileName = ""; 안에 Wpf 빌드파일에 들어있는 Unity 빌드파일 명을 기입하면된다.
MainWindow.xaml
<Window x:Class="WPF_UNITY.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
mc:Ignorable="d"
Closed="btnClose_Click"
Title="MainWindow" Height="450" Width="800">
<Border>
<Grid x:Name="UnityGrid1" >
<WindowsFormsHost>
<wf:Panel x:Name="UnityGrid" Resize="UnityContentResize" VisibleChanged="UnityGrid_VisibleChanged" />
</WindowsFormsHost>
</Grid>
</Border>
</Window>
MainWindow
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer.Tick += attemptInit;
dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
dispatcherTimer.Start();
}
private void UnityGrid_VisibleChanged(object sender, EventArgs e)
{
ActivateUnityWindow();
}
private void btnClose_Click(object sender, EventArgs e)
{
ApplicationExit(sender, e);
}
// Close Unity application
private void ApplicationExit(object sender, EventArgs e)
{
try
{
DeactivateUnityWindow();
_process.CloseMainWindow();
Thread.Sleep(1000);
while (!_process.HasExited)
_process.Kill();
this.Close();
Window.GetWindow(this).Close();
System.Windows.Application.Current.Shutdown();
}
catch (Exception)
{
}
}
#region
[DllImport("User32.dll")]
static extern bool MoveWindow(IntPtr handle, int x, int y, int width, int height, bool redraw);
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);
private Process _process;
private IntPtr _unityHWND = IntPtr.Zero;
bool initialized = false;
private const int GWLP_WNDPROC = -4;
private const int WM_INPUT = 0x00FF;
private const int WM_ACTIVATE = 0x0006;
private readonly IntPtr WA_ACTIVE = new IntPtr(1);
private readonly IntPtr WA_INACTIVE = new IntPtr(0);
[StructLayout(LayoutKind.Sequential)]
public struct RAWINPUTDEVICE
{
public ushort usUsagePage;
public ushort usUsage;
public uint dwFlags;
public IntPtr hwndTarget;
}
const ushort HID_USAGE_PAGE_GENERIC = 0x01;
const ushort HID_USAGE_GENERIC_KEYBOARD = 0x06;
[DllImport("user32.dll", SetLastError = true)]
public static extern bool RegisterRawInputDevices([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] RAWINPUTDEVICE[] pRawInputDevices, int uiNumDevices, int cbSize);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWindowLongPtrW(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
private new delegate IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
private MulticastDelegate originalWndProc;
private WndProc myWndProc;
void attemptInit(object sender, EventArgs e)
{
if (initialized)
return;
IntPtr unityHandle = UnityGrid.Handle;
try
{
_process = new Process();
_process.StartInfo.FileName = "Pilot.exe";
_process.StartInfo.Arguments = "-parentHWND " + unityHandle.ToInt32() + " " + Environment.CommandLine;
_process.StartInfo.UseShellExecute = true;
_process.StartInfo.CreateNoWindow = true;
_process.Start();
_process.WaitForInputIdle();
EnumChildWindows(unityHandle, WindowEnum, IntPtr.Zero);
SetupRawInput(unityHandle);
UnityContentResize(this, EventArgs.Empty);
PresentationSource s = PresentationSource.FromVisual(System.Windows.Application.Current.MainWindow);
initialized = true;
}
catch (Exception ex)
{
}
}
private void ActivateUnityWindow()
{
SendMessage(_unityHWND, WM_ACTIVATE, WA_ACTIVE, IntPtr.Zero);
}
private void DeactivateUnityWindow()
{
SendMessage(_unityHWND, WM_ACTIVATE, WA_INACTIVE, IntPtr.Zero);
}
private int WindowEnum(IntPtr hwnd, IntPtr lparam)
{
_unityHWND = hwnd;
ActivateUnityWindow();
return 0;
}
private void UnityContentResize(object sender, EventArgs s)
{
MoveWindow(_unityHWND, 0, 0, (int)UnityGrid.Width, (int)UnityGrid.Height, true);
Debug.WriteLine("RESIZED UNITY WINDOW TO: " + (int)UnityGrid.Width + "x" + (int)UnityGrid.Height);
ActivateUnityWindow();
}
private void UnityContentActivate(object sender, EventArgs e)
{
ActivateUnityWindow();
}
private void UnityContentDeactivate(object sender, EventArgs e)
{
//DeactivateUnityWindow();
}
private IntPtr HookWndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam)
{
if (msg == WM_INPUT)
{
SendMessage(_unityHWND, msg, wParam, lParam);
return IntPtr.Zero;
}
return (IntPtr)originalWndProc.DynamicInvoke(new object[] { hwnd, msg, wParam, lParam });
}
private void SetupRawInput(IntPtr hostHWND)
{
myWndProc = HookWndProc;
var originalWndProcPtr = SetWindowLongPtrW(hostHWND, GWLP_WNDPROC, Marshal.GetFunctionPointerForDelegate(myWndProc));
if (originalWndProcPtr == null)
{
var errorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(errorCode, "Failed to overwrite the original wndproc");
}
Type lel = typeof(MulticastDelegate);
originalWndProc = (MulticastDelegate)Marshal.GetDelegateForFunctionPointer(originalWndProcPtr, lel);
var rawInputDevices = new[]
{
new RAWINPUTDEVICE()
{
usUsagePage = HID_USAGE_PAGE_GENERIC,
usUsage = HID_USAGE_GENERIC_KEYBOARD,
dwFlags = 0,
hwndTarget = hostHWND
}
};
if (!RegisterRawInputDevices(rawInputDevices, 1, Marshal.SizeOf(typeof(RAWINPUTDEVICE))))
{
var lastError = Marshal.GetLastWin32Error();
throw new Win32Exception(lastError, "Failed to register raw input devices");
}
}
#endregion
}
728x90
'VisualStudio > WPF' 카테고리의 다른 글
[WPF] Win32 api 사용하여 윈도우 창 제어하기 max창 드레그 및 축소화 (0) | 2023.01.09 |
---|---|
[WPF] 무료 Icon Nuget 및 사이트 (0) | 2023.01.09 |
[WPF] 바인딩(onetime, oneway, twoway, onewaytosource) (0) | 2023.01.09 |
[WPF] Margin 마진 순서 (0) | 2023.01.06 |
[WPF] 다양한이벤트처리방법 Nuget XamlBehaviorsWpf (0) | 2023.01.05 |