Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Constant flickering with child window in C++ app embedded in C# app?

Discussion in 'Windows' started by sharpener, Jun 20, 2015.

  1. sharpener

    sharpener

    Joined:
    Jan 6, 2015
    Posts:
    8
    Hello,

    My major apologies up front for posting this question since it is a not a Unity 3D development question per se. However, the C# app that I'm having this problem with also does embed a Unity 3D app in one of it's windows using the parentHWND command line argument, and that works perfectly. In fact, I got the idea to try embedding one of the child windows in the C++ app (launched by the same C# app that embeds a Unity 3D app), from the Unity 3D parentHWND command line argument feature. I am hoping that one of the geniuses behind the Unity 3D embedding capability will see this post and lend a generous hand.

    As I said, the Unity 3D app embedding works perfectly with no glitches, repaint issues, or other problems. However, when I try to embed the C++ child window into a Panel control in my C# app, I do see the outline of the C++ Picture control in the C# host container, but the video frames I write into it from the webcam do not appear any longer like they do when the Picture control is not re-parented. (I use the Windows API BitBlt function to move the frames from the WebCam into the C++ Picture control).

    NOTE: The flicker is definitely the result of drawing into the now re-parented child window. If I disable the that operation, the flicker doesn't happen.

    Below is the C++ code I am using to reparent the Picture control. Again, my apologies in advance. I would never do this is it weren't for the fact a project crucial to my company is dependent on getting this working.

    Here is the code in the C++ app that does the re-parenting and the attachment of the C++ main input thread (the thread that owns the Picture control) to the input thread belonging to the main thread of the C# app (the thread that owns the Panel control):

    Code (CSharp):
    1.  
    2.     // The following code executes in the wWinMain() function of the C++
    3.     //  app after the main dialog window and it's child controls have been
    4.     //  setup and initialized.  The value assigned to g_VideoHostContainerHWnd
    5.     //  was passed to the C++ app by the C# app that launched it, as a
    6.     //  command line argument, using the Panel control's Handle property
    7.     //  converted to an unsigned integer.
    8.     g_OurMainThreadID = GetCurrentThreadId();
    9.  
    10.     if (g_VideoHostContainerHWnd > 0)
    11.     {
    12.         // Make our video stream window a parent of the designated window
    13.         //  in the HiveMind client.
    14.  
    15.         // Get the window handle for the video stream window: IDC_PANEL_PICTURE.
    16.         HWND videoStreamWindow =
    17.             GetDlgItem(
    18.             g_HwndDlg,
    19.             IDC_PANEL_PICTURE);
    20.  
    21.         if (videoStreamWindow > 0)
    22.         {
    23.             // Get the thread ID for the thread that owns the video host container window.
    24.  
    25.              g_VideoHostThreadID = GetWindowThreadProcessId(
    26.                 g_VideoHostContainerHWnd,
    27.                 &g_VideoHostProcessID);
    28.  
    29.              if (g_VideoHostThreadID > 0)
    30.              {
    31.                  // Make the video stream window a child of the HiveMindClient window.
    32.                  if (NULL == SetParent(videoStreamWindow, g_VideoHostContainerHWnd))
    33.                      OutputDebugString(L"The reparenting of the video stream window FAILED.");
    34.                  else
    35.                      OutputDebugString(L"The reparenting of the video stream window SUCCEEDED.");
    36.  
    37.                  // Attach the our input thread to the thread ID for the process that launched us
    38.                  //  (i.e. - owns the video host window).
    39.                  if (AttachThreadInput(g_OurMainThreadID, g_VideoHostThreadID, true))
    40.                      OutputDebugString(L"Attaching our input thread to the video host thread SUCCEEDED.");
    41.                  else
    42.                      OutputDebugString(L"Attaching our input thread to the video host thread FAILED.");
    43.              }
    44.              else
    45.              {
    46.                  OutputDebugString(L"The thread ID of the video host container's owner thread is ZERO.");
    47.              } // else - if (g_VideoHostThreadID > 0)
    48.         }
    49.         else
    50.             OutputDebugString(L"The video stream window handle is INVALID.");
    51.     } // if (g_VideoHostContainerHWnd > 0)
    52.  
     
    Last edited: Jun 20, 2015
  2. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,507
    Got any screenshots of what's going on? How exactly do you create your parent window? Make sure to include WS_CLIPCHILDREN flag in its window style.

    You might also want to just draw a texture using DirectX, rather than doing a BitBlt, as that will definitely be more performant.
     
  3. sharpener

    sharpener

    Joined:
    Jan 6, 2015
    Posts:
    8
    >> Got any screenshots of what's going on?

    I'd have to make a video but it's pretty straightforward. Many times a second, you can see a fast repaint of all the controls on the display areas for both the C# and C++ apps (checkboxes, list boxes, text, etc.). It only happens when the video stream panel that has been reparented to the C# app is being written to. If I turn off the BitBlt/StretchBlt operation that does the writing, the flickering stops.

    Normally, when not reparented, the C++ Picture box I BitBlt/StretchBlt the latest webcam frame into shows the the video feed from the webcam. But as I said, all I see when the Picture box is repearented is the flickering. The Picture box canvas itself is empty. It's as if writing to the Picture box window when it is reparented causes an invalidate-rect/paint operation on the entire window chain in both apps (child and parent), instead of simply writing to the Picture box canvas.

    >> Make sure to include WS_CLIPCHILDREN flag in its window style.

    Ok, I'll see if I can figure out how to do that. I am not using CreateWindowEx(). Instead the dialog form that contains the Picture box as a child control is created with CreateDialogW().

    >> You might also want to just draw a texture using DirectX, rather than doing a BitBlt, as that will definitely be more performant.

    I'll consider that but note performance has not been a problem. The CPU load is very light. Just the flickering is the thing.