Creating visual class instances

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