由於在嘗試用BCB 4訪問NameService時,遇到了一些奇奇怪怪的問題,而Visibroker所帶的例子卻可以用bcc32正常編譯運行,俺決定從頭做一個程序看看問題出在哪裡。折騰了一夜,結論是做服務器還是不用Corba Server wizard好。(我還是不明白為什麼?)
1、File| New, Multitier,Corba IDL File:
interface Order{
string Name();
};
存為order.idl
2、File|New, Consol Wizard,生成一個無vcl支持的consol應用。
3、Project|Add to project,選上剛寫的order.idl,Project | Compile之。
4、File|New, Miltitier, Corba Object Implementation,IDL選剛寫的order.idl,Interface選Order,為簡明起見,其它的名字就不改了。確定,自動生成OrderServer.cpp。
5、在OrderServer.cpp中找到char* OrderImpl::Name(),在其函數體中寫:
return "Hi, I am Test CorbaServer";
6、File | Save All,Unit1.cpp存為tcnServer.cpp,Project存為tcnServer.bpr。然後Make之。一個簡單的Corba Server就做好了。
7、測試運行一下,然後在MS-Dos方式下運行osfind.exe(應該在path裡,否則到$(VBroker)\bin裡找),這時會顯示一系列的corba信息:
C:\>osfind
osfind: Found one agent at port 14000
HOST: YANGWU
osfind: Found 1 OADs in your domain
HOST: YANGWU
osfind: Following are the list of Implementations registered with OADs.
HOST: YANGWU
REPOSITORY ID: IDL:CorbaTester/DBServer2Factory:1.0
OBJECT NAME: DBServer2
osfind: Following are the list of Implementations started manually.
HOST: YANGWU
REPOSITORY ID: IDL:Order:1.0
OBJECT NAME: OrderObject
REPOSITORY ID: IDL:visigenic.com/Activation/OAD:1.0
OBJECT NAME: 61.132.58.166
8、確定無誤後,回到IDE中,打開tcnServer.CPP,在#include的最後部分加上:
#include "CosNaming_c.hh"
然後,Project | Add To Project,將$(VBroker)\lib\name_br.lib加到工程中,這時tcnServer.CPP的頂部分出現USELIB("..\..\..\vbroker\lib\name_br.lib"); 一行代碼。其中的path與你的Visibroker安裝目錄及工程的保存位置都有關,以你的BCB生成的代碼為准。
9、boa->obj_is_ready(&order_OrderObject);一句(如無意外應為26行),在這一行和下邊的注釋// Wait for incoming requests之間加上以下代碼段,完成NamingContext建立、Name建立、Name綁定的工作:
//獲取由命令行參數傳入的NameComponent
const char* id = argv[1];
const char* kind = argv[2];
//取得默認的NamingContext對象
CosNaming::NamingContext_var context = CosNaming::NamingContext::_bind();
//生成一個Name對象
CosNaming::Name name;
//設定Name中只包含1個{id,kind}的NameComponet
name.length(1); name[0].id = id; name[0].kind = kind;
//將該名字綁定給程序中建立的對象實例order_OrderObject
context->bind(name, &order_OrderObject);
//在consol上輸出已經綁定的名字。
cout << "The object is bound: \"" << name[0].id << "\" \"" << name[0].kind << "\"" << endl;
10、File | Save All,Project | Make之。
11、測試運行:進入MS-DOS方式,
start nameextf MyTester test.log //啟動NamingContext Factory
start tcnServer MyName MyKind //啟動服務器,指定其名字為{MyName, MyKind}
再用osfind查看就會發現最後的REPOSITORY裡OBJECT NAME裡出現了一個OrderObject。
D:\Program Files\Borland\CBuilder4\Projects\tcn>osfind
osfind: Found one agent at port 14000
HOST: YANGWU
osfind: Found 1 OADs in your domain
HOST: YANGWU
osfind: Following are the list of Implementations registered with OADs.
HOST: YANGWU
REPOSITORY ID: IDL:CorbaTester/DBServer2Factory:1.0
OBJECT NAME: DBServer2
osfind: Following are the list of Implementations started manually.
HOST: YANGWU
REPOSITORY ID: IDL:omg.org/CosNaming/NamingContext:1.0
OBJECT NAME: Tester/1
REPOSITORY ID: IDL:omg.org/CosNaming/ExtendedNamingContextFactory:1.0
OBJECT NAME: Tester
REPOSITORY ID: IDL:visigenic.com/Activation/OAD:1.0
OBJECT NAME: 61.132.58.166
REPOSITORY ID: IDL:Order:1.0
OBJECT NAME: OrderObject
--------------------------------------------------------------------------------
下邊就做個Client來試試訪問。
1、File | New,Consol Wizard,做一個不支持VCL的consol應用。
2、Project| Add To Project,將選前邊做server時寫的order.idl加進來。
3、File | Save All,取名為tcnClientConsol.bpr(.cpp),存到server同一目錄裡。(在其下建立一個client子目錄似乎也不錯)。
4、Edit | Use Corba Object,IDL File已經填好,如果不對手動改為order.idl,Interface選Order,Object Name寫OrderObject(做服務器時指定的)。其余不改,確定。
5、注意此時主程序中已經完成了orb和boa的初始化工作。注意,注釋掉boa->impl_ready();!
6、在主程序頭部加上#include "CosNaming.hh",並將$(VBroker)\lib\name_br.lib加進Project。
7、在main()的那個try的最後,加上如下代碼:
const char* id=argv[1];
const char* kind=argv[2];
CosNaming::NamingContext_var context=CosNaming::NamingContext::_bind();
CosNaming::Name name;
name.length(1); name[0].id=id;name[0].kind=kind;
CORBA::Object_var obj=context->resolve(name);
Order_var order=Order::_narrow(obj);
cout<< "test result: "<<order->Name()<< endl;
8、啟動服務器並綁定名字給它,然後運行客戶程序。要說明的是如下幾點:首先我們在服務器中沒有注銷名字的動作,所以用綁定過的名字再來啟動服務器就會提示已經綁定過的提示並自動退出,所以每次要用不同的名字來啟動服務器,或每次都將test.log刪掉後從頭做。其次如果test.log不清除,那只要有一個服務器的實例在運行,就可以使用定義過的任何一個名字來取得服務器對象引用。第三測試過程可以不退出nameextf這個factory,省掉操作,而如果不刪除test.log的話,重啟nameextf後,它會自動恢復到上次退出時的狀態,即所有的名字仍可使用。最後,如果進行名字綁定的那個對象實例在內存中,那麼使用該名字訪問該對象速度最快,用其它名字則要慢很多(3~5秒)。
--------------------------------------------------------------------------------
做一個漂亮的Windows客戶
1、File | New,Multitier,Corba Client,GUI型,IDL選order.idl。
2、Edit | Use Corba Object,Interface選Order,ObjectName填OrderObject。
3、File | Save All,Project存為tcnClient.bpr,unit1.cpp存為OrderClient.cpp
4、Form1上放一個Edit1,一個Button1,Button1的OnClick代碼為:
Edit1->Text=AnsiString(order->Name());
5、這時一個簡單的CORBA CLIENT做好了,試一下Project | Make,Run。
6、在Form1上再放兩個Edit(2,3),其Text分別為"MyName","MyKind",放兩個Lable,注明這兩個Edit分別代表"name[0].id","name[0].kind"。
7、在Form1上放個Button,Button2的OnClick代碼為:
try {
Edit1->Text="正在查找名為:{"+Edit2->Text+","+Edit3->Text+"}的對象";
CosNaming::NamingContext_var context = CosNaming::NamingContext::_bind(); //取根名字空間
CosNaming::Name name;
char id[32],kind[32];
strcpy(id ,Edit2->Text.c_str());
strcpy(kind ,Edit3->Text.c_str());
name.length(1);
name[0].id = id;
name[0].kind = kind; //以上將Edit2,Edit3的內容組成一個名字,存在name中。
CORBA::Object_var object = context->resolve(name); //求解這個名字,得到對CORBA對象的引用
Order_var test = Order::_narrow(object);
if(!CORBA::is_nil(test)) {Edit1->Text=AnsiString(test->Name()); }
else Edit1->Text="訪問失敗!";
}
catch(const CORBA::Exception& e)
{
ShowMessage(e._description.name());
exit(1);
}
--------------------------------------------------------------------------------
樣本工程源碼(內含consol Server、WinGUI Server、consol Client、WinGUI Client)