Accessing PowerBuilder COM servers from clients
You can access the methods on a PowerBuilder COM component from
clients built with any COM-compliant tool. For COM+, the
client must have Microsoft Windows Installer. The COM server must
be registered on the client machine, or the COM+ application
proxy file must be installed.
For how to access PB COM servers from a remote client, see “Using PowerBuilder COM servers
and objects with DCOM”.
The following examples show how you access a PowerBuilder COM
object from Visual Basic or C++. They use a PowerBuilder COM
object that was generated from a user object called ccuo_employee and
has the Program ID PB100.employee.
For information about building PowerBuilder clients and an example
using the same COM object, see Chapter 28, “Building a COM or COM+ Client.”
Visual Basic as client
In Visual Basic, you can connect to the registered object
using its program ID (late binding). In Visual Basic 5 or later,
you can also use its class name (early binding).
To access a PowerBuilder COM object in Visual Basic:
-
Do one of the following:
- Declare an object and connect
to it using its program ID:1Dim EmpObj As Object<br />Set EmpObj = CreateObject("PB100.employee") - Add a reference to the generated type library for
the PowerBuilder COM object to your project, then declare an instance
of the object using its class name (in Visual Basic 5 or later):1Dim EmpObj As New CoEmployee
- Declare an object and connect
-
Check that the connection was established:
1Dim response<br />If EmpObj Is Nothing Then<br />response = MsgBox("Creating Employee Object", <br /> vbOKOnly, "Error")<br />End If -
Access functions or properties of the object:
1Dim units, time as Long<br />Dim DoubleReturn as Double<br />Dim StringReturn As String<br /><br />DoubleReturn = EmpObj.f_calcdayavg units, time <br />StringReturn = EmpObj.f_teststring<br />EmpObj.ll_hours = 37 -
Destroy the object:
1Set EmpObj = Nothing
C++ as client
In C++, you use COM library functions to
create an instance of a PowerBuilder COM object. You also need to
use C/C++ definitions of the PowerBuilder COM
objects when you build the client. The Microsoft IDL (MIDL) compiler generates
these definitions from the IDL file created by the PowerBuilder COM
generator.
For example, using the IDL file generated for the Employee PowerBuilder COM
object:
1 |
midl.exe employee.idl |
The MIDL compiler generates a header file (employee.h)
containing definitions of the interfaces of all the objects in the
IDL file and a C file (employee_i.c)
that defines the CLSIDs and Interface IDs (IIDs) associated with
the object.
Additional files The MIDL compiler also generates proxy/stub code
(in employee_p.c and dlldata.c),
but you do not need to use the proxy/stub code to build
the C++ client executable or access the PowerBuilder COM
object.
Building a client To build a C++ client executable that can
access methods in a PowerBuilder COM object, you create a C++ source
file that includes the generated header file, compile both the C++ client
source file and the C file generated by the MIDL compiler, then
link the resulting object files to create the executable.
For the Employee example:
- Create
a C++ source file called client.cpp (shown
below). - Compile client.cpp.
- Compile employee_i.c.
- Link client.obj and employee_i.obj to
create an executable–for example, employee_ecl.exe.
Employee.h The following code fragments from the employee.h header
file generated by the MIDL compiler show the definitions to be used
by C++ clients:
1 |
typedef interface DIEmployee DIEmployee;<br />EXTERN_C const IID IID_DIEmployee;<br /><br />interface DECLSPEC_UUID("A2F59F71-D5FB-11D1-92B9-00A0247712F1")<br /> DIEmployee : public IDispatch<br /> {<br /> public: <br /> virtual /* [id] */ HRESULT STDMETHODCALLTYPE<br /> f_calcdayavg( <br /> /* [in] */ long units,<br /> /* [in] */ long time,<br /> /* [retval][out] */ double __RPC_FAR <br /> *retval) = 0;<br /><br /> virtual /* [id] */ HRESULT <br /> STDMETHODCALLTYPE f_teststring( <br /> /* [retval][out] */ BSTR __RPC_FAR<br /> *retval) = 0;<br /> };<br /><br />EXTERN_C const CLSID CLSID_CoEmployee; |
Client.cpp The following sample client file uses the MIDL-generated C/C++ definitions
of PowerBuilder COM objects. For further information on the COM API
calls shown in client.cpp, see the Microsoft
Software Development Kit documentation.
1 |
#include <windows.h><br />// employee.h I( from MIDL.EXE)<br />#include "employee.h"<br /><br />int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)<br />{<br /> HRESULT hr;<br /> DIEmployee *pDIEmployee = 0;<br /><br /> // Initialize COM<br /> CoInitialize(0);<br /><br /> hr = CoCreateInstance(CLSID_CoEmployee,NULL,<br /> CLSCTX_INPROC_SERVER, IID_DIEmployee,<br /> (void **)&pDIEmployee);<br /> if (FAILED(hr))<br /> ErrorMessage("CoCreateInstance", hr);<br /><br /> // variables for methods<br /> long units, time;<br /> double dReturn;<br /> BSTR strReturn = NULL;<br /> <br /> // call methods<br /> hr = pDIEmployee->f_calcdayavg(units,<br /> time,&dReturn);<br /> if (FAILED(hr))<br /> ErrorMessage("f_calcdayavg",hr); <br /><br /> hr = pDIEmployee->f_teststring(&strReturn);<br /> if (FAILED(hr))<br /> ErrorMessage("f_teststring",hr);<br /><br /> // release the interface ptr<br /> pDIEmployee->Release();<br /><br /> CoFreeUnusedLibraries();<br /> // all done!<br /> <br />CoUninitialize();<br /> return 0;<br />} |
Using PowerBuilder COM servers and objects with DCOM
A PowerBuilder COM object can be activated from remote clients
using DCOM. The object must be activated in a server process on
the designated host computer. Out-of-process servers (EXE files)
create a server process, but in-process servers (DLL files)
must be hosted in a surrogate process.
COM provides a general-purpose surrogate host (DLLHOST.EXE)
that can be used to host PowerBuilder COM server DLLs. Marking PowerBuilder COM servers
to use a surrogate host is the primary step in enabling remote client access
to your PowerBuilder COM objects. You can use the DCOM configuration
utility (DCOMCNFG.EXE) to change values for
location, security, and identity, but in most cases the defaults
are adequate. For more information, see the online Help for the DCOMCNFG utility.
Enabling PowerBuilder COM servers to use a surrogate
host
There are two ways to enable PowerBuilder COM servers to use
a surrogate:
- Use the registry editor (REGEDIT32.EXE)
to edit the PowerBuilder COM server’s AppID registry entry. - Use the OLE/COM Object Viewer (OLEVIEW.EXE)
provided with Microsoft Visual C++ 5.0 or greater.
Using OLEVIEW is the preferred approach, because manually
editing your computer’s registry may render all or parts
of your computer’s configuration inoperable.
To enable a COM server to use a surrogate process
using the registry editor:
-
Open the project used to generate the server
and copy the PowerBuilder COM server’s AppID value from the
General property page. -
Run REGEDIT.EXE, find the
server’s AppID key in My ComputerHKEY_CLASSES_ROOTAppID,
and select it. -
Select Edit>New>String Value
from the menu bar. -
Enter the name DllSurrogate and
leave the data field empty.An empty data field tells COM to use the default surrogate
host (DLLHOST.EXE). The AppID value keys should
look like this:Name Data (Default) PowerBuilder 10 generated server: servername.dll DllSurrogate “”
To enable a COM server to use a surrogate process
using the OLE/COM Object Viewer:
-
Run OLEVIEW.EXE.
-
Expand the Automation Objects in the list view
and select an object in your PowerBuilder COM server. -
Select an object associated with your PowerBuilder COM
server. -
Select the Implementation tab.
-
Select the Inproc Server tab and check the Use
Surrogate Process check box.
Configuring client computers to activate remote PowerBuilder COM
objects
To activate a remote component, a client application must
pass the object’s class identifier (CLSID) in the activation
request to the remote host.
Some clients, such as those built with PowerBuilder 10 or
C++, can use the object’s CLSID in the
method call when they create an instance of a remote object. These
client applications do not require any client-side configuration.
Most clients reference an object by its name (ProgID) rather
than its CLSID. In these cases the client computer’s registry
must contain the information necessary to map a ProgID to a CLSID
in order to make the remote activation request. You can use either
of two methods to add the required registry information to the client
computer:
- Register the PowerBuilder COM server
on each client computer that requires remote access.
To use this method, you must be able to locate the appropriate
version of PBVMn0.DLL. - On the host where the PowerBuilder COM server is registered,
export the required registry information into .REG files using REGEDIT.EXE,
then copy and import these files into the registry of each client
computer that requires remote access.
For each PowerBuilder COM object, export the following registry
keys:1HKEY_CLASSES_ROOTPB100.<i>objectname</i><br />HKEY_CLASSES_ROOTPB100.<i>objectname</i>.<i>version_number</i><br />HKEY_CLASSES_ROOTCLSID{<i>objects_clsid</i>}You may also need the following registry keys for the PowerBuilder COM server:
1HKEY_CLASSES_ROOTTypeLib{<i>comserver_typelib_id</i>}<br />HKEY_CLASSES_ROOTAppID{<i>comserver_application_id</i>}
Connecting to remote objects
using PowerBuilder
PowerBuilder 6 or greater clients can use the ConnectToNewRemoteObject function
to activate remote objects, as shown in this code fragment:
1 |
OLEObject remobj<br />remobj = CREATE OLEObject<br />remobj.ConnectToNewRemoteObject("myremotehostname", &<br /> "PB10.employee") |
For PowerBuilder 7 or greater clients, the remote object’s
CLSID string can be used in the classname parameter:
1 |
remobj.ConnectToNewRemoteObject("myremotehostname", &<br /> "clsid:0EA53FED-646A-11D2-BF8E-00C04F795006") |
The use of the object’s CLSID as the classname parameter
eliminates the need for any client-side configuration.
Connecting to remote objects using C++
C++ clients that use header files created
from the generated PowerBuilder COM server IDL file can use the remote
object’s CLSID in the activation request:
1 |
COSERVERINFO ServerInfo;<br />MULTI_QI mqi[1];<br />OLECHAR wszHostName[MAXFILE];<br />LPTSTR pszHost=NULL;<br /><br />memset(&ServerInfo,0,sizeof(ServerInfo));<br />pszHost =GetUserRequestedHostName();<br />mbstowcs(wszHostName,pszHost,MAXFILE);<br /><br />ServerInfo.pwszName = wszHostName;<br />mqi[0].pIID = &IID_Iemployee;<br />mqi[0].pItf = NULL;<br />mqi[0].hr = S_OK;<br /><br />// Create employee object on the desired server<br />hr = CoCreateInstanceEx(CLSID_Employee,NULL,<br /> CLSCTX_REMOTE_SERVER,&ServerInfo,1,mqi); |