0

I have used the information from the following SO posts to make the parent of a Picture control in my C++ Desktop app, the child of a Panel control in my C# app. The C++ and C# apps are separate apps running in their own process:

Various issues using SetParent to embed window into external process

Embedding HWND into external process using SetParent

I am using the code shown below to do the re-parenting. The C# app launches the C++ app, passing it on the command line the Windows handle of the Panel control that should host the C++ app's Picture control. When I run the C# app I do see the outline of the C++ Picture control on the designated Panel control that is native to the C# app.

However, I am having the following problems:

1) Both the C++ and C# apps flicker terribly like they are both being repainted many times a second.

2) The picture control in the C++ app normally shows a video feed from my WebCam. I BitBlt() the frames from the webcam into the C++ Picture control. It works fine without the re-parenting but with it, I don't see any frames at all.

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.

Does anyone know what is wrong and how I can fix it? 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)
Community
  • 1
  • 1
Robert Oschler
  • 14,153
  • 18
  • 94
  • 227
  • 2
    [Is it legal to have a cross-process parent/child or owner/owned window relationship?](http://blogs.msdn.com/b/oldnewthing/archive/2013/04/12/10410454.aspx) – GSerg Jun 20 '15 at 21:21
  • 1
    This won't work. Give it up. – David Heffernan Jun 20 '15 at 22:12
  • @DavidHeffernan Unity 3D apps do it flawlessly with their parentHWND command line argument so that isn't true: http://forum.unity3d.com/threads/how-to-integrate-unity3d-into-c-wpf-application.332276/#post-2152167 – Robert Oschler Jun 20 '15 at 22:23
  • I'm not convinced. That you can use SetParent cross process is a Win16 back compat bodge. It looks like you are in charge of all of the code. Make it one process. – David Heffernan Jun 20 '15 at 22:27
  • @DavidHeffernan This same app also embeds a Unity 3D app in a window and as I said, it works flawlessly. That's why I'm sure it works. – Robert Oschler Jun 20 '15 at 22:36
  • 1
    Does Unity 3D use GDI or does it use opengl/direct X? The flicker is normally caused by forcing the system to redraw instead of buffering up the drawing in a bitmap and blting it when it gets a paint. Does the C++ code just draw directly to the screen or does it draw only when it gets a WM_PAINT? – cup Jun 20 '15 at 23:09
  • @cup I believe Unity 3D can do either OpenGL or DirectX. I'll have to ask the programmer that wrote the Unity app that question. The C++ code uses StretchBlt and BitBlt to write frames from the WebCam into the Picture control, after which InvalidateRect() is called on the Picture control. – Robert Oschler Jun 20 '15 at 23:17
  • This does not work reliably. Unless both processes are prepared to have a cross-process parent/child relationship, this is not going to happen. The first comment has authoritative information. Read it. If there is anything you do not understand, stop trying to do what mandates **intimate** knowledge of the Windows API. As for your *"I'm sure it works"* mantra, consider this: If you don't know why your code works, it doesn't. – IInspectable Jun 21 '15 at 01:50
  • @IInspectable However, if I can reliably point to an app that does do it, like the hundreds of Unity 3D apps that do embed properly in a cross-process parent window, then just because my code doesn't work does not contradict the clear evidence that someone (Unity) does know how to do it and that is absolutely possible; knowledge that I can confirm first hand because as I said, my app also embeds a foreign (external) Unity 3D app and it works fine. So I have come to Stack Overflow to find a person that also has that knowledge and is willing to share it. – Robert Oschler Jun 21 '15 at 03:53
  • Try copying/StretchBlt the frames locally, do an InvalidateRect and only BitBlt them to the Picture Control when you get a WM_PAINT. The PictureControl is GDI: it works differently from OpenGL/DirectX. Note that the frequency of WM_PAINTs may not coincide with the frequency of your frames changing so you may miss some frames. When you get a WM_PAINT, the local buffer will have the latest picture to be BLTted. – cup Jun 21 '15 at 06:45
  • *"An app"* cannot do this reliably, since **both** processes must be prepared. If you fully understand the implications of sharing an input queue between 2 processes, you know what to look out for. Raymond Chen has blogged on the topic ([more](http://blogs.msdn.com/b/oldnewthing/archive/2013/06/19/10426841.aspx) [than](http://blogs.msdn.com/b/oldnewthing/archive/2013/06/07/10424279.aspx) [once](http://blogs.msdn.com/b/oldnewthing/archive/2013/06/04/10423296.aspx)). – IInspectable Jun 21 '15 at 09:03

1 Answers1

0

I also got this problem, the solution is the parent hwnd requires flag WS_CLIPCHILDREN.