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

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):

    // The following code executes in the wWinMain() function of the C++
    //  app after the main dialog window and it's child controls have been
    //  setup and initialized.  The value assigned to g_VideoHostContainerHWnd
    //  was passed to the C++ app by the C# app that launched it, as a
    //  command line argument, using the Panel control's Handle property
    //  converted to an unsigned integer.
    g_OurMainThreadID = GetCurrentThreadId();

    if (g_VideoHostContainerHWnd > 0)
    {
        // Make our video stream window a parent of the designated window
        //  in the HiveMind client.

        // Get the window handle for the video stream window: IDC_PANEL_PICTURE.
        HWND videoStreamWindow =
            GetDlgItem(
            g_HwndDlg,
            IDC_PANEL_PICTURE);

        if (videoStreamWindow > 0)
        {
            // Get the thread ID for the thread that owns the video host container window.

             g_VideoHostThreadID = GetWindowThreadProcessId(
                g_VideoHostContainerHWnd,
                &g_VideoHostProcessID);

             if (g_VideoHostThreadID > 0)
             {
                 // Make the video stream window a child of the HiveMindClient window.
                 if (NULL == SetParent(videoStreamWindow, g_VideoHostContainerHWnd))
                     OutputDebugString(L"The reparenting of the video stream window FAILED.");
                 else
                     OutputDebugString(L"The reparenting of the video stream window SUCCEEDED.");

                 // Attach the our input thread to the thread ID for the process that launched us
                 //  (i.e. - owns the video host window).
                 if (AttachThreadInput(g_OurMainThreadID, g_VideoHostThreadID, true))
                     OutputDebugString(L"Attaching our input thread to the video host thread SUCCEEDED.");
                 else
                     OutputDebugString(L"Attaching our input thread to the video host thread FAILED.");
             }
             else
             {
                 OutputDebugString(L"The thread ID of the video host container's owner thread is ZERO.");
             } // else - if (g_VideoHostThreadID > 0)
        }
        else
            OutputDebugString(L"The video stream window handle is INVALID.");
    } // if (g_VideoHostContainerHWnd > 0)

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.

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.