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; };
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; }
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; }