Handling Interdependent Objects in Automation - An Example of a Bank Server Object

-->

Bank : This application explains component creatability with a Client application perspective. I got most of my inputs by using Microsoft Schedule+ Application . It supports lots of objects like Appointments, Alarm, Schedule, etc,. One important thing in that application is that, most of these components, any Client application can't create as it is. What I mean by that, in VC++, Client can't creat these compnents by calling CoCreateInstance function, as these classes don't have coclass property attached to them. Similary in VB Client, you can't just say " Dim AlarmObj as New Alarm ". That means, there are objects which the Microsoft Schedule+ server exposes, which the Client applications can't directly create. So, to creat them, user uses some other objects (whcih can be created directly). For example, assume a case where a SingleAppointment object is there with you. You can create a Alarm Object by calling one of its method i.e. " Set AlarmObject = SingleAppointments.Alarm ". This is very nice feature, which enable lots of inherent security in your object design.

The Server component that I have developed, is a Simple Bank object. The main security in this server is, even though it exposes a BankAccount object, any Client application can't create a BankAccount object directly. This is very much true in real life also. For example, any Account you can think of is never existant in real world, unless it is given out by a Bank. So, nobody can have a Bank account with himself without the account being related to some Bank. Sorry.. for saying the same things again. But, it is very necessary to expain this. You see, the flexibility that you provide for creating the objects from your Server component is a very critical issue. Generally, I have seen some applications, where in the Server allows user to create all the objects they have without ever bringing out the creatability in to picture.

I have developed this server, keeping all these things in mind. It has been developed using ATL and VC++ 5.0. I have also written two sample Test applications to demonstrate my point of view. One test application is written using VB 5.0 and other is written using VC++ 5.0.

For simplicity sake, I have considered only three objects. viz. Bank , IAccount , IAccountManager. One more thing that I have done in this server application is that, it implements COM Collection class. It also shows how to use STL vector library. The server is a inproc server and has MFC support also.

There is very well defined clear heirarchy existing in creating the three components the server exposes. In fact initially Client application can creat only one (i.e Bank Object) of these three components. Other components (AccountManager and Account) can't be created. Of course in real life, an AccountManager and an Account can't exist, without being related to particular bank.

As mentioned earlier, the Client will creat first the Bank object. Once he is throug with this, he will ask the created Bank object, to get the AccountManager using one of its methods (i.e. GetAccountManager()). Once he gets the AccountManager, he will go for creating an account. The AccountManager object, acts like a collection class. He maintains a list of Account that are there in the Bank. The client calls Add method of AccountManager to create a new Account. If the AccountManager feel it is ok to create a new account, it will return a Account object. Thus in turn, Bank object is managing the whole show. The whole control is with the Bank Object.

One main thing to observe is the IDL file. In this you can clearly make out that we have AccountManager and Account objects.


-------------------
// BankAccount.idl : IDL source for BankAccount.dll
//

// This file will be processed by the MIDL tool to
// produce the type library (BankAccount.tlb) and marshalling code.

import "oaidl.idl";
import "ocidl.idl";

[
	uuid(68B00060-801D-11D2-A7DE-00C04F79FED8),
	version(1.0),
	helpstring("BankAccount 1.0 Type Library")
]
library BANKACCOUNTLib
{
	importlib("stdole32.tlb");
	importlib("stdole2.tlb");

	typedef enum 
	{
		ACCOUNT_SAVINGS,
		ACCOUNT_CURRENT,
		ACCOUNT_MISC
	}Enum_Account_Type;

	[
		object,
		uuid(68B00071-801D-11D2-A7DE-00C04F79FED8),
		dual,
		helpstring("IAccountManager Interface"),
		pointer_default(unique)
	]
	interface IAccountManager : IDispatch
	{
		[id(1), helpstring("Add an account")] HRESULT Add([out, retval] IDispatch** ppAccount);
		[id(2), helpstring("Remove the current selected item (if any)")] HRESULT Remove();
		[id(3), helpstring("Item get the One based Indexed Account")] HRESULT Item([in] short int nIndex,[out, retval] IDispatch** ppAccount);
		[id(4), helpstring("Returns Number of Accounts ")] HRESULT Count([out, retval] short int* nNoOfAccounts);
		[id(-4), helpstring("method _Enum")] HRESULT _Enum([out, restricted] short int* pSafeArray);
	};
	[
		object,
		uuid(68B00073-801D-11D2-A7DE-00C04F79FED8),
		dual,
		helpstring("IAccount Interface"),
		pointer_default(unique)
	]
	interface IAccount : IDispatch
	{
		[propget, id(1), helpstring("property Type")] HRESULT Type([out, retval] Enum_Account_Type *pVal);
		[propput, id(1), helpstring("property Type")] HRESULT Type([in] Enum_Account_Type newVal);
		[propget, id(2), helpstring("Account Holder's Name")] HRESULT Name([out, retval] BSTR *pVal);
		[propput, id(2), helpstring("Account Holder's Name")] HRESULT Name([in] BSTR newVal);
	};

	[
		object,
		uuid(68B0006F-801D-11D2-A7DE-00C04F79FED8),
		dual,
		helpstring("IBank Interface"),
		pointer_default(unique)
	]
	interface IBank : IDispatch
	{
		[id(1), helpstring("Method to get AccountManager object of the Bank")] HRESULT GetMeAccountManager([out, retval] IDispatch** ppAccountManager);
	};
	[
		uuid(68B00070-801D-11D2-A7DE-00C04F79FED8),
		helpstring("Bank Class")
	]
	coclass Bank
	{
		[default] interface IBank;
	};
/*
	[
		uuid(68B00072-801D-11D2-A7DE-00C04F79FED8),
		helpstring("AccountManager Class")
	]
	coclass AccountManager
	{
		[default] interface IAccountManager;
	};
	[
		uuid(68B00074-801D-11D2-A7DE-00C04F79FED8),
		helpstring("Account Class")
	]
	coclass Account
	{
		[default] interface IAccount;
	};
*/
};

