When the window or other visual control in which a visual native class resides is created in a PowerBuilder application, the PBVM calls the PBX_CreateVisualObject method in the extension automatically -- the PowerBuilder application developer does not need to write a CREATE statement in a script. The PBVM also calls the IPBX_VisualObject's CreateControl method. Every extension that contains visual native classes must export PBX_CreateVisualObject and implement CreateControl.
The following is sample code for PBX_CreateVisualObject:
PBXEXPORT PBXRESULT PBXCALL PBX_CreateVisualObject ( IPB_Session* pbsession, pbobject pbobj, LPCTSTR className, IPBX_VisualObject **obj ) { PBXRESULT result = PBX_OK; string cn(className); if (cn.compare("visualext") == 0) { *obj = new CVisualExt(pbsession, pbobj); } else { *obj = NULL; result = PBX_FAIL; } return PBX_OK; };
Registering the window class
Before CreateControl can be called, the window class must be registered. This code uses the Windows RegisterClass method to register the window class with the class name s_className:
void CVisualExt::RegisterClass() { WNDCLASS wndclass; wndclass.style = CS_GLOBALCLASS | CS_DBLCLKS; wndclass.lpfnWndProc = WindowProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = g_dll_hModule; wndclass.hIcon = NULL; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); wndclass.hbrBackground =(HBRUSH) (COLOR_WINDOW + 1); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = s_className; ::RegisterClass (&wndclass); }
You must also implement the Windows UnregisterClass method to unregister the class when the window is closed:
void CVisualExt::UnregisterClass() { ::UnregisterClass(s_className, g_dll_hModule); }
The RegisterClass and UnregisterClass methods are called in the initialization code for the PBX. This is the Visual C++ DllMain method:
BOOL APIENTRY DllMain( HANDLE hModule, DWORD reasonForCall, LPVOID lpReserved ) { g_dll_hModule = (HMODULE)hModule; switch (reasonForCall) { case DLL_PROCESS_ATTACH: CVisualExt::RegisterClass(); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: CVisualExt::UnregisterClass(); break; } return TRUE; }
Implementing CreateControl
Every visual native class must implement the IPBX_VisualObject CreateControl method. After getting the class name with the IPBX_VisualObject GetClassName method, CreateControl passes the class name to the Windows CreateWindowEx method to create the window, then returns the window handle to the PBVM:
TCHAR CVisualExt::s_className[] = "PBVisualExt"; LPCTSTR CVisualExt::GetWindowClassName() { return s_className; } HWND CVisualExt::CreateControl ( DWORD dwExStyle, // extended window style LPCTSTR lpWindowName, // window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or // owner window HINSTANCE hInstance // handle to application // instance ) { d_hwnd = CreateWindowEx(dwExStyle, s_className, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, NULL, hInstance, NULL); ::SetWindowLong(d_hwnd, GWL_USERDATA, (LONG)this); return d_hwnd; }