title: Sinking DWebBrowserEvents2 events appears to hang programmatic navigation
body: <p>I posted this question on the MSDN forums, but my experience has been a better quality of answer here on Stack Overflow, so I'm posting here as well. As I've posted several times before, I'm working on a browser automation framework, automating Internet Explorer from an external process. My architecture is as follows: I have a server which opens a named pipe that my automation client pushes commands to. The server interprets the commands, and executes them on the IWebBrowser2 object, which I have wrapped in my own C++ class. Everything works fine until I try to sink events on the IE instance. My wrapper class implements IDispEventSimpleImpl, but when I try to sink the events, the browser instance doesn't respond to any communication, either programmatically or via the UI. Here are my main two methods with the most relevance:</p>
  
  <pre><code>void BrowserManager::Start(void)
  {
    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    std::basic_string&lt;TCHAR&gt; pipeName =L"\\\\.\\pipe\\managerpipe";
    HANDLE hPipe = ::CreateNamedPipe(pipeName.c_str(), 
      PIPE_ACCESS_DUPLEX, 
      PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 
      PIPE_UNLIMITED_INSTANCES,
      1024,
      1024,
      0,
      NULL);
  
    if (hPipe == INVALID_HANDLE_VALUE)
    {
      DWORD dwError = ::GetLastError();
    }
  
    this-&gt;m_isRunning = true;
  
    while (this-&gt;m_isRunning)
    {
      BOOL result = ::ConnectNamedPipe(hPipe, NULL);
      std::vector&lt;CHAR&gt; inputBuffer(1024);
      DWORD bytesRead = 0;
      ::ReadFile(hPipe, &amp;inputBuffer[0], 1024, &amp;bytesRead, NULL);
  
      std::string command = &amp;inputBuffer[0];
      std::string response = DispatchCommand(command);
  
      std::vector&lt;CHAR&gt; outputBuffer(response.begin(), response.end());
      ::WriteFile(hPipe, &amp;outputBuffer[0], outputBuffer.size(), &amp;bytesRead, NULL);
      ::FlushFileBuffers(hPipe);
      ::DisconnectNamedPipe(hPipe);
  
      if (strcmp(command.c_str(), "quit\r\n") == 0)
      {
        this-&gt;m_isRunning = false;
      }
    }
  
    ::CloseHandle(hPipe);
    CoUninitialize();
  }
  
  std::string BrowserManager::DispatchCommand(std::string command)
  {
    std::string response;
    if (strcmp(command.c_str(), "start\r\n") == 0)
    {
      // Launch the browser process using CreateProcess on XP 
      // or IELaunchURL on Vista or higher. This is done on a
      // low-integrity thread so we have the correct integrity.
      DWORD procId = this-&gt;m_factory-&gt;LaunchBrowserProcess();
      CComPtr&lt;IWebBrowser2&gt; pBrowser(this-&gt;m_factory-&gt;AttachToBrowser(procId));
      BrowserWrapper wrapper(pBrowser);
      this-&gt;m_wrapper = wrapper;
      response = "started";
    }
    else if (strcmp(command.c_str(), "goto\r\n") == 0)
    {
      this-&gt;m_wrapper.GoToUrl("http://www.google.com/");
      response = "navigated";
    }
    else if (strcmp(command.c_str(), "quit\r\n") == 0)
    {
      this-&gt;m_wrapper.CloseBrowser();
      response = "closed";
    }
    else
    {
      response = "invalid command";
    }
  
    return response;
  }
  </code></pre>
  
  <p>Interestingly, I prototyped this same mechanism in C# before translating it into unmanaged C++ to make sure what I was attempting would work, since my C++ skills are not at the same level as my C# skills. Needless to say, it works fine in C#, but it is a requirement that this component be written in unmanaged code. I'm sure I'm overlooking something obvious that the .NET Framework abstracts away, but whatever it is, it isn't obvious to me.</p>
  
  <p>To help me learn from my mistake, I'd appreciate a pointer to what it is that the .NET Framework is doing to let this work. In the C# version, I'm using a single thread with blocking I/O on the pipe, just like I (think I) am here. If the posted code snippet isn't enough to point toward a diagnosis, I'm more than happy to provide a full Visual Studio 2008 solution demonstrating the difficulty.</p>