<html>
<head>
<style><!--
.hmmessage P
{
margin:0px;
padding:0px
}
body.hmmessage
{
font-size: 10pt;
font-family:Tahoma
}
--></style>
</head>
<body class='hmmessage'>
I've been trying to solve a program crash problem for the past several days and running out of idea. I would like people has deeper knowledge of VTK and/or Windows OS to offer some suggestions as to where to look for the problem.<br><br>Background:<br><br>I'm trying to use VTK in a WPF application. WPF is the tool allows development of UI application that renders controls in a single top level window, much like the windowless control in visual studio 6.<br>However, WPF does not allow the program to draw using unmanaged code to the window it manages. Instead, it supplies a HwndHost class allows a native windowed control to be placed on top of the WPF window. To use HwndHost, the minimum one need to do is to derive from it and override two methods (all error checking code are omitted), one to create the native control, one to destroy it.<br><font style="" face="Courier New"><br></font><font style="" face="Courier New"> protected override HandleRef BuildWindowCore(HandleRef hwndParent)</font><font style="" face="Courier New"><br></font><font style="" face="Courier New"> {</font><font style="" face="Courier New"><br></font><font style="" face="Courier New"> IntPtr hwndHost = Import.CreateChildWindow(hwndParent.Handle, hostHeight, hostWidth);</font><font style="" face="Courier New"><br></font><font style="" face="Courier New"> return new HandleRef(this, hwndHost);</font><font style="" face="Courier New"><br></font><font style="" face="Courier New"><br></font><font style="" face="Courier New"> return new HandleRef(this, IntPtr.Zero);</font><font style="" face="Courier New"><br></font><font style="" face="Courier New"> }</font><font style="" face="Courier New"><br></font><font style="" face="Courier New"><br></font><font style="" face="Courier New"> protected override void DestroyWindowCore(System.Runtime.InteropServices.HandleRef hwnd)</font><font style="" face="Courier New"><br></font><font style="" face="Courier New"> {</font><font style="" face="Courier New"><br></font><font style="" face="Courier New"> Import.DestroyChild(hwnd.Handle, instance);</font><font style="" face="Courier New"><br></font><font style="" face="Courier New"> }</font><br><br>Notice that native functions CreateChildWindow and DestroyChild are called to create the hosted window. The native control can then be inserted into WPF application by attaching the MyHwndHost instance to the WPF visual tree.<br><br><font style="" face="Courier New"> MyHwndHost myHwndHost = new MyHwndHost(hostBorder.ActualWidth, hostBorder.ActualHeight);</font><font style="" face="Courier New"><br></font><font style="" face="Courier New"> hostBorder.Child = myHwndHost;<br> myHwndHost.SubClassChild();</font><font style="" face="Courier New"> //<<= the subclass the control just like vtkInteractor does<br></font><br>This last statement is the above code snippet is used to simulate the subclassing by vtkWin32RenderWindowInteractor, discussed later. Under the hood, Upon completion of BuildwondowCore and before calling DestroyWindowCore, HwndHost attaches and detaches it's own window procedure to intercept Window messages send to the hosted window, using SetWindowLongPtr API call.<br><br>On the other hand, VTK interactive also uses subclassing to intercept the messages. Which, in my case, is done after WPF attaches it's Window procedure. So after the control is rendered, the Window procedure chain looks like this (in the reverse order they're called):<br><br>vtkWin32OpenGLRenderWindow::WndProc <- HwndHost.SubclassWndProc <- vtkHandleMessage<br><br>These all works out nicely, until the time comes to close the control. WPF first send a registered message to the hosted window which is passed along to HwndHost's SubclassWndProc by vtkHandleMessage. At this point, WPF tried to detach itself from the hosted window. It first calls GetWindowLongPtr to check if it is at the beginning of the chain and this is where the problem shows up. Instead of getting the address of vtkHandleMessage, it gets an invalid address and crashes the program.<br><br>To rule out VTK as the source of the problem, I tried to reproduce it without VTK buy create a Windows Procedure Chain similar to that of VTK (see the source code at the end). And, as you already guessed it. The test program without VTK, worked flawlessly.<br><br>How much a role does vtk played in crashing the program? If it does, where the problem most likely to be originated?<br><br>xz<br><br><font style="" face="Courier New">__declspec(dllexport) HWND WINAPI CreateChildWindow(HWND hWndParent, int width, int height)<br>{<br> HINSTANCE hApp = (HINSTANCE)GetWindowLongPtr(hWndParent, GWLP_HINSTANCE);<br><br> WNDCLASS wndClass;<br> wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;<br> wndClass.lpfnWndProc = Win32CtrlImpl::DummyWndProc;<br> wndClass.cbClsExtra = 0;<br> wndClass.hInstance = hApp;<br> wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);<br> wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);<br> wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);<br> wndClass.lpszMenuName = NULL;<br> wndClass.lpszClassName = L"Win32Control";<br> wndClass.cbWndExtra = 2*sizeof(LONG_PTR);<br> RegisterClass(&wndClass);<br><br> HWND hwnd = CreateWindow<br> ( L"Win32Control"<br> , L"Win32 Control"<br> , WS_CHILD|WS_CLIPCHILDREN<br> , 0, 0<br> , width, height<br> , hWndParent<br> , NULL, hApp, NULL);<br><br> SetWindowLongPtr(hwnd, sizeof(LONG_PTR), (LONG_PTR)&wndClass);<br><br> wchar_t buffer[1024];<br> swprintf(buffer, L"Initial Window Procedure: %0lx", wndClass.lpfnWndProc);<br> MessageBox(hWndParent, buffer, L"Window Procedure", MB_OK);<br><br> return hwnd;<br>}<br><br>__declspec(dllexport) void* WINAPI SubClassChild(HWND hwnd)<br>{<br> Instance* instance = new Instance();<br><br> SetLastError(0);<br> LONG_PTR rv = SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)MyWndProc);<br> if (!rv || GetLastError())<br> MessageBox(hwnd, L"Failed to subclass window.", L"debug", MB_OK);<br><br> wchar_t buffer[1024];<br> swprintf(buffer, L"Window Procedure Prior to sub-classing: %0lx", rv);<br> MessageBox(hwnd, buffer, L"Window Procedure", MB_OK);<br><br> instance->wndProc = (WNDPROC)rv;<br><br> rv = SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)instance);<br> if (!rv && GetLastError())<br> MessageBox(hwnd, L"Failed to store user data.", L"debug", MB_OK);<br><br> ShowWindow(hwnd, SW_NORMAL);<br><br> return instance;<br>}<br><br>__declspec(dllexport) void WINAPI DestroyChild(HWND hwnd, void* p)<br>{<br> Instance* instance = (Instance*)p;<br><br> SetLastError(0);<br> LONG_PTR rv = SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)instance->wndProc);<br> if (!rv && GetLastError())<br> MessageBox(hwnd, L"Failed to restore window.", L"debug", MB_OK);<br><br> if (rv != (LONG_PTR)&MyWndProc)<br> MessageBox(hwnd, L"Bad Window Process", L"debug", MB_OK|MB_ICONQUESTION);<br><br> wchar_t buffer[1024];<br> swprintf(buffer, L"Window Procedure Prior to restoring: %0lx", rv);<br> MessageBox(hwnd, buffer, L"Window Procedure", MB_OK);<br><br> delete instance;<br>}<br><br>LRESULT CALLBACK MyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)<br>{<br> // do nothing but to pass the message to the original window procedure<br> Instance* instance = (Instance*)GetWindowLongPtr(hWnd, GWLP_USERDATA);<br> //WNDPROC wndProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);<br> if (!instance)<br> MessageBox(hWnd, L"Failed to extract previous windows procedure.", L"debug", MB_OK);<br><br> UINT regMessage = RegisterWindowMessage(L"HwndSubclass.DetachMessage");<br> if (message==regMessage)<br> {<br> wchar_t buffer[1024];<br> swprintf(buffer, L"Window Procedure Prior to detaching: %0lx", GetWindowLongPtr(hWnd, GWLP_WNDPROC));<br> MessageBox(hWnd, buffer, L"Window Procedure", MB_OK);<br> }<br><br> return CallWindowProc(instance->wndProc, hWnd, message, wParam, lParam);<br>}<br><br>LRESULT CALLBACK Win32CtrlImpl::DummyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)<br>{<br> return DefWindowProc(hWnd, message, wParam, lParam);<br>}<br></font><br><br><br><br> </body>
</html>