Probably there might be some more articles about Collection class objects.

VC Test project - 5 KB

VB Test project sources zip file name here - 18 KB


Bank Server Download source - 53 KB



Comments

  • Usefull to me

    Posted by Legacy on 03/27/2003 12:00am

    Originally posted by: swordingliang

    I have succeedfully compiled and run the client app
    and server app.But Is this means it is possible
    for them to transfer large datas without errors!

    Reply
  • Error while executing VCBankTest file

    Posted by Legacy on 04/05/2002 12:00am

    Originally posted by: anandkumar

    On compilation i have got this error
    
    

    fatal error C1010: unexpected end of file while looking for precompiled header directive

    Reply
  • Excellent idea but one small bug found...

    Posted by Legacy on 01/01/2000 12:00am

    Originally posted by: Craig Green

    This was an excellent article but I did find one small (but signicant) bug. When you queried the Bank to get an IDispatch of an AccountManager an extra QueryInterface was added into your method that should not have occurred:

    hr = pAccountManagerObj->QueryInterface(IID_IAccountManager,reinterpret_cast<void**>(&pIAccountManager));

    Since you are attempting to retrieve the IDispatch there is no reason to get a pointer to IAccountManager (this is done on the client side).

    Although a small bug it did cause an automation server (out of process) to stay in memory since some of the objects still had references to them even though the main object (the Bank in your case) was released correctly.

    A correct version of the method should be:

    STDMETHODIMP CBank::GetMeAccountManager(IDispatch** ppAccountManager)
    {
    AFX_MANAGE_STATE(AfxGetStaticModuleState())

    HRESULT hr;
    IAccountManager* pIAccountManager = NULL;
    CComObject<CAccountManager>* pAccountManagerObj = NULL;
    LPDISPATCH pDispatch = NULL;

    hr = CComObject<CAccountManager>::CreateInstance(&pAccountManagerObj);

    if(FAILED(hr))
    return hr;

    hr = pIAccountManager->QueryInterface(IID_IDispatch,reinterpret_cast<void**>(ppAccountManager));

    if(FAILED(hr))
    {
    delete pAccountManagerObj;
    pAccountManagerObj = NULL;
    return hr;
    }

    return hr;
    }

    This same problem holds true in the AccountManager class when getting an IDispatch to an Account.

    Keep up the good articles - there should be more articles like this about object design as opposed to the abundance of utility classes. Thanks for the ideas...

    Reply
  • Question

    Posted by Legacy on 01/24/1999 12:00am

    Originally posted by: Hai NGuyen

    Hi Shashi Kumar M. Kolavi , how do you do!
    Im Hai Nguyen, a Vietnamese and i am living in VietNam. Now i am studying MSMQ(Microsoft Message Queue), I want to send message between two site, so I don't know how to do it. Can you help me! If you know informaion about it, please send it for me ASAP following email address hainguyen@psv.com.vn. thank you very must.

    Best regards,
    HaiNguyen.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Hybrid cloud platforms need to think in terms of sweet spots when it comes to application platform interface (API) integration. Cloud Velocity has taken a unique approach to tight integration with the API sweet spot; enough to support the agility of physical and virtual apps, including multi-tier environments and databases, while reducing capital and operating costs. Read this case study to learn how a global-level Fortune 1000 company was able to deploy an entire 6+ TB Oracle eCommerce stack in Amazon Web …

  • Live Event Date: August 20, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT When you look at natural user interfaces as a developer, it isn't just fun and games. There are some very serious, real-world usage models of how things can help make the world a better place – things like Intel® RealSense™ technology. Check out this upcoming eSeminar and join the panel of experts, both from inside and outside of Intel, as they discuss how natural user interfaces will likely be getting adopted in a wide variety …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds