• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by bird1000000000 · Aug 12, 2019 at 08:33 AM · standalonec++command-lineembedembedding

How do you get an application using parentHWND to detect keyboard input?

I've now solved my resizing and mouse input problems. I'm left with 1 last problem: Keyboard input does not work. Looking at the example WM_PAINT and WM_SIZING should use activateUnityWindow(); but using it makes all input break.

Here's my C++ code

 #include "pch.h"

     // Specifies Windows Class Name - The one that shows up in processes on task manager.
 static TCHAR szWindowClass[] = _T("ContainerTest");
 
 // Title of the window
 static TCHAR szTitle[] = _T("ContainerTest");
 
 HWND unityHwnd = NULL;
 
  void activateUnityWindow() {
      SendMessage(unityHwnd, WM_ACTIVATE, WA_ACTIVE, NULL); 
 }
  void deactivateUnityWindow() {
      SendMessage(unityHwnd, WM_ACTIVATE, WA_INACTIVE, NULL);
  }
 
 
  BOOL CALLBACK EnumChildProc(HWND hwndChild, LPARAM lParam)
  {
      LPRECT rcParent;
 
      // Size and position the child window.  
 
      rcParent = (LPRECT)lParam;
      MoveWindow(hwndChild,
          0,
          0,
          rcParent->right - rcParent->left,
          rcParent->bottom - rcParent->top,
          TRUE);
 
      // Make sure the child window is visible. 
 
      return TRUE;
  }
  
 
 // This is called when there's events (Procedures) from windows
 // https://docs.microsoft.com/en-us/windows/win32/winmsg/window-procedures
 LRESULT CALLBACK WinProcs(
     _In_ HWND   hMainWindow,
     _In_ UINT   uMsg,
     _In_ WPARAM wParam,
     _In_ LPARAM lParam)
 {
 
 
     switch (uMsg) {
 
     case WM_SIZING: { // On dragging the resize
 
         RECT winSize;
         GetWindowRect(hMainWindow, &winSize);
 
         EnumChildWindows(hMainWindow, EnumChildProc, (LPARAM)& winSize);
         
         //activateUnityWindow();
 
         break;
     }
 
     //Called when the GUI updates in some way, Must be redrawn.
     case WM_PAINT: {
 
         RECT winSize;
         GetWindowRect(hMainWindow, &winSize);
 
         EnumChildWindows(hMainWindow, EnumChildProc, (LPARAM)& winSize);
 
         //activateUnityWindow();
 
         break;
     }
 
     case WM_CREATE: {
 
         activateUnityWindow();
 
         break;
     }
 
     case WM_DESTROY: {
         PostQuitMessage(0);
     }
 
     default: {
 
         return DefWindowProc(hMainWindow, uMsg, wParam, lParam);
         break;
     }
 
     }
 
     return 0;
 }
 
 
 BOOL CALLBACK EnumWindowsProcMy(HWND hwnd, LPARAM lParam)
 {
     DWORD lpdwProcessId;
     GetWindowThreadProcessId(hwnd, &lpdwProcessId);
     if (lpdwProcessId == lParam)
     {
         unityHwnd = hwnd;
 
         return FALSE; //Stops the method
     }
     return TRUE;
 }
 
 
 // This is called when the window is opened.
 int CALLBACK WinMain(
     _In_ HINSTANCE hInstance,            // Handle to windows instance
     _In_opt_ HINSTANCE hPrevInstance,    // This paremeter is always null
     _In_ LPSTR     lpCmdLine,            // The command line for this application
     _In_ int       nCmdShow)            // "TBD" thankyou windows documentation, very cool
 {
     //
     // First we've got to check if the game is already running.
     //
 
 // When we create a mutex, it will return ERROR_ALREADY_EXISTS i
     HANDLE MutexHandle =
         CreateMutex(
             FALSE,        // This only needs to be set if we want child proccesses to inherit it.
             TRUE,        // This makes us the ownder of the mutex
             "BTD6-MODDED-ISRUNNING"
         );
 
     if (MutexHandle == NULL) {
 
         BOOL lastError = GetLastError();
 
         // Game is already running
         if (lastError == ERROR_ALREADY_EXISTS) {
             TEMPBP
                 return 1;
         }
         // Limmited access right, could not create mutex.
         else if (ERROR_ACCESS_DENIED) {
             TEMPBP
                 return 1;
         }
 
         return 1;
     }
 
     //
     // Second, we've got to create the window information.
     //
 
 
     WNDCLASSEX wcex;
 
     // Sizeof this structure.
     wcex.cbSize = sizeof(WNDCLASSEX);
     // Class Styles.
     // https://msdn.microsoft.com/en-us/library/ms633574(v=VS.85).aspx
     wcex.style = CS_HREDRAW | CS_VREDRAW;
     // The procedures handling method.
     //wcex.lpfnWndProc = WinProcs;
     wcex.lpfnWndProc = WinProcs;
     // Number of extra bytes to allocate after this structure.
     wcex.cbClsExtra = 0;
     // Number of extra bytes to allocate before this structure
     wcex.cbWndExtra = 0;
     // The windows instance, provided by winmain.
     wcex.hInstance = hInstance;
     // Handle to the Icon reso urce
     wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
     // Handle to the cursor resource.
     wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
     // A windows colour.
     // See https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-tagwndclassexa
     wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
     // A string that represents the name of the resource of the menu class.
     wcex.lpszMenuName = NULL;
     // 
     wcex.lpszClassName = szWindowClass;
     // Small Icon, if set to null, looks for hIcon
     wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
 
     if (!RegisterClassEx(&wcex)) {
         return GetLastError();
     }
 
 
     //
     // Third, we have to make the window
     //
 
     HWND hMainWindow = CreateWindowEx(
         //WS_EX_OVERLAPPEDWINDOW,    // Extended window sytle
         NULL,
         szWindowClass,            // Window class
         szTitle,                // Window name
         //WS_OVERLAPPEDWINDOW,    // Window Style
         WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
         CW_USEDEFAULT,            // Initial X position of the window
         CW_USEDEFAULT,            // Initial Y position of the window
         //TODO: Save resolution to a file.
         1920,                    // Initial width of the window
         1080,                    // Initial height of the window
         NULL,                    // HWND to a parent window. This is the main window.
         NULL,                    // A HWND to a menu
         hInstance,                // Handle tot he instance of the module to be associated with the window
         NULL
     );
 
     if (hMainWindow == NULL) {
         int xd = GetLastError();
         return 1;
     }
 
     //
     // Now we need to load BTD6 as a child proccess
     //
 
     STARTUPINFO si;
     PROCESS_INFORMATION pi;
 
     ZeroMemory(&si, sizeof(si));
     si.cb = sizeof(si);
     si.dwFlags = STARTF_USESTDHANDLES;
     si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
     si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
     si.hStdOutput= GetStdHandle(STD_OUTPUT_HANDLE);
     ZeroMemory(&pi, sizeof(pi));
 
 
     std::string scmdLine = std::string(std::string(R"(Raw/Path/To/Game)") 
         + std::to_string((uint64_t)hMainWindow).c_str());
 
     lpCmdLine = (char*)(scmdLine.c_str());
 
 
     if (!CreateProcess(
         NULL,                // Application path, we're not using this, we're just going to use the command line.
         lpCmdLine,            // Use this programs command line as the childs, dont plan on doing any command line shit with the container anyway.
         NULL,                // Process security attributes
         NULL,                // Thread security attributes
         true,                // If the child will inherit this applications handle.                    
         CREATE_NO_WINDOW,    // Dont make a new window unity, it crashes :(
                             // See: https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
         NULL,                // Use parents environment
         NULL,                // Use parents current directory.
         &si,
         &pi
     )) {
         return GetLastError();
     }
 
     WaitForInputIdle(pi.hProcess, INFINITE);
 
     // Only needs ~25 ms, give it some extra time just in case of potato.
     Sleep(1000);
 
     EnumWindows(EnumWindowsProcMy, pi.dwProcessId);
 
 
     if (unityHwnd == NULL) {
         return GetLastError();
     }
 
     if (!SetParent(unityHwnd, hMainWindow)) {
         return GetLastError();
     }
     
 
     //CloseHandle(pi.hProcess);
     //CloseHandle(pi.hThread);
 
 
     //
     // Finally, We have to make the window actually visible.
     //
 
     ShowWindow(
         hMainWindow,
         nCmdShow
     );
 
     //
     // Now we need to start reciving messages.
     //
 
     MSG msg;
     while (GetMessage(
         &msg,    // Pointers to the message struct that recieves the information.
         NULL,    // Null retrieves any windows on the current thread.
         0,        // Lowest message to be retrieved
         0        // Highest message to be retrieved
                 // If the lowest and the highest value are 0, then all messages are retrieved. 
     )) {
         Sleep(1);
         TranslateMessage(&msg);
         DispatchMessage(&msg);
     }
 
     return msg.wParam;
 }

Not sure why activating the windows would break all input, probably need to find a way for it to not break all input.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

0 Replies

· Add your reply
  • Sort: 

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.



Follow this Question

Answers Answers and Comments

112 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How to embed WebGL game on a website? 4 Answers

How to set full screen mode by command line in standalone? 0 Answers

Embedded Unity Application not displaying in iOS app 0 Answers

DllNotFoundException in standalone 2 Answers

start unity standalone on server from php 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges