Library Zone Articles
External Articles
Byte Size

Discovery Zone Catalogue
Diary
Links
Bookstore
Interactive Zone Ask the Gurus
Discussion Groups
Newsletters
Feedback
Etc Cartoons
Humour
COMpetition
Advertising
Site Builder ASP Web Ring ASP Web Ring

Click here
The Developer's Resource & Community Site
COM XML ASP Java & Misc. NEW: VS.NET
International This Week Forums Author Central Find a Job

String Binding Moniker

Download print article

Assumed knowledge: This article assumes you are familiar with COM Monikers and DCE/MS RPC.

Introduction:

The String Binding (SB) Moniker is a moniker that resolves a string binding to a connection with a DCE RPC server. The RPC server runs on Linux. The moniker runs on Windows. The server is implemented using Free DCE, an Open Source implementation of DCE RPC [1]. Functionality inside the RPC server will be invoked from a VB Client through the CreateObject method.

I will first describe the implementation of the DCE RPC server on Linux. Then I will describe the moniker. And finally the VB client that uses the moniker to talk to the RPC server. I will not discuss monikers in general.

RPC Server

The RPC server is an executable file that runs on Linux. It is built from 2 files: calculator.idl and calculator.c. The idl will be used at the client side as well. The idl file looks as follows:


[
   uuid(4d9f4ab8-7d1c-11cf-861e-0020af6e7c57),
   pointer_default(unique)

]
interface ICalculator

{
   long Add( 
      [in] handle_t binding_h , 
      [in] long a, [in] long b, [out] long* sum );

}

The file calculator.c implements the methods Add and main. Inside main, the RPC server is launched after which execution blocks inside rpc_server_listen. The RPC run-time will dispatch incoming calls to the method Add.


#include 
#include "calculator.h"

long Add( handle_t binding_h, long a, long b, long* sum )

{
   return *sum = a + b;

}

main( int argc, char* argv[] )

{
   unsigned32 status;
   rpc_binding_vector_t* binding_vector;
        
   unsigned_char_t* string_binding;
   unsigned_char_t* protseq;
   unsigned_char_t* networkaddress;
   unsigned_char_t* endpoint;
        
   rpc_server_register_if(
      ICalculator_v0_0_s_ifspec,
      NULL,
      NULL,
      &status );

   rpc_server_use_protseq(
      (unsigned_char_t*) "ncacn_ip_tcp",
      2, /* rpc_c_protseq_max_calls_default, */
      &status );
   
   rpc_server_inq_bindings(
      &binding_vector,
      &status );

   rpc_binding_to_string_binding(
      binding_vector->binding_h[0],
      &string_binding,
      &status );

   rpc_string_binding_parse(
      string_binding, 
      NULL, /* UUID */
      &protseq, &networkaddress, &endpoint,
      NULL, 
      &status );

   fprintf( stdout, "String binding = %s:%s[%s]\n", 
      protseq, 
      networkaddress, 
      endpoint );
   
   rpc_string_free( &protseq, &status );
   rpc_string_free( &networkaddress, &status );
   rpc_string_free( &endpoint, &status );

   fprintf( stdout, "Listening...\n" );
   rpc_server_listen( 1, &status );

   rpc_server_inq_bindings(
      &binding_vector,
      &status );

   rpc_binding_vector_free(
      &binding_vector,
      &status );

}

Note that I never check status. I tested this on Red Hat Linux release 5.2 in combination with Free DCE 1.2.2.

After you launch the server, the string binding will be displayed:


[frank@study sbmoniker]$ ./calculator 
String binding =  ncacn_ip_tcp:192.168.0.2[1112]
Listening...

Moniker

The SB moniker is packaged as a DLL. COM will load it into the client process when the moniker is needed to resolve a string binding to a connection with the RPC server. The moniker is implemented by the class CoSBMoniker. This class creates an instance of CCalculatorProxy when it is asked to resolve a string binding. The class CCalculatorProxy implements the connection by forwarding COM calls to the RPC server. I will now discuss both classes in turn.

CoSBMoniker

This class derives from the template CComMoniker [2]. This gives me default implementations of the interfaces IPersist, IPersistStream, IMoniker, IParseDisplayName, IROTData and IMarshal. I only override the implementation of IMoniker.


class ATL_NO_VTABLE CoSBMoniker : 
        public CComObjectRootEx,
        public CComCoClass,
        public CComMoniker<&CLSID_CoSBMoniker>

{
   ...
};


IMoniker::ParseDisplayName checks whether the string starts with the correct display name. The remaining part of the display name (after the colon) is the actual string binding. This part is copied to the member variable m_szStringBinding. When the method IMoniker::BindToObject is called, m_szStringBinding is used to resolve the string to a binding handle. For this, the helper method CalculatorProxyFromStringBinding is called. This method creates an instance of CCalculatorProxy.


STDMETHODIMP CoSBMoniker::BindToObject(
    IBindCtx*   pbc,
    IMoniker*   pmkToLeft,
    REFIID      riidResult,
    void**      ppvResult)

{
   if ( !ppvResult ) return E_POINTER;
   if ( pmkToLeft ) return E_UNEXPECTED;
   return CalculatorProxyFromStringBinding( riidResult, ppvResult ); 

}

HRESULT CoSBMoniker::CalculatorProxyFromStringBinding(
   REFIID  riid,
   void**  ppv)

{
   if ( !ppv ) return E_POINTER;
   if ( !m_szStringBinding ) return E_UNEXPECTED;

   handle_t hBinding;
   RPC_STATUS status;
   status = RpcBindingFromStringBinding(
      ( unsigned char* ) m_szStringBinding,
        &hBinding );
   if ( status != RPC_S_OK ) return E_FAIL;

   CComObject* pCalculatorProxy = NULL;
   CComObject::CreateInstance( &pCalculatorProxy );
   if ( !pCalculatorProxy ) return E_OUTOFMEMORY;

   pCalculatorProxy->SetBinding( hBinding );
   HRESULT hr = pCalculatorProxy->QueryInterface( riid, ppv );
   if ( FAILED(hr) ) delete pCalculatorProxy;
   
   return hr;

}
 
CCalculatorProxy


The moniker resolves the string binding to an instance of CCalculatorProxy inside CSBMoniker::BindToObject as shown in the previous section. CCalculatorProxy holds the binding handle of the RPC server and provides a method for each method of the interface of the RPC server.
CCalculatorProxy forwards all methods calls to the RPC server. Note that this is a badly maintainable solution since an extension of the interface affects both the RPC server and the moniker. An alternative solution is using an IDispatch-like interface instead of a custom interface.

The implementation of CCalculatorProxy is very trivial. The class is generated using the ATL Wizard after which all (one, in this case) methods of the RPC interface are added:


#include "calculator.h"

STDMETHOD(Add)(long a, long b, long* sum)

{
   if ( !sum  ) return E_POINTER;
   ::Add( m_hBinding, a, b, sum );
   return S_OK;

}


The included file calculator.h is generated in a custom build step as follows:


midl /osf calculator.idl

This generates calculator.h and calculator_c.c. The last file is added to the project. The file calculator.idl is the same one as used at the server-side.

Visual Basic Client

The VB client runs on a Windows machine where the moniker has been registered. It will use the string binding moniker to obtain a connection to the RPC server.

The form of the VB client consists of 4 text boxes and 1 button. The text boxes contain the string binding, the arguments a and b and the result sum. The button invokes CreateObject followed by Add(a,b).

 

Private Sub Add_Click()
    Dim obj
    Set obj = CreateObject( "frem.stringbinding.1:" & txtSB.Text)
    txtSum.Text = obj.Add(CLng(txtA.Text), CLng(txtB.Text))
End Sub


The CreateObject call is resolved to the following steps:

1. COM searches the registry for the class object that goes with frem.stringbinding.1.

2. COM asks the class object for an implementation of IMoniker.

3. The class object returns an instance of CoSBMoniker.

4. CoSBMoniker::ParseDisplayName is called.

5. CoSBMoniker::BindToObject is called.

6. The moniker returns an instance of CCalculatorProxy.

7. The moniker is released.

Conclusions

The String Binding Moniker can be a very useful building block in a system consisting of both Windows and UNIX platforms. Imagine your UNIX legacy code being wrapped as a COM object that can be invoked from an easily written VB client running on Windows. It certainly is a cheap alternative compared to a full-blown UNIX COM implementation.

Although not shown here, the String Binding Moniker can be generalized by resolving the string binding to an implementation of IDispatch instead of a custom interface. If the RPC server implements IDispatch as well, only one moniker has to be developed that handles any interface. Of course there is a performance penalty. Furthermore passing interface pointers to the RPC server will require unmarshal functionality on Linux. I will present this kind of functionality in another article.

References

[1] Free DCE RPC: https://www.bu.edu/~jrd/FreeDCE

Back to reference in Article

[2] CComMoniker: https://www.sellsbrothers.com/tools#basicmk

Back to reference in Article

Acknowledgements

Thanks go to the authors of Free DCE (Jim Doyle e.a.) and CComMoniker (Tim Ewald, Chris Sells and Don Box).

Further Reading

Author: Frank Rem - [email protected]
MSc Electrical Engineering
Software Engineer at Ocй-Technologies B.V. (Venlo, The Netherlands)

Frank will soon have his own site at Author Central - contribute to iDevResource.com and you can have one too!

© 2000 IDevResource.com


Click here

Contribute to IDR:

To contribute an article to IDR, a click here.

To contact us at IDevResource.com, use our feedback form, or email us.

To comment on the site contact our webmaster.

Promoted by CyberSavvy UK - website promotion experts

All content © Copyright 2000 IDevResource.com, Disclaimer notice

Learn C#

Code Project

WTL Introduction

Visit the IDR Forums