11.07.2015 Views

in PowerBuilder - sys-con.com's archive of magazines - SYS-CON ...

in PowerBuilder - sys-con.com's archive of magazines - SYS-CON ...

in PowerBuilder - sys-con.com's archive of magazines - SYS-CON ...

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

HAMMER THECOMPETITIONWITH POWERBUILDER®The market’s favorite RAD tool for creat<strong>in</strong>gWeb, desktop, “occasionally <strong>con</strong>nected” andtablet PC applications. With <strong>PowerBuilder</strong> youcan enhance web application performancewith XHTML Web DataW<strong>in</strong>dow. TMYou can alsoaccess your favorite RDBMS us<strong>in</strong>g ADO.NET,display data from different character sets<strong>in</strong> one DataW<strong>in</strong>dow with Unicode, or addhandwritten notes and signature collection withINK <strong>con</strong>trols support.Learn more about the power <strong>of</strong> Powerbuilderat sybase.com/powerbuilder© Copyright 2005 Sybase, Inc.. All rights reserved.


“The technology beh<strong>in</strong>dthe scenes is transparentto our clients. Theyrealize the benefits <strong>of</strong> it,though, <strong>in</strong> our ability tohandle transactions <strong>in</strong>half the time <strong>of</strong> ourcompetitors and at amuch lower cost.”— Glenn Santa Cruzcomponent types as well as multipleplatforms. After <strong>in</strong>vestigat<strong>in</strong>g itsoptions, DailyAccess found its solution<strong>in</strong> Sybase EAServer.EAServer Allows Code Reuse,Elim<strong>in</strong>ates Cost and Risk <strong>of</strong>Rewrit<strong>in</strong>g“When we found that we were grow<strong>in</strong>gfaster than what our <strong>sys</strong>tems couldsupport, we knew we needed to dosometh<strong>in</strong>g to allow us to scale <strong>in</strong>response to the demand,” says SantaCruz. “We needed someth<strong>in</strong>g thatwould support large numbers <strong>of</strong> <strong>con</strong>currentrequests. We also wanted toma<strong>in</strong>ta<strong>in</strong> our <strong>in</strong>tellectual <strong>in</strong>vestment <strong>in</strong>the Sybase <strong>PowerBuilder</strong> code we’ddeveloped as well as preserve our hardware<strong>in</strong>vestments. Sybase EAServer fitthe bill quite well. It allowed us to reuseour Sybase <strong>PowerBuilder</strong> code, to avoida costly and risky rewrite <strong>of</strong> our exist<strong>in</strong>g<strong>sys</strong>tems. Its ability to run Sybase<strong>PowerBuilder</strong>, Java, C/C++, and CORBAcomponents <strong>in</strong> a unified environmentwith seamless communication betweenthem provided us great flexibility as welooked ahead to add<strong>in</strong>g functionalityand creat<strong>in</strong>g new applications. WithSybase EAServer, we’re free to choosethe best technology for the particulartask rather than be<strong>in</strong>g locked <strong>in</strong>to as<strong>in</strong>gle component type.”For example, DailyAccess has foundthat Sybase <strong>PowerBuilder</strong> works bestfor develop<strong>in</strong>g report<strong>in</strong>g functionality,while Java is a better choice for otherfunctionality such as implement<strong>in</strong>gXML handl<strong>in</strong>g, external sockets, andregular expressions for text process<strong>in</strong>g.‘EAServer Is So Reliable,You Don’t Even KnowIt’s There’“By mov<strong>in</strong>g much <strong>of</strong> our code – ourbus<strong>in</strong>ess logic – to Sybase EAServer,”says Doug Porter, a s<strong>of</strong>tware developerat DailyAccess, “it’s much easier torefresh our code and to apply hot fixeswhen they’re required. Its cross-platformsupport is also quite beneficial.Thanks to Sybase EAServer, we nowhave the ability to use the right programm<strong>in</strong>glanguage for the right job onthe right platform. Best <strong>of</strong> all,” Porteradds, “Sybase EAServer is so reliable,you don’t even know it’s there. It justruns, and that lets us focus on otherth<strong>in</strong>gs. It’s transparent to our customers,but it’s the key to the uptime they see,which is very important to them.”Perhaps above all, DailyAccessrequires reliability. “In our market, failureis not an option,” says Santa Cruz.“If we deploy a <strong>sys</strong>tem that doesn’t giveour customers the <strong>con</strong>fidence that theirrequests or transactions are be<strong>in</strong>g handledpromptly and accurately, they’rego<strong>in</strong>g to feel that their retirement plansare at risk. One <strong>of</strong> the best th<strong>in</strong>gs wecan say about Sybase EAServer is thatit’s been extremely stable.”“As we look ahead,” Santa Cruzadds, “I th<strong>in</strong>k we’re evolv<strong>in</strong>g <strong>in</strong>to a fullblownWeb application that’s hosted onSybase EAServer. We’ve still got a largeamount <strong>of</strong> code that we want to move“We needed someth<strong>in</strong>gthat would support largenumbers <strong>of</strong> <strong>con</strong>currentrequests. We also wantedto ma<strong>in</strong>ta<strong>in</strong> our <strong>in</strong>tellectual<strong>in</strong>vestment <strong>in</strong> the Sybase<strong>PowerBuilder</strong> code we’ddeveloped. SybaseEAServer fit the bill quitewell. It allowed us to reuseour <strong>PowerBuilder</strong> code,to avoid a costly andrisky rewrite <strong>of</strong> ourexist<strong>in</strong>g <strong>sys</strong>tems.”— Glenn Santa Cruzonto Sybase EAServer so it can beshared across all <strong>of</strong> our applications.The bottom l<strong>in</strong>e is that for us to rema<strong>in</strong>competitive, we need to be nimble.That means automat<strong>in</strong>g as much as wecan beh<strong>in</strong>d the scenes to <strong>in</strong>crease efficiencyand keep costs low. SybaseEAServer enables us to do that. ▼…This article is repr<strong>in</strong>ted with permission fromSybase Incorporated.~<strong>con</strong>t<strong>in</strong>ued from page 3~JavaServer Faces DataW<strong>in</strong>dowexpect the GUI layer to <strong>in</strong>teract with the bus<strong>in</strong>ess logic classes, notbypass the bus<strong>in</strong>ess logic and object-relational mapp<strong>in</strong>g layers.• I th<strong>in</strong>k it’s past time (both for the JSF DataW<strong>in</strong>dow and DataW<strong>in</strong>dow.NET)that we got rid <strong>of</strong> the PBL, as least for DataW<strong>in</strong>dowobjects. In both environments, it’s counter-<strong>in</strong>tuitive to put a collection<strong>of</strong> source code from different objects <strong>in</strong>to a s<strong>in</strong>gle non-humanreadable file. It also causes problems with source <strong>con</strong>trol <strong>sys</strong>tems, <strong>in</strong>which you’ll want to be able to check out a particular DataW<strong>in</strong>dowObject, not the entire PBL. Given that the source <strong>con</strong>trols <strong>sys</strong>tems <strong>in</strong>these two IDEs are file based, it’s time that the DataW<strong>in</strong>dow <strong>con</strong>troland the DataStore can be assigned with a file that represents theDataW<strong>in</strong>dow object source. Further, it would be an additionaladvantage if the DataW<strong>in</strong>dow object syntax <strong>in</strong> that file could besaved <strong>in</strong> XML format.One <strong>of</strong> the significant new features <strong>in</strong>troduced with DataW<strong>in</strong>dow.NET2.0 is the ability to work directly with .NET DataSets andDataTables. That makes work<strong>in</strong>g with DataW<strong>in</strong>dow.NET more <strong>in</strong>tuitivefor seasoned .NET developers. What JSF DataW<strong>in</strong>dow will needto really capture the attention <strong>of</strong> seasoned Java developers is some <strong>of</strong>the same th<strong>in</strong>k<strong>in</strong>g. There needs to be some way to use Java classes asthe data source rather than expect<strong>in</strong>g the JSF DataW<strong>in</strong>dow to beallowed to directly access the database.Don’t get me wrong. I th<strong>in</strong>k a Java 4GL would be a good th<strong>in</strong>g, primarilybecause <strong>of</strong> how much time it takes to get anyth<strong>in</strong>g done us<strong>in</strong>ga 3GL. But there’s some m<strong>in</strong>dset hurdles to overcome, and it will takemore than just a great product to overcome them. It will also takemarket<strong>in</strong>g and marketplace presence, someth<strong>in</strong>g that Sybase hasn’tbeen do<strong>in</strong>g well for <strong>in</strong>dividual products for some time. ▼6 PBDJ volume12 issue11pbdj.<strong>sys</strong>-<strong>con</strong>.com


Never write another SQL <strong>in</strong>sert, update,or delete statement as long as you live.While DataW<strong>in</strong>dow® .NET is easy to use, it is also very flexible,giv<strong>in</strong>g you complete <strong>con</strong>trol over the look and feel <strong>of</strong> your databoth at design time and programmatically at runtime.DataW<strong>in</strong>dow .NET is the only .NET component that can be used fordata entry forms and reports! Use the power <strong>of</strong> patented technologyto visually create the data access and presentation layers <strong>of</strong> yourW<strong>in</strong>dows Forms, ASP .NET and Tablet PC applications.Easily access data fromany data source andpresent ityour way.You no longer need toworry about writ<strong>in</strong>gSQL <strong>in</strong>sert,update ordelete statements,DataW<strong>in</strong>dow .NETdoes the heavy lift<strong>in</strong>gfor you!More than just a grid <strong>con</strong>trol, theDataW<strong>in</strong>dow <strong>of</strong>fers 10 presentationstyles <strong>in</strong>clud<strong>in</strong>g Graph, Crosstab,and TreeView.F<strong>in</strong>d out for yourself how powerful, yet easy to useDataW<strong>in</strong>dow .NET really is. Visitwww.sybase.com/dataw<strong>in</strong>dow.net for more <strong>in</strong>formationand to download an evaluation copy or call (800) 8 SYBASEand take your .NET application development to the next level!Copyright © 2005 Sybase, Inc.All Rights Reserved. All productand company names are trademarks<strong>of</strong> their respective owners.


Word Excel OutlookOffice 97 VBAWRD8.HLP VBAXL8.HLP VBAOUTL.HLPOffice 2000 VBAWRD9.CHM VBAXL9.CHM VBAOUTL9.CHMOffice XP VBAWD10.CHM VBAXL10.CHM VBAOL10.CHMTABLE 1 | VBA Help Files for Micros<strong>of</strong>t Office ApplicationsFIGURE 1 | The VBA script<strong>in</strong>g utility available with<strong>in</strong> Micros<strong>of</strong>t Officeproducts+++...n_cst_ole_word_97<strong>of</strong>_<strong>con</strong>nect ()<strong>of</strong>_visible (boolean ab_status)<strong>of</strong>_open (str<strong>in</strong>g as_filename)...: <strong>in</strong>teger: <strong>in</strong>teger: <strong>in</strong>teger...n_cst_word+ <strong>in</strong>v_word : n_cst_ole_word+ <strong>of</strong>_<strong>con</strong>nect (): <strong>in</strong>teger+ <strong>of</strong>_dis<strong>con</strong>nect () : <strong>in</strong>teger+ <strong>of</strong>_visible: <strong>in</strong>teger(boolean ab_status)... ......<strong>in</strong>v_wordn_cst_ole_word# <strong>in</strong>v_word : oleobject# <strong>in</strong>v_<strong>con</strong>st : n_cst_<strong>con</strong>stants_word_ole+ <strong>of</strong>_<strong>con</strong>nect (): <strong>in</strong>teger+ <strong>of</strong>_dis<strong>con</strong>nect (): <strong>in</strong>teger+ <strong>of</strong>_visible (boolean ab_status) : <strong>in</strong>teger... ......+++...n_cst_ole_word_2000<strong>of</strong>_<strong>con</strong>nect (): <strong>in</strong>teger<strong>of</strong>_visible (boolean ab_status) : <strong>in</strong>teger<strong>of</strong>_open (str<strong>in</strong>g as_filename) : <strong>in</strong>teger......n_cst_<strong>con</strong>stants_word_oleis because it’s not <strong>in</strong>stalled by default but <strong>in</strong>stead requires a custom<strong>in</strong>stallation <strong>of</strong> Micros<strong>of</strong>t Office. The documentation is provided as a set<strong>of</strong> help files as <strong>in</strong>dicated <strong>in</strong> Table 1.The VBA script<strong>in</strong>g utility that comes with those products also <strong>con</strong>ta<strong>in</strong>san object browser that can be used to determ<strong>in</strong>e which functionsare accessible on different objects and the syntax for us<strong>in</strong>g them (seeFigure 1). You access the VBA script<strong>in</strong>g utility from Tools->Macro->Visual Basic Editor with<strong>in</strong> the application, and then the object browseris available from the toolbar, from the View menu item, or by hitt<strong>in</strong>gF2. From with<strong>in</strong> the VBA Script<strong>in</strong>g utility you can br<strong>in</strong>g up the documentationfor a particular method, property, or event by hitt<strong>in</strong>g F1after select<strong>in</strong>g it (assum<strong>in</strong>g that the help files have been <strong>in</strong>stalled).The se<strong>con</strong>d issue raised above is the compatibility between versions<strong>of</strong> the same target application. Fortunately, at least with theMicros<strong>of</strong>t products, there is a fairly easy way to determ<strong>in</strong>e which version<strong>of</strong> the target application is <strong>in</strong>stalled. (This will be demonstratedonce we get <strong>in</strong>to the source code.) In addition, the OLE Automation+++...+++...wd100Wordswd10Percentwd10Sentences...: long: long: long...<strong>in</strong>v_<strong>con</strong>stn_cst_ole_word_XP<strong>of</strong>_<strong>con</strong>nect ()<strong>of</strong>_visible (boolean ab_status)<strong>of</strong>_open (str<strong>in</strong>g as_filename))...FIGURE 2 | Class diagram for OLE automation implementation objects= -4= -6= -2...: <strong>in</strong>teger: <strong>in</strong>teger: <strong>in</strong>teger...syntax for these applications is highly backward-compatible. Whenobjects (or methods, properties, or events <strong>of</strong> an object) are depreciatedby Micros<strong>of</strong>t <strong>in</strong> a new version <strong>of</strong> the application, they usually markthose as “hidden.” Hidden objects (or methods, properties, or events)still work with the newer version, but they don’t appear <strong>in</strong> the objectmodel for that new version. Obviously, because each new version <strong>of</strong>the application adds additional features that were not present <strong>in</strong> earlierversions, the syntax developed us<strong>in</strong>g a newer version <strong>of</strong> the objectmodel will not always work for an older version.As mentioned previously, <strong>PowerBuilder</strong> uses late b<strong>in</strong>d<strong>in</strong>g to <strong>in</strong>terfacewith OLE Automation objects, so we are unable to use the <strong>con</strong>stantsprovided <strong>in</strong> the Word type library. However, Micros<strong>of</strong>t does providean Excel spreadsheet on their MSDN site that <strong>con</strong>ta<strong>in</strong>s all <strong>of</strong> the<strong>con</strong>stants and their values used with<strong>in</strong> Office. (Those <strong>con</strong>stants arealso def<strong>in</strong>ed <strong>in</strong> the Micros<strong>of</strong>t supplied help files and can be browsedus<strong>in</strong>g the VBA script<strong>in</strong>g utility.) I downloaded that file and used that<strong>in</strong>formation to create an auto<strong>in</strong>stantiat<strong>in</strong>g nonvisual user object thatcould be used for a similar purpose as the type library, at least withrespect to the <strong>con</strong>stants (see Figure 2).The n_cst_<strong>con</strong>stants_word_ole class <strong>con</strong>ta<strong>in</strong>s the <strong>con</strong>stants and isdef<strong>in</strong>ed as an <strong>in</strong>stance variable on another class, n_cst_ole_word. Thatclass is basically a “virtual” class; it’s never actually called directly.Instead, descendants <strong>of</strong> it are created to handle each <strong>of</strong> the differentversions <strong>of</strong> Word we might actually <strong>in</strong>teract with. The virtual classdeterm<strong>in</strong>es which methods we are go<strong>in</strong>g to make available, and thedescendants actually implement those methods as appropriate. Thevirtual class returns an error message if the method is called, so if themethod is not implemented on a descendant, it implies that particularversion <strong>of</strong> Word does not support the method. This allows us to addadditional methods to the virtual class as new versions <strong>of</strong> Word, andadd new functions and implement them <strong>in</strong> whichever descendantsactually support them without hav<strong>in</strong>g to modify the classes represent<strong>in</strong>gearlier versions <strong>of</strong> Word. n_cst_word acts as a wrapper class so thatthe <strong>in</strong>stantiation <strong>of</strong> the appropriate descendant <strong>of</strong> n_cst_ole_word andcalls to its methods are handled automatically.In the <strong>of</strong>_<strong>con</strong>nect method <strong>of</strong> n_cst_word, the object determ<strong>in</strong>eswhich version <strong>of</strong> Word the user has <strong>in</strong>stalled and creates the appropriatedescendant <strong>of</strong> n_cst_ole_word (see List<strong>in</strong>g 1).Prior to version 8 <strong>of</strong> <strong>PowerBuilder</strong>, the standard method for handl<strong>in</strong>gerrors <strong>in</strong> OLE Automation was to create a user object that <strong>in</strong>heritedfrom the OLEObject class and then code its Error and ExternalExceptionevents. Then that class, rather than the OLEObject class, wouldbe used for the ConnectToObject or ConnectToNewObject call. Oneproblem with that approach is that some OLE Automation propertiesand method returns are themselves OLEObjects, and would not allowthemselves to be cast <strong>in</strong>to the descendant user object. Instead, a userobject based on OLEObject would have to be used, and then theSetAutomationPo<strong>in</strong>ter function <strong>of</strong> that object would be used to redirectprocess<strong>in</strong>g to an <strong>in</strong>stance <strong>of</strong> the custom class.That was all very complicated. It also tended to disassociate theerror-handl<strong>in</strong>g logic from the code that was mak<strong>in</strong>g the call to theobject that caused the error, which made recovery from the errorsomewhat problematic.Fortunately version 8 <strong>of</strong> <strong>PowerBuilder</strong> <strong>in</strong>troduced structured exceptionhandl<strong>in</strong>g, which greatly simplifies this for us. The object that weare us<strong>in</strong>g <strong>in</strong> this sample to <strong>in</strong>teract with Word is the <strong>in</strong>v_word <strong>in</strong>stancevariable <strong>in</strong> the n_cst_word class, and you can see from Figure 3 thatthe class we are us<strong>in</strong>g for it is OLEObject. We simply wrap our OLEAutomation calls <strong>in</strong> a try...catch...end try block and can deal with anyerrors that occur with<strong>in</strong> that block.We’re go<strong>in</strong>g to review some <strong>of</strong> the code from the sample application(which can be downloaded from www.pbdj.<strong>sys</strong>-<strong>con</strong>.com), certa<strong>in</strong>ly notall <strong>of</strong> it, just certa<strong>in</strong> code that illustrates some important <strong>con</strong>cepts.The <strong>of</strong>_visible function determ<strong>in</strong>es whether or not Word will actuallybe visible to the end user. It’s fairly straightforward, simply sett<strong>in</strong>gthe visible property <strong>of</strong> the Word application (not a <strong>PowerBuilder</strong> objectvisible property).10 PBDJ volume12 issue11pbdj.<strong>sys</strong>-<strong>con</strong>.com


THE STRAIGHT GOODS ON EAServer.BRING APPS TO THE WEBWITHOUT LEAVINGYOUR POWERBUILDERINVESTMENTBEHIND.It’s easy. It’s proven. Sybase EAServer is thecomplete solution with the highest ROIfor mov<strong>in</strong>g <strong>PowerBuilder</strong> applications to theWeb. But don’t just take our word for it. Sierrahave all rapidly web-enabled their <strong>PowerBuilder</strong> appswith a faster and easier time to market. To discover howyou can leverage your exist<strong>in</strong>g <strong>in</strong>vestments, check outour ROI Case Study Guide atClub, The Greenbrier Companies and Hennep<strong>in</strong> County, MN,www.sybase.com/pbextension.Information Anywhere SYBASE e-BUSINESS SOFTWARE.EVERYTHING WORKS BETTER WHEN EVERYTHING WORKS TOGETHER ṬM©2002 Sybase, Inc. All rights reserved. All trademarks are the property <strong>of</strong> their respective owners.


end tryReturn 1end function<strong>PowerBuilder</strong> does not support skipp<strong>in</strong>g “optional” arguments <strong>in</strong>OLE Automation function calls. For example, the Word Documentobject Close function used above takes three optional arguments:• SaveChanges• Orig<strong>in</strong>alFormat• RouteDocumentFIGURE 3 | OLE Control Properties <strong>in</strong> User Object pa<strong>in</strong>terEvent1 :3Event2 :3Event3 :3PBNI OLE ObjectEvent1 :2Event2 :2Event3 :2EventS<strong>in</strong>kConnectionPo<strong>in</strong>tEvent1 :1Event2 :1Event3 :1S<strong>in</strong>ce all the arguments are optional, we could have called it withoutpass<strong>in</strong>g any arguments. However, once we start pass<strong>in</strong>g arguments,we have to pass all the arguments through the last optional one wewish to pass. That is, we could pass the SaveChanges argument byitself, but we couldn’t pass that Orig<strong>in</strong>alFormat argument by itself.Instead, we would have to pass someth<strong>in</strong>g for the SaveChanges argumentas well as the Orig<strong>in</strong>alFormat argument (as we have done <strong>in</strong> thesample). This may not come as much <strong>of</strong> a surprise to many Power-Builder developers unless they have some Visual Basic background,because that development tool does support skipp<strong>in</strong>g optional arguments.<strong>PowerBuilder</strong> also does not support the use <strong>of</strong> named notationrather than positional notation for arguments.The <strong>of</strong>_pr<strong>in</strong>tpreview demonstrates the use <strong>of</strong> the AsStatement! keyword.The Word ActiveDocument Pr<strong>in</strong>tPreview method doesn’t takeany arguments and doesn’t have a return value, which makes it looklike a property. What’s more, there is a Word Pr<strong>in</strong>tPreview property aswell. Therefore, we need to use the AsStatement! to ensure that Power-Builder knows we are attempt<strong>in</strong>g to call a function rather than refer toa property.<strong>PowerBuilder</strong> Client ApplicationFIGURE 4 | Captur<strong>in</strong>g OLE Automation Eventspublic function <strong>in</strong>teger <strong>of</strong>_visible (boolean ab_status);IF IsNull ( <strong>in</strong>v_word ) THEN Return -1try<strong>in</strong>v_word.Visible = ab_statuscatch (OLERuntimeError MyOLEError )Return -1end tryReturn 1end functionThe <strong>of</strong>_open function demonstrates the use <strong>of</strong> multiple catch portions<strong>of</strong> the try...catch...end try block to handle different types <strong>of</strong> errors.public function <strong>in</strong>teger <strong>of</strong>_open (str<strong>in</strong>g as_filename);IF IsNull ( <strong>in</strong>v_word ) THEN Return -1try<strong>in</strong>v_word.Documents.open ( as_filename )catch (OLERuntimeError MyOLEError )Return -1catch (NullObjectError MyNullError )Return -1end tryThe <strong>of</strong>_close function shows how the <strong>con</strong>stant’s <strong>in</strong>stance variable isused to pass arguments to functions <strong>of</strong> the OLE object.public function <strong>in</strong>teger <strong>of</strong>_close ();try<strong>in</strong>v_word.Documents.close( &<strong>in</strong>v_<strong>con</strong>st.wdSaveChanges, &<strong>in</strong>v_<strong>con</strong>st.wdWordDocument )catch (OLERuntimeError MyOLEError )Return -1OLE Serverpublic function <strong>in</strong>teger <strong>of</strong>_pr<strong>in</strong>tpreview ();IF IsNull ( <strong>in</strong>v_word ) THEN Return -1long ll_typetryll_type = <strong>in</strong>v_word.ActiveW<strong>in</strong>dow.View.TypeIF ll_type = <strong>in</strong>v_<strong>con</strong>st.wdPr<strong>in</strong>tPreview THEN<strong>in</strong>v_word.ActiveDocument.ClosePr<strong>in</strong>tPreview()ELSE<strong>in</strong>v_word.ActiveDocument.Pr<strong>in</strong>tPreview( AsStatement! )END IFcatch ( OLERuntimeError MyOLEError )Return -1end tryReturn 1end functionSo far the method we’ve used to <strong>in</strong>teract with OLE Automationmethods and properties is no different from the method we used withOLE Custom Controls. The similarity ends when we come to handl<strong>in</strong>gevents though. While <strong>PowerBuilder</strong> exposes the events fired by the <strong>con</strong>trolwith<strong>in</strong> the IDE, it doesn’t do so for OLE Automation. For that matter,few programm<strong>in</strong>g languages do, and many OLE Automation targetsfire few – if any – events.Nonetheless, there is a mechanism for captur<strong>in</strong>g OLE Automationevents (see Figure 4), which is expla<strong>in</strong>ed <strong>in</strong> some detail <strong>in</strong> Micros<strong>of</strong>tKnowledge Base article 183599. Basically, it’s necessary to create anotherCOM object referred to as an “events<strong>in</strong>k” that implements the same“OLE objects store data <strong>in</strong>ternally <strong>in</strong>objects referred to as “streams,”which are <strong>con</strong>ta<strong>in</strong>ed with<strong>in</strong> otherobjects called ‘storages’”12 PBDJ volume12 issue11pbdj.<strong>sys</strong>-<strong>con</strong>.com


© 2003 Sybase, Inc. All rights reserved. All trademarks are the property <strong>of</strong> their respective owners.4GL RAD ToolsPOWERBUILDERTHE CLASSIC,TRIED-AND-PROVENCLIENT/SERVERDEVELOPMENT TOOL.POWERBUILDERTHE HANG-ONTO-YOUR-SEATCLIENT/SERVERDEVELOPMENT TOOL.For years, <strong>PowerBuilder</strong>® has reignedas the premier development toolfor client/server applications. Ournewest iteration extends both ourleadership and your <strong>in</strong>vestment<strong>in</strong> skills and applications forclient/server development. There’sa host <strong>of</strong> excit<strong>in</strong>g new features.Download all the technical detailsat sybase.com/powerbuilder.Take your client/server applicationsto the next level with the Power-Builder Native Interface. Integrateyour exist<strong>in</strong>g and new Power-Builder applications withC and C++ applications. Andeasily work with J2EE and .NETcomponents and applicationsexposed as Web Services. Detailsat sybase.com/powerbuilder.INFORMATION LIQUIDITY.SYBASE INTEGRATION TECHNOLOGIES.E VERYTHING WORKS BETTER WHEN EVERYTHING WORKS TOGETHER ṬM


FEATUREture named “PowerTipText” that allows automatic “bubble” help toappear dur<strong>in</strong>g a mouse hover.Just to be on the safe side, I selected the F1 key on my laptop <strong>in</strong>side<strong>of</strong> PocketBuilder and checked out the ShowPopupHelp ( ) and SetMicroHelp( ) commands. Guess what…“Not supported.” Okay…I knewthat! However, be<strong>in</strong>g a stubborn Great White North developer (youhave to be tough here <strong>in</strong> the Canadian w<strong>in</strong>ter), I set out to tackle thislimitation. One <strong>of</strong> the mechanisms I used to get there was the use <strong>of</strong>the database “<strong>sys</strong>tem tables” that the <strong>PowerBuilder</strong> and PocketBuilderIDEs create and ma<strong>in</strong>ta<strong>in</strong> for the developer.Still one <strong>of</strong> the great features <strong>of</strong> <strong>PowerBuilder</strong> and PocketBuilder istheir ability to use any RDBMS vendor’s database to store develop-Context-SensitiveHelpBuild<strong>in</strong>g and <strong>in</strong>tegrat<strong>in</strong>gWRITTEN BY CHRIS POLLACHSummertime here <strong>in</strong> Canada’s “Great White North” is hot andhumid but I found myself attend<strong>in</strong>g Sybase’s TechWave 2005<strong>con</strong>ference with punish<strong>in</strong>g 105F (40.5C) degree heat.The Las Vegas heat must have gotten to me as I started a new PocketBuilderapplication and wanted to encompass some <strong>of</strong> the “<strong>con</strong>textsensitive” help features that I have previously used <strong>in</strong> a <strong>PowerBuilder</strong>application. I knew that this was not go<strong>in</strong>g to be easy, as the Pocket PCoperat<strong>in</strong>g <strong>sys</strong>tem does not support the (Multiple Document Interface)behavior. As a result, neither the Micro-Help bar nor pop-up help (alsoknown as “bubble help”) are available as they would be <strong>in</strong> a standard<strong>PowerBuilder</strong> application. <strong>PowerBuilder</strong> developers also use a nice fea-16 PBDJ volume12 issue11pbdj.<strong>sys</strong>-<strong>con</strong>.com


ment data <strong>in</strong> the “<strong>sys</strong>tem table” area (see Figure 1). The <strong>sys</strong>tem tablearea is normally where you (or your DBA) place the database schemathat def<strong>in</strong>es the metadata (<strong>in</strong>formation about your data). This area isalso available to the <strong>PowerBuilder</strong> and PocketBuilder developmenttools along with Sybase’s InfoMaker report writer. All these Sybasedevelopment tools make use <strong>of</strong> the <strong>sys</strong>tem table area (would youbelieve designed and available s<strong>in</strong>ce <strong>PowerBuilder</strong> release 1.0) tostore “metadata” about your database. The first developer who <strong>con</strong>nectsto a new database area us<strong>in</strong>g InfoMaker, PocketBuilder, or<strong>PowerBuilder</strong> with DBA privileges (i.e., “Create Table”) has the developmenttool automatically add five new tables to the <strong>sys</strong>tem tablearea. These five tables are PBCatCol, PBCatEdt, PBCatFmt, PBCatTbl,and PBCatVld. To view these new System Tables, open the databasepa<strong>in</strong>ter and <strong>con</strong>nect to your favorite database, then select the“Tables” item <strong>in</strong> the TreeView <strong>of</strong> the database Pa<strong>in</strong>ter and use the“alternate” (aka politically <strong>in</strong>correct “right-hand”) mouse button toproduce a pop-up menu. From the pop-up menu, select the “ShowSystem Tables” option. Once selected, this will force InfoMaker, PocketBuilder,or <strong>PowerBuilder</strong> to show you all the <strong>sys</strong>tem table area –notice the PBCatxxx tables <strong>in</strong> the list.The PBCatxxx tables are where the Sybase IDE tools store extensionsto the database schema tables and columns that perta<strong>in</strong> to thedeveloper’s delivery <strong>of</strong> <strong>in</strong>formation to the GUI user. The DBMS doesnot care about the GUI world and, <strong>in</strong> fact, it detaches itself from it. Inthe graphic environment, however, we are <strong>con</strong>cerned about propertiessuch as font, height, units <strong>of</strong> measure, formatt<strong>in</strong>g, and validat<strong>in</strong>g. ThePBCatxxx tables supply this exact <strong>in</strong>formation to the Sybase developmenttools. It should be noted here that this applies only to databasedesigners who use tools like PowerDesigner or System Architect andknow how to also load this GUI <strong>in</strong>formation <strong>in</strong>to the Sybase PBCatxxxtables. Another alternative, before any development team starts itsproject work, is to have one developer take the time to use the DatabasePa<strong>in</strong>ter to <strong>in</strong>clude this extra “metadata.” Do<strong>in</strong>g so can improvethe development time <strong>of</strong> a project from 3 to 15 times.Assum<strong>in</strong>g that your manager is too naive or cheap to purchase adesign/model<strong>in</strong>g tool like PowerDesigner, fear not, you can still use theInfoMaker, PocketBuilder, or <strong>PowerBuilder</strong>’s DataBase pa<strong>in</strong>ter toachieve this tremendous productivity ga<strong>in</strong>; as you will see shortly, thiswill tie <strong>in</strong>to the need and delivery <strong>of</strong> the “Context Sensitive” help.Load<strong>in</strong>g Your MetadataTo beg<strong>in</strong> load<strong>in</strong>g your PBCatxxx System Tables us<strong>in</strong>g the InfoMaker,PocketBuilder, or <strong>PowerBuilder</strong> database pa<strong>in</strong>ter, open the databasepa<strong>in</strong>ter and carefully note the “extended” properties <strong>of</strong> either a “table”or a “column” entity. For a table, the extended property categories are<strong>in</strong> the General tab’s “Comments,” all <strong>of</strong> the Data Font, Head<strong>in</strong>g Fontand Label Font tab pages (see Figure 2). For the column entity, theextended properties are “Comments” <strong>in</strong> the General Tab, all <strong>of</strong> theHeaders, Display, Validation, and Edit Style tab pages (see Figure 3).Any property that you fill out <strong>in</strong> the areas listed above are automaticallysaved to the PBCatTbl <strong>sys</strong>tem table (for a table) and the PBCatCols<strong>sys</strong>tem table for any column properties that are beyond the vendor’sANSI implementation.I should also take the time to mention that the database pa<strong>in</strong>ter is<strong>in</strong>cluded <strong>in</strong> the current DataW<strong>in</strong>dow.NET product and will be present<strong>in</strong> the new DataW<strong>in</strong>dow.NET plug-<strong>in</strong> for Visual Studio 2005. So the tipsI am referr<strong>in</strong>g to <strong>in</strong> this article focus ma<strong>in</strong>ly on the <strong>PowerBuilder</strong> andPocketBuilder development tools but will also work for this new environmentas well. The PBCatxxx tables are always present after the first<strong>con</strong>nection to your Oracle, Sybase, Micros<strong>of</strong>t, IBM, or other DBMS. Ifthere are security implications for creat<strong>in</strong>g these five new <strong>sys</strong>temtables, Sybase provides DBA scripts to populate these table structuresmanually by us<strong>in</strong>g your favorite DBA utility.The next three PBCatxxx tables are for Edit Styles, Validation Rules,and Display Formats (see Figure 4). These extended properties can beadded to the System Table area us<strong>in</strong>g the “Extended Attributes” panel<strong>of</strong> the database pa<strong>in</strong>ter. This allows the developer to <strong>in</strong>put theseextended properties, which I would imag<strong>in</strong>e most seasoned Power-Builder developers would recognize also appears <strong>in</strong> the DataW<strong>in</strong>dowpa<strong>in</strong>ter. Tak<strong>in</strong>g the time to add this metadata <strong>in</strong> the DBMS will allowthis extra <strong>in</strong>formation to be available to the DataW<strong>in</strong>dow pa<strong>in</strong>ter dur<strong>in</strong>gthe creation <strong>of</strong> the DataW<strong>in</strong>dow object. Take note <strong>of</strong> this last statementas this also applies to the Table and Column extended propertiesas well.Remember though that the PBCatxxx <strong>sys</strong>tem tables are just standardDBMS tables that can be read by your development tool. While <strong>in</strong>the database pa<strong>in</strong>ter, you can locate the ISQL pane and select <strong>in</strong>formationfrom any <strong>of</strong> the PBCatxxx tables. For example, <strong>in</strong> the Employeetable – if I attach a “Display Format” <strong>of</strong> '$#,##0;($#,##0)' to the Salarycolumn, then, us<strong>in</strong>g the follow<strong>in</strong>g query:SELECT "pbcatfmt"."pbf_frmt","pbcatcol"."pbc_cnam","pbcatcol"."pbc_tnam"FROM "pbcatcol","pbcatfmt"WHERE ( "pbcatfmt"."pbf_name" = "pbcatcol"."pbc_mask" );FIGURE 1 | FIGURE 2FIGURE 3FIGURE 4FIGURE 5we can see if there is a correlationbetween the Display Format andany column – <strong>in</strong> particular, theSalary column. Runn<strong>in</strong>g theabove query resulted <strong>in</strong> the follow<strong>in</strong>gresult set <strong>in</strong> my development environment and <strong>in</strong>dicated thatthe display format I just created was <strong>in</strong>deed <strong>con</strong>nected to the salarycolumn with<strong>in</strong> the Employee table.Us<strong>in</strong>g the above <strong>in</strong>formation and test we can also extend thisbehavior to the “Comments” part <strong>of</strong> the PBCatCols <strong>sys</strong>tem table. Thereason I might be <strong>in</strong>terested <strong>in</strong> this would be to automate the Help filegeneration. Then I could use the ShowPopUp ( ) command <strong>in</strong> Power-Builder to dynamically support this feature. An SQL query for this<strong>in</strong>formation might look like this:pbdj.<strong>sys</strong>-<strong>con</strong>.comPBDJ volume12 issue1117


FIGURE 6 |FIGURE 8 |FIGURE 7 | FIGURE 9 |SELECT "pbcatcol"."pbc_cnam","pbcatcol"."pbc_cmnt"FROM "pbcatcol"WHERE "pbcatcol"."pbc_cmnt" is not NULL;The above query should return the column name and the column’scomment textual value as located <strong>in</strong> the PBCatCol table. For this test Iadded a comment to the Employee’s Sex column and the query aboveresulted <strong>in</strong> the ISQL result set shown <strong>in</strong> Figure 5.Help CompilationOnce you have taken the time to populate appropriate commentson the data elements with<strong>in</strong> your data model (schema), the extendedproperties will also be loaded <strong>in</strong>to your database’s <strong>sys</strong>tem tables. Youcan use the technique I just described earlier to extract the columnname and the column’s comment text us<strong>in</strong>g the previous SQL example.To test this, I commented the “Contact” table’s columns and ran theSQL, which resulted <strong>in</strong> a two-column output <strong>in</strong> the ISQL pane <strong>of</strong> thedatabase pa<strong>in</strong>ter. To export this <strong>in</strong>formation, I used the “alternate”mouse button (RHMB) and chose the “Save Rows As” option <strong>in</strong> theresult<strong>in</strong>g pop-up menu. I then proceeded to save the result set as a tabdelimited text file. Us<strong>in</strong>g this format allows the developer to easily<strong>in</strong>clude this key <strong>in</strong>formation <strong>in</strong>to any help compiler.The favorite product that I use to generate help files is called “Docto-Help”from ComponentOne. I can utilize this tool to generate varioushelp file flavors for all my Web, PocketBuilder, and <strong>PowerBuilder</strong>projects. I will briefly show you the highlights <strong>of</strong> this process. The firststep is to create a new project and import the tabbed delimited textoutput from the database pa<strong>in</strong>ter as described above. The new projectwill generate an MS-Word document where you can import the text filewith the column name and description. At this po<strong>in</strong>t you must markthe column names as a procedural head<strong>in</strong>g. In Doc-to-Help, you cando this by select<strong>in</strong>g each column name and sett<strong>in</strong>g each property to“Head<strong>in</strong>g 4.” The type “Head<strong>in</strong>g 4” sets the font, po<strong>in</strong>t size, and marksthe column name as “procedural” help (see Figure 6).Doc2Help will automatically generate Context IDs for any project.In the project pa<strong>in</strong>ter <strong>of</strong> Doc-to-Help, select “topic types,” then thesub-type “procedural.” At this po<strong>in</strong>t you can select a property called“AutoContextID” and set this value to “True” (see Figure 7). This forcesthe Doc-to-Help Compiler <strong>in</strong> <strong>con</strong>cert with the MS-Help compiler togenerate and <strong>in</strong>corporate “Context ID” numbers <strong>in</strong>to your .HLP or.CHM file. From this po<strong>in</strong>t onward, the easy part can be enjoyed by the<strong>PowerBuilder</strong> developer who only has to use the ShowPopupHelp ( )command to activate this great MS-W<strong>in</strong>dows feedback mechanism.Doc2Help has also generated a reference file for the <strong>PowerBuilder</strong>,VisualBasic, C#, Delphi, etc., programmer as to the topic names andtheir Context IDs, so now we have the direct mapp<strong>in</strong>g to the <strong>in</strong>formationthat we need for the help or bubble help feature we want to use.In the test case above, I used the “Contact” table <strong>in</strong> the sample ASA9.0 database and the columns such as City, Fax, and First Name showup as well as their Context ID numbers (see Figure 8). When cod<strong>in</strong>g aS<strong>in</strong>gleL<strong>in</strong>eEdit, Multil<strong>in</strong>eEdit, DataW<strong>in</strong>dow, or other type <strong>of</strong> <strong>con</strong>trol <strong>in</strong><strong>PowerBuilder</strong>, you are provided with a “Help” event (present s<strong>in</strong>ce<strong>PowerBuilder</strong> version 8.0). The Help event is automatically triggeredwhen the application user has focus on the <strong>con</strong>trol and presses the“shift+F1” key. Also, <strong>in</strong> a response dialog, you use the “ContextHelp”property (set to True) to have the O/S generate a “?” on the w<strong>in</strong>dow’stitle bar. Dragg<strong>in</strong>g the w<strong>in</strong>dow “?” on to any <strong>con</strong>trol also fires the Helpevent dur<strong>in</strong>g the drop operation.For the Help event, use the ShowPopupHelp ( ) command. If I wantedto provide Context help to the command button, for example, called“City,” my Help event would use the code: ShowPopupHelp ("<strong>CON</strong>-TEXT.HLP", THIS, 63) – which would result <strong>in</strong> Figure 9.To make this more reusable, I typically use the “Tag” property orcreate an ancestor class that adds a protected <strong>in</strong>stance variable (suchas il_<strong>con</strong>text_id”) where I can store the Context ID mapp<strong>in</strong>g that I getfrom the help compiler. You would never want to hard-code this valueas it can change as new <strong>in</strong>formation is added to the help file. I wouldeven take this further for pure object-oriented reusability and create aservice that would dynamically read the “mapp<strong>in</strong>g file” and return theContext ID based on a component name.DataW<strong>in</strong>dow ColumnsFor DataW<strong>in</strong>dow columns, the process has to be slightly different aswe have to <strong>con</strong>sider two objects – the DataW<strong>in</strong>dow <strong>con</strong>trol and theDataW<strong>in</strong>dow object – that when comb<strong>in</strong>ed create the “dynamic duo”that all <strong>PowerBuilder</strong> developers have come to know and love (evenVisual Studio developers now with DataW<strong>in</strong>dow.NET). When the Helpevent is fired, the operat<strong>in</strong>g <strong>sys</strong>tem message is actually sent to theDataW<strong>in</strong>dow <strong>con</strong>trol but it only <strong>con</strong>ta<strong>in</strong>s the X and Y position <strong>of</strong> theContext Help request. What the developer needs to do at this po<strong>in</strong>t isdeterm<strong>in</strong>e the column name. Luckily, we can use the “GetColumn-Name” method to return the column, which has focus <strong>in</strong> the DataW<strong>in</strong>dowobject. Once we have that <strong>in</strong>formation, you could use the technique<strong>of</strong> stor<strong>in</strong>g the Context ID <strong>in</strong> the “tag” property.Once you have the column name and its Context ID, the ShowPopupHelp( ) method should do nicely here. However, the DataW<strong>in</strong>dow<strong>con</strong>trol does not activate the “Help” event and we need to acquire the<strong>in</strong>formation about the column that has focus (which is an object <strong>in</strong>sidethe DataW<strong>in</strong>dow object, which is <strong>in</strong>side the DataW<strong>in</strong>dow Control, i.e.,nested scenario). Remember, the GUI standard for request<strong>in</strong>g Help isShift+F1, but if you try this on the DataW<strong>in</strong>dow Control, the Help eventwill not fire. This seems to have been an oversight <strong>in</strong> <strong>PowerBuilder</strong>s<strong>in</strong>ce release 8.0.We can easily simulate the Help request though by add<strong>in</strong>g a userevent to the DataW<strong>in</strong>dow <strong>con</strong>trol. In this case, we need to map a newuser event to the “pbm_dwkey” Event ID. This will allow you to receivenotifications from the keyboard. Once this event is mapped, we can18PBDJ volume12 issue11www.<strong>SYS</strong>-<strong>CON</strong>.COM/pbdj/


use the KeyDown ( ) method <strong>in</strong> <strong>PowerBuilder</strong> to determ<strong>in</strong>e the exactkeys pressed. Once we have determ<strong>in</strong>ed that <strong>con</strong>text help is required,we can easily fire the real Help event. The code for the “key” user eventon the DataW<strong>in</strong>dow Control should be:IF KeyDown ( KeyShift!) = TRUE THENIF KeyDown ( KeyF1!) = TRUE THENTHIS.POST Event Help (0,0)END IFEND IFAs you can see from the above code, the real Help Event is activatedon a Shift+F1. S<strong>in</strong>ce we don’t know the object that has focus, you canpass the value “0,0” as the arguments.In the real DataW<strong>in</strong>dow <strong>con</strong>trol’s Help event, we can use the “0,0”arguments to determ<strong>in</strong>e that the “Key” User Event has probably beenthe trigger <strong>of</strong> how we arrived here <strong>in</strong> this code segment. The next stepwould be to get the column name and then its tag property where youmay have stored the Context ID. The code for the DataW<strong>in</strong>dow Helpevent might be as follows:Str<strong>in</strong>gls_objectLong ll_idls_object = THIS.GetColumnname ( )ll_id = Long (THIS.Describe(ls_object +".Tag"))ShowPopUpHelp ("<strong>CON</strong>TEXT.hlp", THIS, ll_id )In the above code segment, the DataW<strong>in</strong>dow <strong>con</strong>trol <strong>in</strong>terrogatesthe DataW<strong>in</strong>dow object for the column name that the user is focusedon. Once it has the name, you can use the Describe ( ) method toacquire the “tag” property sett<strong>in</strong>g. Convert<strong>in</strong>g the Tag property to aContext ID number to forward <strong>in</strong>to the ShowPopUpHelp ( ) methodcompletes the requirements and the real columns’ <strong>con</strong>text help shouldPocketPCGett<strong>in</strong>g back to the orig<strong>in</strong>al PocketBuilder <strong>con</strong>text-sensitive helpissue I started describ<strong>in</strong>g at the beg<strong>in</strong>n<strong>in</strong>g <strong>of</strong> this article – s<strong>in</strong>ce we cannotuse the nice features from the <strong>PowerBuilder</strong> world that I outl<strong>in</strong>edearlier <strong>in</strong> this article, how could I implement a robust feedback mechanismto the Pocket PC user? One <strong>of</strong> my first thoughts was to extend myS<strong>of</strong>tware Tool & Die Inc. (STD) Foundation Classes (FC) to emulate astandard MicroHelp bar on an MDI type <strong>of</strong> w<strong>in</strong>dow class. As it turnsout, the “Controller” w<strong>in</strong>dow class <strong>in</strong> the <strong>sys</strong>tem STD framework isemulat<strong>in</strong>g an MDI behavior. All I would have to do is extend its featuresto <strong>in</strong>clude such a feature.In the real old days <strong>of</strong> <strong>PowerBuilder</strong> (i.e., releases 1 and 2), we didnot have an MDI w<strong>in</strong>dow as the version <strong>of</strong> MS W<strong>in</strong>dows that Power-Builder supported at that time did not yet have the MDI feature. So creativedevelopers used User Objects to design such an object class andallow this to be used, like an early version <strong>of</strong> the MDI MicroHelp bar. Idecided that the STD FCs could easily implement this feature and createda “vc_status_bar” object class. This object has one public method(<strong>of</strong>_Set_StatusBar) that allows external rout<strong>in</strong>es to send the object themessage text to be displayed (see Figure 11). The user object is alsoattached to the “abstract” level MDI Controller w<strong>in</strong>dow class (wn_Controller_Master).The Base class w<strong>in</strong>dow was enhanced to <strong>in</strong>clude an“<strong>of</strong>_Set_StatusBar” method, which allows the redirection <strong>of</strong> the displaytext to the user object. In the Controller w<strong>in</strong>dow class, this function isextended to work with the user object. In all other w<strong>in</strong>dows classes, themethod ignores the request, as the Status Bar user object is not present.The latest version <strong>of</strong> the STD FCs for PocketBuilder 2.0.3 <strong>in</strong>cludesthe retr<strong>of</strong>it described above. Also, the sample Order Entry applicationfor version 2.0.3 <strong>of</strong> PocketBuilder now <strong>in</strong>cludes the demonstration <strong>of</strong>the use <strong>of</strong> the MicroHelp feature (see Figure 12). The FCs and sampleapplication have been uploaded to Sybase’s CodeXchange Web site. Inthe sample Order Entry application, the Controller dialog allows theuser to access functionality from the command buttons with<strong>in</strong> aDataW<strong>in</strong>dow. The DataW<strong>in</strong>dow command buttons have <strong>con</strong>text-sensitivehelp attached to their “tag” property. To display this <strong>in</strong>formation atruntime, code was placed on the “ButtonClick<strong>in</strong>g” event <strong>of</strong> theDataW<strong>in</strong>dow <strong>con</strong>trol. What is nice about this event is that a po<strong>in</strong>ter tothe current <strong>con</strong>trol object is passed to the PowerScript code (namedDWO), which allows the developer to <strong>in</strong>trospect the subord<strong>in</strong>ate object’sproperties. Add<strong>in</strong>g the <strong>in</strong>clusional polymorphic function, the <strong>con</strong>text<strong>in</strong>formation can be easily displayed with a simple statement such as:THIS.<strong>of</strong>_set_statusBar (DWO.Tag).FIGURE 10 |FIGURE 11 |FIGURE 12 |appear (see Figure 10). To make this design even more dynamically<strong>con</strong>figurable, I would suggest writ<strong>in</strong>g a <strong>PowerBuilder</strong> utility programthat reads the Context Map from the latest help file build – load<strong>in</strong>g this<strong>in</strong>formation <strong>in</strong>to a database table. Then, the Context ID can be ascerta<strong>in</strong>edby read<strong>in</strong>g the database table at runtime. That way, if yourebuild the help file and resequence all the Context IDs, you can simplyreload the database table with the current mapp<strong>in</strong>g <strong>in</strong>formation. Thiswill avoid a lot <strong>of</strong> work updat<strong>in</strong>g all the column “tag” properties,recompil<strong>in</strong>g, and redistribut<strong>in</strong>g the application and help file(s).Bubble Help (PowerTipText)This feature would be great for <strong>con</strong>text-sensitive help but neitherthe ShowPopUpHelp ( ) method or the PowerTipText feature is supportedby the Pocket PC operat<strong>in</strong>g <strong>sys</strong>tem (and hence PocketBuilder).To <strong>of</strong>fset this deficiency, I thought about the notification bubble feature<strong>of</strong> the Pocket PC. The more I thought about it, the more I realized thatthis was an excellent vehicle to deliver <strong>con</strong>text-sensitive help as thefeature uses dynamic space, is always over top <strong>of</strong> the active w<strong>in</strong>dow,and can be programmed to accept different responses. S<strong>in</strong>ce Pocket-Builder 2.0 the STD FCs have been upgraded to deliver this featureus<strong>in</strong>g the “<strong>of</strong>_set_nb_message” method <strong>of</strong> the base w<strong>in</strong>dow class.The ancestor code <strong>of</strong> the “<strong>of</strong>_set_nb_message” method <strong>in</strong>stantiatesa user object class <strong>of</strong> type “ns_notification_bubble_master” that allowscommunication to the Pocket PC operat<strong>in</strong>g <strong>sys</strong>tem for the use <strong>of</strong> thisfeature. One <strong>of</strong> the problems I had encountered <strong>in</strong> the past us<strong>in</strong>g thisfeature was when the issu<strong>in</strong>g w<strong>in</strong>dow did not close the notificationbubble. This left the notification bubble <strong>in</strong> “limbo” and the user wasnot able to remove the notification until the application fully closed. Toget around this problem, the STD FCs were enhanced to always add anOK command button to the notification bubble. By do<strong>in</strong>g so, I foundthat the user could also reactivate the notification bubble at any timeand respond to the “OK.” If the w<strong>in</strong>dow <strong>in</strong>stance that orig<strong>in</strong>ally openedthe notification bubble was closed, the Pocket PC operat<strong>in</strong>g wouldclean up the notification bubble. This was a great discovery.By add<strong>in</strong>g a command button feature though, the notification bub-20 PBDJ volume12 issue11pbdj.<strong>sys</strong>-<strong>con</strong>.com


extended at the base W<strong>in</strong>dow class with an “oe_command” user eventto allow the capture <strong>of</strong> the communicae from the notification bubbleto the issu<strong>in</strong>g w<strong>in</strong>dow <strong>in</strong>stance. This allowed a full communication circlefrom the W<strong>in</strong>dow <strong>in</strong>stance to the notification bubble <strong>in</strong>stance andback aga<strong>in</strong>. If we now couple the automatic population <strong>of</strong> the Tagproperty from the comment text <strong>in</strong> the ASA database with the STD FCs’easy use <strong>of</strong> the notification bubble feature, the <strong>con</strong>text sensitive helpwas an easy reach. The only question was how to <strong>in</strong>itiate the helprequest, as the Pocket PC does not support any function keys or the use<strong>of</strong> the <strong>con</strong>text-help question mark on response dialogs.To help with the <strong>con</strong>text-help <strong>in</strong>itiation, the STD FCs were extendedat the base PopUp menu class level to <strong>in</strong>clude a “Help” menu item.This can be easily activated by the Pocket PC stylus with a “Tap andhold” action. The popup menu understands the <strong>con</strong>trol that <strong>in</strong>stantiatedit and the help menu redirects a “oe_help” user event back to the<strong>con</strong>trol. The GUI <strong>con</strong>trol <strong>in</strong> turn can extract the <strong>con</strong>trol’s tag properties(or the DataW<strong>in</strong>dow object’s current column’s tag) and redirect a notificationbubble request to the parent w<strong>in</strong>dow. Ancestor code <strong>in</strong> the basew<strong>in</strong>dow class takes care <strong>of</strong> the notification bubble <strong>in</strong>stantiation andHTML message text wrapp<strong>in</strong>g. In the STD FCs, the only action requiredby the Pocket PC developer to allow this behavior is to set the“ib_help_required” property <strong>of</strong> any <strong>con</strong>trol to TRUE. This makes thehelp menu item appear on the pop-up and the notification bubble<strong>con</strong>text help feature enabled at runtime. The developer can set thisproperty <strong>in</strong> the W<strong>in</strong>dow pa<strong>in</strong>ter or at runtime under script <strong>con</strong>trol. ▼FIGURE 13 |ble is also able to communicate to its issu<strong>in</strong>g w<strong>in</strong>dow class (see Figure13). To accomplish this, the notification bubble sends a “pbm_command”message to the <strong>in</strong>stantiat<strong>in</strong>g w<strong>in</strong>dow class. The STD FCs wereAUTHOR BIOChris Pollach is the president <strong>of</strong> S<strong>of</strong>tware Tool & Die Inc. (a <strong>con</strong>sult<strong>in</strong>g company based <strong>in</strong> Ottawa,Ontario, Canada) and has been us<strong>in</strong>g PB s<strong>in</strong>ce November 1989 (version 0.8). When not develop<strong>in</strong>g <strong>in</strong> PB,Chris enjoys fish<strong>in</strong>g and martial arts.cpollach@travel-net.comPBDJ ADVERTISER INDEXADVERTISER URL PHONE PAGEActive Endpo<strong>in</strong>ts, Inc. www.active-endpo<strong>in</strong>ts.com 203-929-9400 2Amyuni Technologies www.amyuni.com 866-926-9864 21ClearNova www.clearnova.com/th<strong>in</strong>kcap 770-442-8324 19E.crane www.ecrane.com 603-226-4041 36iAnywhere www.ianywhere.com 800-801-2069 35ISSJ www.ISSJournal.com 888-303-5282 27Sybase www.sybase.com/pocketbuilder 877-230-6771 7Sybase www.sybase.com/pbextension 877-230-6771 11Sybase www.sybase.com/powerbuilder 877-230-6771 5, 13Sybase www.sybase.com/dataw<strong>in</strong>dow.net 800-8-SYBASE 9Sybase www.dataw<strong>in</strong>dow.com 800-667-9936 15<strong>SYS</strong>-<strong>CON</strong> repr<strong>in</strong>ts www.<strong>sys</strong>-<strong>con</strong>.com 201-802-3026 17<strong>SYS</strong>-<strong>CON</strong> Website www.<strong>sys</strong>-<strong>con</strong>.com 201-802-3000 25Web Services Edge/Open Source www2.<strong>sys</strong>-<strong>con</strong>.com/events 201-802-3066 23Advertiser is fully responsible for all f<strong>in</strong>ancial liability and terms <strong>of</strong> the <strong>con</strong>tract executedby their agents or agencies who are act<strong>in</strong>g on behalf <strong>of</strong> the advertiser. This <strong>in</strong>dex isprovided as an additional service to our readers. The publisher does not assumeany liability for errors or omissions.22 PBDJ volume12 issue11pbdj.<strong>sys</strong>-<strong>con</strong>.com


TMTMENGAGE AND EXPLORE...The Technologies, Solutions and Applications thatare Driv<strong>in</strong>g Today’s Initiatives and Strategies...CALL FOR PAPERS NOW OPEN!CALL FOR PAPERS NOW OPEN!June 2006 | New York, NYThe Sixth Annual SOA Web Services Edge 2006 East - International Web ServicesConference & Expo, to be held June 2006, announces that its Callfor Papers is now open. Topics <strong>in</strong>clude all aspects <strong>of</strong> Web services andService-Oriented ArchitectureSuggested topics...> Transition<strong>in</strong>g Successfully to SOA> Federated Web services> ebXML> Orchestration> Discovery> The Bus<strong>in</strong>ess Case for SOA> Interop & Standards> Web Services Management> Messag<strong>in</strong>g Buses and SOA> Enterprise Service Buses> SOBAs (Service-Oriented Bus<strong>in</strong>ess Apps)> Deliver<strong>in</strong>g ROI with SOA> Java Web Services> XML Web Services> Security> Pr<strong>of</strong>essional Open Source> Systems Integration> Sarbanes-Oxley> Grid Comput<strong>in</strong>g> Bus<strong>in</strong>ess Process Management> Web Services ChoreographyThe fi rst annual Enterprise Open Source Conference & Expo announces thatits Call for Papers is now open. Topics <strong>in</strong>clude all aspects <strong>of</strong> Open Sourcetechnology. The Enterprise Open Source Conference & Expo is a s<strong>of</strong>twaredevelopment and management <strong>con</strong>ference address<strong>in</strong>g the emerg<strong>in</strong>g technologies,tools and strategies surround<strong>in</strong>g the development <strong>of</strong> open source s<strong>of</strong>tware.We <strong>in</strong>vite you to submit a proposal to present <strong>in</strong> the follow<strong>in</strong>g topics. Casestudies, tools, best practices, development, security, deployment, performance,challenges, application management, strategies and <strong>in</strong>tegration.Suggested topics...June 2006 | New York, NY> Open Source Licenses> Open Source & E-Mail> Databases> ROI Case Studies> Open Source ERP & CRM> Open-Source SIP> Test<strong>in</strong>g> LAMP Technologies> Open Source on the Desktop> Open Source & Sarbanes-Oxley> IP ManagementSubmit Your Topic Today! www2.<strong>sys</strong>-<strong>con</strong>.com/eventsSponsored by*Call for Papers email: jimh@<strong>sys</strong>-<strong>con</strong>.comFor Exhibit and Sponsorship InformationCall 201 802-3066Attention Exhibitors:An Exhibit-Forum will displaylead<strong>in</strong>g Web services andOpenSource products,services, and solutionsProduced by© 2005 WEB SERVICES EDGE. ALL RIGHTS RESERVED


PBNIWRITTEN BYDAVID HUOCall<strong>in</strong>g <strong>PowerBuilder</strong>NVOs <strong>in</strong> C#PBNI answers the callHow can we reuse Power-Builder NVOs <strong>in</strong> .NET applications?Before <strong>PowerBuilder</strong>9.0, the answer was Power-Builder automation or a three-tiersolution.In the latter case that meant host<strong>in</strong>gall the NVOs <strong>in</strong> EAServer as middle-tiercomponents. Beg<strong>in</strong>n<strong>in</strong>g with version 9,<strong>PowerBuilder</strong> <strong>of</strong>fers a new <strong>in</strong>terface to<strong>in</strong>teract with the <strong>PowerBuilder</strong> VM – the<strong>PowerBuilder</strong> Native Interface (PBNI).In this article I will expla<strong>in</strong> how to usePBNI <strong>in</strong> unmanaged C++ code and marshalthe parameters to C# managedcode so that you can <strong>in</strong>voke Power-Builder NVOs from C#.FIGURE 1 |Java-based applications can use JNIto <strong>in</strong>voke <strong>PowerBuilder</strong> via PBNI.• Many <strong>PowerBuilder</strong> built-<strong>in</strong> featurescan be moved to <strong>PowerBuilder</strong> extensionsso that the <strong>PowerBuilder</strong> corecan be very small and the deploymentsize can vary depend<strong>in</strong>g onwhich features the user needs.us<strong>in</strong>g the <strong>PowerBuilder</strong> librarypa<strong>in</strong>ter. Right-click the method <strong>in</strong> theNVO and select “Properties”. The signaturestr<strong>in</strong>g is shown <strong>in</strong> the “Signature”text field (see Figure 2). Anotherway to do it is us<strong>in</strong>g pbsig100.exe,which is a command-l<strong>in</strong>e toolshipped with PBNI SDK:AUTHOR BIODavid Huo works forthe Sybase Waterloo<strong>con</strong>sultant team.Introduc<strong>in</strong>g PBNI (Power-Builder Native Interface)PBNI is a new feature <strong>in</strong>troducedwith <strong>PowerBuilder</strong> 9.0. It is only available<strong>in</strong> the enterprise versions and is<strong>in</strong>stalled under %<strong>PowerBuilder</strong><strong>in</strong>stall%\ SDK\PBNI. You can f<strong>in</strong>d allthe required header files to use PBNIunder the <strong>in</strong>clude directory.PBNI is a standard programm<strong>in</strong>g<strong>in</strong>terface that enables developers toextend the functionality <strong>of</strong> <strong>PowerBuilder</strong>.Us<strong>in</strong>g PBNI, you can create visual andnonvisual extensions to <strong>PowerBuilder</strong>(<strong>in</strong>clud<strong>in</strong>g marshaler extensions) andalso embed the <strong>PowerBuilder</strong> virtualmach<strong>in</strong>e (PBVM) <strong>in</strong>to C++ applications.Compared with <strong>PowerBuilder</strong> automation,PBNI has many advantages:• It is not just reus<strong>in</strong>g exist<strong>in</strong>g NVOs.<strong>PowerBuilder</strong> can be extended us<strong>in</strong>gPBNI to provide capabilities such asXML pars<strong>in</strong>g and Web service <strong>in</strong>tegration.• The solution is not COM-based,therefore no registry sett<strong>in</strong>gs arerequired and it can be deployed tonon-W<strong>in</strong>dows platforms.• More languages can reuse Power-Builder components; for example,How It WorksPBNI provides predef<strong>in</strong>ed C++ <strong>in</strong>terfacesto allow the PBVM <strong>in</strong>teract to withother languages (see Figure 1). Table 1describes some important <strong>in</strong>terfaces.Call<strong>in</strong>g <strong>PowerBuilder</strong> NVOfrom Unmanaged CodeTo <strong>in</strong>voke a <strong>PowerBuilder</strong> NVO us<strong>in</strong>gPBNI, you need to follow these steps:1. Identify the required <strong>PowerBuilder</strong>library files and the method signaturestr<strong>in</strong>g <strong>in</strong> the NVO. This can be donepbsig100 .Here is a sample output <strong>of</strong>pbsig100.exe show<strong>in</strong>g the methods’signature str<strong>in</strong>gs <strong>of</strong> NVO n_automation:PB Object Name: automationPB Object Name: n_automationpublic function str<strong>in</strong>g fn_barcode(str<strong>in</strong>g specimenid, str<strong>in</strong>gInterfaceDescriptionsIPB_VMUsed to load <strong>PowerBuilder</strong> objects <strong>in</strong> third-party applications and<strong>in</strong>teroperate with the <strong>PowerBuilder</strong> virtual mach<strong>in</strong>e (PBVM).IPB_Session <strong>in</strong>terface An abstract <strong>in</strong>terface that def<strong>in</strong>es methods for perform<strong>in</strong>g variousactions such as access<strong>in</strong>g PowerScript data, creat<strong>in</strong>g <strong>PowerBuilder</strong>objects, and call<strong>in</strong>g PowerScript functions.IPB_ValueRepresents a <strong>PowerBuilder</strong> value, which could be one <strong>of</strong> the Power-Builder standard datatypes such as <strong>in</strong>teger, long, str<strong>in</strong>g, and so forth.It provides <strong>in</strong>formation about each variable, <strong>in</strong>clud<strong>in</strong>g its type, nullflag, access privileges, array or simple type, and reference type.IPB_Arguments Represents the arguments passed to a PowerScript function andused to access the data.PBCallInfo (structure) Used to hold data and return type <strong>in</strong>formation for calls betweenextensions and the PBVM.TABLE 1 |24 PBDJ volume12 issue11pbdj.<strong>sys</strong>-<strong>con</strong>.com


2. GetAt obta<strong>in</strong>s the value at a specific<strong>in</strong>dex <strong>of</strong> the pArgs member <strong>of</strong> thePBCallInfo structure. For each argument,GetAt returns a po<strong>in</strong>ter to theIPB_Value <strong>in</strong>terface.FIGURE 2 |specimen_formatted)/* SSS */public subrout<strong>in</strong>e fn_workdraft(str<strong>in</strong>g <strong>con</strong>nstr, str<strong>in</strong>gspecimenid)/* QSS */PBNI uses the NVO’s name, methodname, and the signature str<strong>in</strong>g t<strong>of</strong><strong>in</strong>d the method to call.2. Call LoadLibrary() to load the PBVMDLL. In version 10, the PBVM DLL iscalled pbvm100.dll.3. Use GetProcAddress() to get theaddress <strong>of</strong> the “PB_GetVM” methodand then call the PB_GetVM() methodto get a reference to the PBVM.4. Call CreateSession() to create aIPB_Session <strong>in</strong>stance. You can storethe IPB_Session reference <strong>in</strong> a classmember or a global variable to reusethe session. Because creat<strong>in</strong>g thesession is a heavy process, it shouldbe done only once.5. Call the F<strong>in</strong>dGroup() method <strong>of</strong> theIPB_Session <strong>in</strong>stance to f<strong>in</strong>d theNVO group. The group name shouldbe the same as the NVO’s name.6. Call the F<strong>in</strong>dClass() method <strong>of</strong> theIPB_Session <strong>in</strong>stance with the groupID and class name. The class nameshould be the NVO’s name. You mayfeel <strong>con</strong>fused here; what is the po<strong>in</strong>t<strong>of</strong> the group def<strong>in</strong>ition? It makesmore sense when you try to f<strong>in</strong>d aw<strong>in</strong>dow and <strong>con</strong>trols <strong>in</strong> the pbl. Forexample, <strong>in</strong> a w<strong>in</strong>dow def<strong>in</strong>ition w_1,w_1 is a group, and w_1 and the <strong>con</strong>trols<strong>con</strong>ta<strong>in</strong>ed <strong>in</strong> it are all classes <strong>of</strong>group w_1.7. Call the NewObject() method <strong>of</strong> theIPB_Session <strong>in</strong>stance to create an<strong>in</strong>stance <strong>of</strong> the class returned byF<strong>in</strong>dClass().8. Call the GetMethodID() method <strong>of</strong>the IPB_Session <strong>in</strong>stance to get a reference<strong>of</strong> the method you want tocall. Please make sure to give thecorrect function name and signaturestr<strong>in</strong>g – (see step 1)9. Call the InitCallInfo() method <strong>of</strong> theIPB_Session <strong>in</strong>stance to <strong>in</strong>itialize aPBCallInfo structure.10. Fill <strong>in</strong> the parameters and callInvokeObjectFunction() to <strong>in</strong>vokethe method.11. Retrieve the return value us<strong>in</strong>g thePBCallInfo structure.12. Release the PBCallInfo reference.13. Release the IPB_Session <strong>in</strong>stanceand call FreeLibrary() to unload thePBVM DLL. This step should bedone <strong>in</strong> the destructor <strong>of</strong> the class orat the moment when you are donewith PBNI calls.“PBNI enablesdevelopers toextend thefunctionality <strong>of</strong><strong>PowerBuilder</strong>”It sounds like a lot steps, but it ismuch easier when you see the samplecode <strong>in</strong> List<strong>in</strong>g 1. In the follow<strong>in</strong>g example,the PBNI calls are wrapped <strong>in</strong> a C++class called CPBInvoker. The DLL load<strong>in</strong>gand IPB_Session <strong>in</strong>itialization aredone <strong>in</strong> the <strong>con</strong>structor and the cleanup is done <strong>in</strong> the destructor <strong>of</strong> the class.For the sample, the method we want tocall is <strong>in</strong> an NVO named n_automationand the method name is fn_barcodewith a method signature str<strong>in</strong>g <strong>of</strong> “SSS”,mean<strong>in</strong>g it returns a str<strong>in</strong>g and takestwo str<strong>in</strong>g type parameters.How to Pass ParametersPBCallInfo is the structure to passparameters and the return value <strong>in</strong>/out<strong>of</strong> the method. The structure <strong>con</strong>ta<strong>in</strong>s apo<strong>in</strong>ter pArgs to the IPB_Arguments<strong>in</strong>terface that has two methods:1. GetCount obta<strong>in</strong>s the number <strong>of</strong>arguments <strong>in</strong> a method call.The IPB_Value <strong>in</strong>terface has a correspond<strong>in</strong>gmethod to set the value fordifferent data types, for example, Set-Str<strong>in</strong>g sets the str<strong>in</strong>g value and SetIntsets the <strong>in</strong>t value and so on.It’s a little tricky to get the returnvalue. If the method returns a simpletype, such as <strong>in</strong>t, you can use PBCall-Info returnValue->GetInt() to retrievethe value. If the return value requires amemory block, such as a str<strong>in</strong>g, youmust do this:pbstr<strong>in</strong>g ret = ci.returnValue->GetStr<strong>in</strong>g();// str has the str<strong>in</strong>g value you wantLPCTSTR str = _session->GetStr<strong>in</strong>g(ret) );If you return ci.returnValue->Get-Str<strong>in</strong>g() value directly, you will get awrong value. Unfortunately, the example<strong>in</strong>cluded with the SDK only showshow to return an <strong>in</strong>teger, which is differentthan return<strong>in</strong>g a str<strong>in</strong>g.Please remember all the values aregone after you call FreeCallInfo. If youwant to keep the return value, you needto use a method called AcquireValue <strong>in</strong>the IPB_Session <strong>in</strong>terface to tell PBNI tomake a copy <strong>of</strong> the memory and don’trelease the po<strong>in</strong>ter after FreeCallInfo iscalled. The follow<strong>in</strong>g data types, pluspbarray datatype, require theAcquireValue call to save the po<strong>in</strong>ter.pbvalue_decpbvalue_str<strong>in</strong>gpbvalue_blobpbvalue_datepbvalue_timepbvalue_datetimeThe follow<strong>in</strong>g is an example <strong>of</strong> howto use AcquireValue:// Acquire a value, ci is thePBCallInfo structure, session isIPB_SessionMessageArg = session->AcquireValue( ci->pArgs->GetAt(0) );pbstr<strong>in</strong>g pbMessage = MessageArg->GetStr<strong>in</strong>g() ;Message = (LPSTR)session->GetStr<strong>in</strong>g(pbMessage) ;…session->FreeCallInfo( ci );// the value is still availableafter you call FreeCallInfo26PBDJ volume12 issue11pbdj.<strong>sys</strong>-<strong>con</strong>.com


Cleanup phase, don’t forgetrelease the value// when is not needed any moreif (MessageArg) {session->ReleaseValue( MessageArg ) ;}Call<strong>in</strong>g the <strong>PowerBuilder</strong> NVOfrom .NET Managed CodeNow we know how to call PBNI <strong>in</strong>C++ unmanaged code. The next step isto export the methods from the C++DLL and declare proper C# prototypesto make it available for C#. The__declspec(dllexport) modifier tells thecompiler to make the function visible(export) to other applications, so thatother applications can call this method.List<strong>in</strong>g 2 exports the PBInvoker class asDLL functions.Note: To check if the methods areproperly exported, you can use dumpb<strong>in</strong>.exeto see if the function names are<strong>in</strong> the list; here is an example <strong>of</strong> theoutput <strong>of</strong> dumpb<strong>in</strong>.exe show<strong>in</strong>g theexported symbols:dumpb<strong>in</strong> /exports PBInvoker.dll1 0 000115B4 _PBX_GetVersion@02 1 0001162C barcode4 3 000115FF closePBSession5 4 000116BD <strong>in</strong>itPBSessionParameter Marshal<strong>in</strong>g from.NET to Unmanaged CodeThe .NET Framework uses managedcode, which is an <strong>in</strong>terpreted <strong>in</strong>structionset, similar to Java bytecode or<strong>PowerBuilder</strong> P-Code. The C++ DLL usesunmanaged code, which is mach<strong>in</strong>ecode. This <strong>in</strong>troduces an issue becausethe data types <strong>in</strong> the .NET Frameworkneed to be marshaled (mean<strong>in</strong>g <strong>con</strong>vertbetween the C/C++ data type formatand the .NET data type format) to passback and forth between managed andunmanaged code. C# provides themeans to do this job.In this example, we need to callthree C++ DLL methods <strong>in</strong> C#:void <strong>in</strong>itPBSession(LPCTSTR libList[],<strong>in</strong>t libNum, LPCTSTR appName);void closePBSession();void barcode(LPCTSTR specimen_formatted, LPCTSTR spcimen_id,char *code);First, we need to tell C# that thesethree methods are from an unmanagedDLL. This is done by us<strong>in</strong>g the[DllImport] attribute tag <strong>in</strong> the functionprototype <strong>in</strong> C#. Also don’t forget to use“PBNI <strong>of</strong>fers a goodsolution to reuse<strong>PowerBuilder</strong>components <strong>in</strong> the.NET Framework”the “extern” keyword, mean<strong>in</strong>g thefunction exists outside the C# module:// pb<strong>in</strong>voker.dll is the DLL file name[DllImport("pb<strong>in</strong>voker.dll",CharSet=CharSet.Auto)]public static extern void closePBSession();Se<strong>con</strong>d, we need to use the proper[MarshalAs] attribute options to def<strong>in</strong>ethe marshal behaviors for LPCSTR[],<strong>in</strong>t, LPCSTR, and char* unmanaged C++parameters. The follow<strong>in</strong>g code showshow to def<strong>in</strong>e the marshal behaviors forthose three DLL methods:[DllImport("pb<strong>in</strong>voker.dll",CharSet=CharSet.Auto)]public static extern void<strong>in</strong>itPBSession([MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)]str<strong>in</strong>g[]libList,<strong>in</strong>t libNum,[MarshalAs(UnmanagedType.LPStr)]str<strong>in</strong>g appName);[DllImport("pb<strong>in</strong>voker.dll",CharSet=CharSet.Auto)]public static extern void closePBSession();[DllImport("pb<strong>in</strong>voker.dll",CharSet=CharSet.Auto)]public static extern void barcode([MarshalAs(UnmanagedType.LPStr)]str<strong>in</strong>gspecimen_formatted,[MarshalAs(UnmanagedType.LPStr)]str<strong>in</strong>gspcimen_id,// Use C# Str<strong>in</strong>gBuilder for outputstr<strong>in</strong>g buffer[MarshalAs(UnmanagedType.LPStr)]Str<strong>in</strong>gBuilder code);There are some <strong>in</strong>terest<strong>in</strong>g th<strong>in</strong>gs Ineed to po<strong>in</strong>t out:1. [MarshalAs(UnmanagedType.LPArray,ArraySubType=Unmanaged-Type.LPStr)] is the way to marshalLPCTSTR[]. It tells C# the array typeand element type <strong>in</strong> C++, which is apo<strong>in</strong>ter array and a C str<strong>in</strong>g po<strong>in</strong>ter<strong>in</strong> each element <strong>in</strong> our case.2. [MarshalAs(UnmanagedType.LPStr)]Str<strong>in</strong>gBuilder is the way to marshalan output str<strong>in</strong>g buffer. The Str<strong>in</strong>g-Builder should have enough space tohold the return value from the DLLmethod; you can allocate the spacefor the Str<strong>in</strong>gBuilder and then call theDLL method <strong>in</strong> C#.Here is the C# code to <strong>in</strong>voke theDLL methods:// allocate buffer for the outputstr<strong>in</strong>gStr<strong>in</strong>gBuilder buf = new Str<strong>in</strong>g-Builder(256);// Init PBInvoker, automation is the<strong>PowerBuilder</strong> application object name<strong>in</strong>itPBSession(new Str<strong>in</strong>g[] {"automation.pbl"},1, "automation");// Call the methodbarcode("C05-10", "tpro402137", buf);Console.Out.WriteL<strong>in</strong>e("sb = {0}", buf);// Clean upclosePBSession();Creat<strong>in</strong>g a Generic<strong>PowerBuilder</strong> Invoker for C#We have discussed some basic techniquesfor us<strong>in</strong>g <strong>PowerBuilder</strong> NVOs <strong>in</strong>C#. One <strong>in</strong>terest<strong>in</strong>g idea is to create atool to generate both the C++ proxyDLL and C# prototypes based on theselected NVOs and methods. To generatethese proxy files, all we need is a list<strong>of</strong> NVOs <strong>in</strong> the PBL and prototypes <strong>of</strong>each method. Fortunately, pbsig100.exedoes it for us. We can parse the output<strong>of</strong> pbsig100.exe to retrieve the metadata<strong>of</strong> any PBL file. The rest <strong>of</strong> the work is togenerate the source code based on theprototypes, which is fairly easy to do. I’llcover the details <strong>of</strong> the code generation<strong>in</strong> a follow-up article.ConclusionPBNI is a great <strong>in</strong>novation <strong>in</strong> Power-Builder. It opens a brand new space fordevelopers to reuse and extend Power-Builder. PBNI <strong>of</strong>fers a good solution toreuse <strong>PowerBuilder</strong> components <strong>in</strong> the.NET Framework.To f<strong>in</strong>d more <strong>in</strong>formation aboutPBNI, please reference the PBNI SDKdocument and CodeXchange for examples.▼david.huo@sybase.com28 PBDJ volume12 issue11pbdj.<strong>sys</strong>-<strong>con</strong>.com


List<strong>in</strong>g 1// Def<strong>in</strong>e the function po<strong>in</strong>ter for PB_GetVMtypedef PBXEXPORT PBXRESULT (*P_PB_GetVM)(IPB_VM** vm);// <strong>con</strong>structorCPBInvoker::CPBInvoker(LPCTSTR LibList[], <strong>in</strong>t libNum, LPCT-STR appName){_h<strong>in</strong>st = NULL; // a member variable to hold the DLL handleIPB_VM* pbvm;_h<strong>in</strong>st = LoadLibrary("pbvm100.dll"); // step2: load PBVMif ( _h<strong>in</strong>st == NULL ) {throw "Loaded PBVM successfully";}// step 3: Get PBVM referenceP_PB_GetVM getvm =(P_PB_GetVM)GetProcAddress(_h<strong>in</strong>st,"PB_GetVM");if (getvm == NULL) {throw "PB_GetVM failed";}getvm(&pbvm);if (pbvm == NULL) {throw "getvm failed";}// step 4: Create IPB_Session <strong>in</strong>stance, LibList is anarray holds the pbl file namesif ( pbvm->CreateSession(appName, LibList, libNum, &_session)!= PBX_OK ) {throw "Error <strong>in</strong> CreateSession";}}// destructorCPBInvoker::~CPBInvoker(){// step 13: Release IPB_Sessionif( NULL != _session ) {_session->Release();}// unload PBVM DLLif( NULL != _h<strong>in</strong>st ) {FreeLibrary(_h<strong>in</strong>st);}}// Call the NVO methodvoid CPBInvoker::barcode(LPCTSTR text, LPCTSTR format,char* code){// step 5: F<strong>in</strong>d the group, n_automation is the NVO’snamepbgroup group = _session->F<strong>in</strong>dGroup("n_automation",pbgroup_userobject);if (group == NULL) throw "n_automation is not found!";// step 6: F<strong>in</strong>d the class, n_automation is the NVO’snamepbclass cls = _session->F<strong>in</strong>dClass(group,"n_automation");if (cls == NULL) throw "n_automation class notfound!";objectpbobject pbobj = _session->NewObject(cls);// PBCallInfo <strong>con</strong>ta<strong>in</strong>s arguments and return valuePBCallInfo ci;// step 8: GetMethodID to get the method. “SSS” is thesignature str<strong>in</strong>g, fn_barcode is// the function namepbmethodID mid = _session->GetMethodID(cls, "fn_barcode",PBRT_FUNCTION, "SSS");// step 9: Initialize call <strong>in</strong>fo structure based onmethod ID_session->InitCallInfo(cls, mid, &ci);// step 10: Fill <strong>in</strong> parameters.ci.pArgs-> GetAt(0)->SetStr<strong>in</strong>g(text);ci.pArgs-> GetAt(1)->SetStr<strong>in</strong>g(format);// step 11: <strong>in</strong>voke the method_session->InvokeObjectFunction(pbobj, mid, &ci);// step 12: Retrieve the return value, code is a validmemory// buffer passed <strong>in</strong> by the callerpbstr<strong>in</strong>g ret = ci.returnValue->GetStr<strong>in</strong>g();strcpy( code, _session->GetStr<strong>in</strong>g(ret) );}// step 13: Release the PBCallInfo structure_session->FreeCallInfo( &ci );List<strong>in</strong>g 2#def<strong>in</strong>e PBINVOKER_API __declspec(dllexport)PBINVOKER_API void barcode(LPCTSTR specimen_formatted,LPCTSTR spcimen_id, char *code){// _<strong>in</strong>voker is a global variable holds the reference <strong>of</strong>the PBInvoker objectif( NULL != _<strong>in</strong>voker ) {// call the NVO method_<strong>in</strong>voker->barcode(specimen_formatted, spcimen_id, code);}}PBINVOKER_API void <strong>in</strong>itPBSession(LPCTSTR libList[], <strong>in</strong>tlibNum, LPCTSTR appName){// <strong>in</strong>it the IPB_Sessionif( NULL == _<strong>in</strong>voker ) {// <strong>in</strong>stantiate the CPBInvoker wrapper class_<strong>in</strong>voker = new CPBInvoker(libList, libNum, appName);}}PBINVOKER_API void closePBSession(){// clean upif( NULL != _<strong>in</strong>voker ) {// delete the wrapper objectdelete _<strong>in</strong>voker;_<strong>in</strong>voker = NULL;}}// step 7: Create an <strong>in</strong>stance <strong>of</strong> the <strong>PowerBuilder</strong>pbdj.<strong>sys</strong>-<strong>con</strong>.comPBDJ volume12 issue1129


TECHNIQUESWRITTEN BYDOUG PORTERWork<strong>in</strong>g with Web Services<strong>in</strong> <strong>PowerBuilder</strong>An <strong>in</strong>troductionAUTHOR BIODoug Porter is a s<strong>of</strong>twaredeveloper withDailyAccess Corporation.He is a Sun CertifiedJava Programmerand Certified Power-Builder Pr<strong>of</strong>essional andwas a speaker at Tech-Wave 2004. He holds aBA <strong>in</strong> Spanish and anMS <strong>in</strong> CIS from the University<strong>of</strong> South Alabamawhere he has alsoworked as an adjunct<strong>in</strong>structor. Doug worksextensively withEAServer, <strong>PowerBuilder</strong>,and Java develop<strong>in</strong>gclient/server and Webapplications for thef<strong>in</strong>ancial <strong>in</strong>dustry.Unless you have been hid<strong>in</strong>g <strong>in</strong>a cave for the past couple <strong>of</strong>years, you are probably wellaware <strong>of</strong> the buzz surround<strong>in</strong>gservice-oriented architecture(SOA). This <strong>con</strong>cept <strong>of</strong> <strong>in</strong>teractionamong loosely coupled collections <strong>of</strong>components is <strong>of</strong>ten implementedthrough a series <strong>of</strong> services accessibleover HTTP that processes requests andresponses (Web services). As a Power-Builder developer you may be wonder<strong>in</strong>ghow you can jo<strong>in</strong> the SOA partywhile still leverag<strong>in</strong>g your exist<strong>in</strong>gskills. This article will walk youthrough three techniques available tothe <strong>PowerBuilder</strong> developer (even ifyou may not be on a currently supportedversion).Access<strong>in</strong>g a Web service is very similarto visit<strong>in</strong>g a Web page <strong>con</strong>ta<strong>in</strong><strong>in</strong>gparameters <strong>in</strong> the URL or submitt<strong>in</strong>g aform on a Web page. An HTTP requestgets sent to a URL via an HTTP GET orPOST along with a set <strong>of</strong> arguments <strong>in</strong>the form <strong>of</strong> name/value pairs. In Power-Builder there are three options availablefor perform<strong>in</strong>g this type <strong>of</strong> operation:the GetURL/PostURL functions, us<strong>in</strong>gMicros<strong>of</strong>t’s XmlHttp object via OLE, andus<strong>in</strong>g the Web Service Proxy object.FIGURE 1 | FIGURE 2 |Demonstration Application toCall Amazon.com Web ServicesIn this article we will create a demonstrationapplication that <strong>in</strong>teracts withthe Amazon.com E-Commerce WebService (http://aws.amazon.com). Ourapplication will use this service tosearch through one <strong>of</strong> their product<strong>in</strong>dexes for items match<strong>in</strong>g our searchcriteria. To use the Amazon.com Webservice you will need to sign up for anaccess key through their site. The codesamples will show where your keyshould be placed with the <strong>in</strong>dicator“[YourAccessKey]”.By look<strong>in</strong>g at the documentation forthe Amazon E-commerce Web service,we can see that to perform an itemsearch operation a m<strong>in</strong>imal set <strong>of</strong> argumentsis required. There are many additionalarguments that may be used whenperform<strong>in</strong>g searches, but we will beus<strong>in</strong>g the subset listed below. (Browsethe Amazon.com Web service documentationto see the full range <strong>of</strong> searcharguments and operations available.)• Web Service URL: http://webservices.amazon.com/onca/xml• Service: Name <strong>of</strong> the service be<strong>in</strong>gused; should be AWSECommerceService• AWSAccessKeyID: [YourAccessKey]• Operation: Operation to be performed(ItemSearch <strong>in</strong> our case)• Keywords: Word or phrase to searchfor• SearchIndex: One <strong>of</strong> Amazon.com’ssearch <strong>in</strong>dexes (Music, Books, etc.)Responses from this Amazon Webservice will be returned as structuredXML that can then be parsed and displayed.A demonstration <strong>of</strong> the variousmethods available for pars<strong>in</strong>g XML <strong>in</strong><strong>PowerBuilder</strong> will be covered <strong>in</strong> a laterarticle.Before we can send requests, wemust decide what to search for. I’m ahuge music fan, so for this example wewill use the “Music” SearchIndex andfor our Keywords argument we willsearch for <strong>in</strong>formation on one <strong>of</strong> myfavorite musicians, the great “ButchWalker” (an Atlanta musician formerlywith the Marvelous 3).GetURL/PostURLThe oldest methods for pull<strong>in</strong>g dataover HTTP <strong>in</strong> <strong>PowerBuilder</strong> (s<strong>in</strong>ce version6.5) are the GetURL and PostURLfunctions. These functions allow you tosend an HTTP GET or POST request30 PBDJ volume12 issue11pbdj.<strong>sys</strong>-<strong>con</strong>.com


from with<strong>in</strong> PowerScript and capturethe result<strong>in</strong>g response.When pass<strong>in</strong>g arguments to a URLvia an HTTP GET, the URL is generated<strong>in</strong> the format:BaseURL?=&=&...The full URL for an HTTP GET to ourAmazon Web services with our selectedparameters would be as follows:http://webservices.amazon.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyID=[YourAccessKey]&Operation=ItemSearch&SearchIndex=Music&Keywords=Butch WalkerThe result<strong>in</strong>g response would beXML <strong>con</strong>ta<strong>in</strong><strong>in</strong>g a list <strong>of</strong> items match<strong>in</strong>gour search (see Figure 1).Now that we know what our requestshould look like, we can beg<strong>in</strong> to writecode to call the Web service. Both theGetURL and PostURL functionsrequire that you first create a standardclass <strong>of</strong> the type InternetResult to captureand process the Web serviceresponse via the InternetData(blob)function. Once we have created thisclass, we will override the InternetData(blob)function with code to processthe response. For demonstration purposes,a simple MessageBox will do fornow, but we could write the data out toa file or parse it for display <strong>in</strong> aSOAP vs RESTSOAP: A well-def<strong>in</strong>ed protocol forexchang<strong>in</strong>g XML-based messages over anetwork usually via HTTP. Oftentimes it’sused <strong>in</strong> an RPC (Remote Procedure Call)messag<strong>in</strong>g pattern.REST: In the <strong>con</strong>text <strong>of</strong> Web services,describes loosely structured requests overHTTP with no set standard def<strong>in</strong><strong>in</strong>g thestructure <strong>of</strong> requests or responses fromthe service.DifferencesAccess<strong>in</strong>g a REST-style Web service<strong>in</strong>volves pass<strong>in</strong>g multiple arguments <strong>in</strong>the form <strong>of</strong> name/value pairs via a GETor POST request. These arguments provideall <strong>of</strong> the <strong>in</strong>com<strong>in</strong>g parameters theWeb service may need to create aresponse (which may or may not beXML). In <strong>con</strong>trast, a SOAP-style Web serviceaccepts a s<strong>in</strong>gle <strong>in</strong>com<strong>in</strong>g argumentthat <strong>con</strong>sists <strong>of</strong> well-formed XML. ThisXML argument holds all <strong>of</strong> the necessaryparameters the Web services requires tocreate a response (which is then returnedas well-formed XML).pbdj.<strong>sys</strong>-<strong>con</strong>.comGetURL/PostURL MS XmlHttp Web Service ProxyM<strong>in</strong>imum PB Version 6.5 6.5 9Supports HTTPS No Yes YesREST Requests Yes Yes NoSOAP Requests Yes Yes YesXML Pars<strong>in</strong>g Standard Str<strong>in</strong>g MS XmlDom PBDom orPars<strong>in</strong>g object DataW<strong>in</strong>dowManually Create Request Yes Yes NoTABLE 1 |DataW<strong>in</strong>dow. The follow<strong>in</strong>g code snippetshould be added to the functionInternetData(blob) <strong>in</strong> the InternetResultobject:MessageBox(“Response”, &Str<strong>in</strong>g(data))Return 1The code <strong>in</strong> List<strong>in</strong>g 1 demonstrates acall to the service with GetURL (seeList<strong>in</strong>g 1). Note that to call theGetURL/PostURL functions, you mustuse GetContextService to get a servicereference to the Internet service.Execut<strong>in</strong>g the snippet should generatea MessageBox filled with our XMLresponse from the Amazon Web service.Perform<strong>in</strong>g the same operation with aPostURL is almost identical; we just haveto set a couple <strong>of</strong> extra parameters (<strong>con</strong>tentheaders and port) (see List<strong>in</strong>g 2).While this approach works well forstandard HTTP requests, theGetURL/PostURL functions do notallow communication over HTTPS. Toachieve secure communication with theWeb service, we must move on to one <strong>of</strong>our other two methods.Micros<strong>of</strong>t XmlHttp ObjectUs<strong>in</strong>g OLEUs<strong>in</strong>g <strong>PowerBuilder</strong>’s OLE capabilities,we can take advantage <strong>of</strong>Micros<strong>of</strong>t’s XmlHttp object to sendrequests to a Web service. The code touse this object is very similar to whatwe have seen for GetURL/PostURL. TheXmlHttp object can send requests viaHTTP GET and POST but adds the benefit<strong>of</strong> be<strong>in</strong>g able to also send requestsover HTTPS. Before you may use thisobject, you must download and <strong>in</strong>stallthe MSXML package from Micros<strong>of</strong>t’sWeb site (this example uses version 4.0<strong>of</strong> the package). One nice added bonus<strong>in</strong>cluded with this package is an XMLparser (handy if you don’t happen to beon a version <strong>of</strong> <strong>PowerBuilder</strong> that canparse XML) (see List<strong>in</strong>g 3).Web Service Proxy ObjectLast but not least is the Web ServiceProxy Object. This object is available tothose who are us<strong>in</strong>g <strong>PowerBuilder</strong> version9 and above. This object exam<strong>in</strong>esa Web service’s WSDL (Web ServiceDescription Language) file to determ<strong>in</strong>eall <strong>of</strong> the services available that may berequested. We will step through the WebService Proxy Wizard to create a proxyobject for our Amazon Web Service. Wecan then deploy this object, which willgenerate a set <strong>of</strong> objects, methods, andstructures we can use to call our Webservice and capture the response(because <strong>of</strong> recent changes <strong>in</strong> the AmazonWSDL file, <strong>PowerBuilder</strong> 9.0.3 Build8565 or above is required to generate aproxy us<strong>in</strong>g the wizard). The Web ServiceProxy uses SOAP-style requests to<strong>in</strong>teract with our Web service. The othertwo methods shown used REST-stylerequests (for more <strong>in</strong>formation see thesidebar SOAP vs REST).To create a Web Service Proxy Object,proceed through the follow<strong>in</strong>g steps:1. Click New object and select the WebService Proxy Wizard from the Projecttab (see Figure 2).2. Click Next and select a WSDL File.Enter the URL to the Amazon WSDLfile: http://webservices.amazon.com/AWSECommerceService/2005-10-05/AWSECommerceService.wsdl.3. Click Next and select the available servicesexposed through the WSDL file.4. Click Next and select an availableport for the Web service.5. Click Next and, if you like, enter aprefix for the proxy name.FIGURE 3 |PBDJ volume12 issue1131


SOA != Web ServicesSOA (Service-Oriented Architecture):An architectural <strong>con</strong>cept <strong>in</strong>volv<strong>in</strong>g thecreation <strong>of</strong> loosely coupled servicesaccessible over a network <strong>in</strong> a standardizedfashion. Normally the <strong>con</strong>sumption<strong>of</strong> a service is not restricted to a specificlanguage or platform.Web Service: A service made accessiblevia the Internet or an <strong>in</strong>tranet. It typicallyuses HTTP as the transport protocolwith requests to and responses from theservice implemented us<strong>in</strong>g SOAP messagesor a REST approach.ComparisonA service-oriented architecture may beimplemented us<strong>in</strong>g Web services as themethod <strong>of</strong> expos<strong>in</strong>g and access<strong>in</strong>g theservices, but this is not the only way toachieve SOA. Other possible implementationscould <strong>in</strong>volve messag<strong>in</strong>g <strong>sys</strong>tems(JMS: Java Messag<strong>in</strong>g Service), CORBAcommunicat<strong>in</strong>g over IIOP, or any othermessag<strong>in</strong>g protocol (STOMP: Stream<strong>in</strong>gText Orientated Messag<strong>in</strong>g Protocol,XMPP: Extensible Messag<strong>in</strong>g and PresenceProtocol).6. Click Next and select a library andname for the proxy object. Click Nextand <strong>con</strong>firm the proxy sett<strong>in</strong>gs andclick F<strong>in</strong>ish (see Figure 3).Now you should have a proxy objectpresent <strong>in</strong> your library that can bedeployed to create all <strong>of</strong> the objectsneeded to access the Amazon Web service.To use the new objects, you willneed to create a SoapClient <strong>con</strong>nection(to use the SoapClient object you willneed to add either pbsoapclient90.pbd(<strong>PowerBuilder</strong> 9) or pbsoapclient100.pbd(<strong>PowerBuilder</strong> 10) to your library list).If you exam<strong>in</strong>e the awseCommerce-ServicePort object, you will see it has anItemSearch function that takes variousarguments. We can call this function tosend a request to our Web service andcapture the response.This is very similar to how you wouldmake a call to a remote object us<strong>in</strong>gCORBA from with<strong>in</strong> <strong>PowerBuilder</strong> (seeList<strong>in</strong>g 4).ComparisonWe have covered three techniques formak<strong>in</strong>g requests aga<strong>in</strong>st a Web service.There are various pros and <strong>con</strong>s for themethods demonstrated. Table 1 summarizesthe differences among theseoptions.ConclusionThe three methods presented heredemonstrate the options available to the<strong>PowerBuilder</strong> developer with regard toWeb services <strong>in</strong> the new SOA paradigm(for more <strong>in</strong>formation on SOA and Webservices, see the sidebar SOA != Web Services).Those <strong>of</strong> you on older versionscan use the GetURL/PostURL functionsand the XmlHttp object, while the developerson supported versions can takeadvantage <strong>of</strong> the new Web Service Proxyobject. The Web Service Proxy does afantastic job <strong>of</strong> abstract<strong>in</strong>g away Webservices to the level <strong>of</strong> distributedmethod calls. This alone is worth theprice <strong>of</strong> an upgrade if you are go<strong>in</strong>g to bework<strong>in</strong>g frequently with Web services.Remember, sh<strong>in</strong>y new <strong>PowerBuilder</strong> CDsare the gift that keeps on giv<strong>in</strong>g.Resources• SOA: http://en.wikipedia.org/wiki/Service-oriented_architecture• Web Service: http://en.wikipedia.org/wiki/Web_service• REST: http://en.wikipedia.org/wiki/REST• SOAP: http://en.wikipedia.org/wiki/SOAP• Amazon Web Services:http://aws.amazon.com• Micros<strong>of</strong>t MSXML Download:http://www.micros<strong>of</strong>t.com/downloads/details.aspx?familyid=3144b72b-b4f2-46da-b4b6-c5d7485f2b42&displaylang=en#filelist ▼dhp@acm.orgList<strong>in</strong>g 1nvo_<strong>in</strong>ternet_result lnvo_<strong>in</strong>ternet_result<strong>in</strong>et l<strong>in</strong>et_base<strong>in</strong>teger li_retvalStr<strong>in</strong>g ls_url, ls_args//Initialize InternetResult object and//Get Internet service referencelnvo_<strong>in</strong>ternet_result = create nvo_<strong>in</strong>ternet_resultli_retval = GetContextService(“Internet”, l<strong>in</strong>et_base)//Web Service URL, note the question mark <strong>in</strong>cluded//on the end. Don’t forget thisls_url=”http://webservices.amazon.com/onca/xml?”//Argument list <strong>of</strong> name/value pairs <strong>in</strong> the format//=&ls_args=”Service=AWSECommerceService&” + &“AWSAccessKeyId=[YourAccessKey]&” + &“Operation=ItemSearch&” + &“SearchIndex=Music&” + &“Keywords=Butch Walker”//Concatenate URL with Arguments and call GetURL method.//The response from the web service will be sent to the//InternetData method <strong>in</strong> the lnvo_<strong>in</strong>ternet_result object//and execute the code there (popp<strong>in</strong>g up a MessageBox)li_retval = l<strong>in</strong>et_base.GetURL(ls_url + ls_args, &lnvo_<strong>in</strong>ternet_result)//Clean updestroy l<strong>in</strong>et_basedestroy lnvo_<strong>in</strong>ternet_resultList<strong>in</strong>g 2nvo_<strong>in</strong>ternet_result lnvo_<strong>in</strong>ternet_result<strong>in</strong>et l<strong>in</strong>et_base<strong>in</strong>teger li_retvallong ll_<strong>con</strong>tent_length, long ll_portStr<strong>in</strong>g ls_url, ls_args, ls_headersblob lblb_args//Initialize InternetResult object and//Get Internet service referencelnvo_<strong>in</strong>ternet_result = create nvo_<strong>in</strong>ternet_resultli_retval = GetContextService(“Internet”, l<strong>in</strong>et_base)//Web Service URL, note the question mark <strong>in</strong>cluded//on the end. Don’t forget thisls_url=”http://webservices.amazon.com/onca/xml?”//Server Port Number, typically 80 or 0 for default//Note putt<strong>in</strong>g 443 here does not give you HTTPSll_port = 80//Argument list <strong>of</strong> name/value pairs <strong>in</strong> the format//=&ls_args=”Service=AWSECommerceService&” + &“AWSAccessKeyId=[YourAccessKey]&” + &“Operation=ItemSearch&” + &“SearchIndex=Music&” + &“Keywords=Butch Walker”//For PostURL we will <strong>con</strong>vert our argument list//from a str<strong>in</strong>g to a blob and get the length <strong>of</strong>//our result<strong>in</strong>g bloblblb_args = blob(ls_args)ll_<strong>con</strong>tent_length = Len(lblb_args)//For PostURL we also have to set two HTML headers//Content-Length and Content-Type separated by two//newl<strong>in</strong>e charactersls_headers = “Content-Length: “ + &Str<strong>in</strong>g(ll_<strong>con</strong>tent_length) + “~n~n” + &“Content-Type: “ + &“application/x-www-form-urlencoded”32 PBDJ volume12 issue11pbdj.<strong>sys</strong>-<strong>con</strong>.com


We call PostURL with our additional parameters (portbe<strong>in</strong>g//The response from the web service will be sent to the//InternetData method <strong>in</strong> the lnvo_<strong>in</strong>ternet_result object//and execute the code there (popp<strong>in</strong>g up a MessageBox)li_retval = l<strong>in</strong>et_base.PostURL(ls_url, &lblb_args, &ls_headers, &ll_port, &lnvo_<strong>in</strong>ternet_result)//Clean updestroy l<strong>in</strong>et_basedestroy lnvo_<strong>in</strong>ternet_resultList<strong>in</strong>g 3//First download and <strong>in</strong>stall the latest XmlHttp package//(this l<strong>in</strong>k goes to the one listed <strong>in</strong>//the <strong>con</strong>nectToNewObject call - “Msxml2.XMLHTTP.4.0”//http://www.micros<strong>of</strong>t.com/downloads/details.aspx?familyid=3144b72b-b4f2-46da-b4b6-c5d7485f2b42&displaylang=en#filelist//XmlHttp object method summary//http://msdn.micros<strong>of</strong>t.com/library/default.asp?url=/library/en-us/xmlsdk/html/xmmscxmldommethods.aspStr<strong>in</strong>g ls_get_url, ls_post_urlStr<strong>in</strong>g ls_args, ls_responseStr<strong>in</strong>g ls_response_text, ls_status_textlong ll_status_codeOleObject loo_xmlhttpls_get_url = “http://webservices.amazon.com/onca/xml?”ls_post_url = “http://webservices.amazon.com/onca/xml”ls_args = “Service=AWSECommerceService&” + &“AWSAccessKeyId=[YourAccessKey]&” + &“Operation=ItemSearch&” + &“SearchIndex=Music&” + &“Keywords=Butch Walker”try//Create an <strong>in</strong>stance <strong>of</strong> our COM objectloo_xmlhttp = CREATE oleobjectloo_xmlhttp.ConnectToNewObject(“Msxml2.XMLHTTP.4.0”)//First lets do a GET requestloo_xmlhttp.open (“GET”,ls_get_url + ls_args, false)loo_xmlhttp.send()//Get our responsels_status_text = loo_xmlhttp.StatusTextll_status_code = loo_xmlhttp.Status//Check HTTP Response code for errors//http://kbs.cs.tu-berl<strong>in</strong>.de/~jutta/ht/responses.htmlif ll_status_code >= 300 thenMessageBox(“GET Request Failed”, ls_response_text)else//Get the response we received from the web serverls_response_text = loo_xmlhttp.ResponseTextMessageBox(“GET Request Succeeded”, ls_response_text)end if//Lets do a POST now, notice now we will pass a Str<strong>in</strong>g//<strong>in</strong> the send() call that <strong>con</strong>ta<strong>in</strong>s the arguments <strong>in</strong> the//format name1=value1&name2=value2&...loo_xmlhttp.open (“POST”,ls_post_url, false)loo_xmlhttp.setRequestHeader(“Content-Type”, &“application/x-www-form-urlencoded”)loo_xmlhttp.send(ls_args)//Get our responsels_status_text = loo_xmlhttp.StatusTextll_status_code = loo_xmlhttp.Status//Check HTTP Response code for errors//http://kbs.cs.tu-berl<strong>in</strong>.de/~jutta/ht/responses.htmlif ll_status_code >= 300 thenMessageBox(“POST Request Failed”, ls_response_text)else//Get the response we received from the web serverls_response_text = loo_xmlhttp.ResponseTextMessageBox(“POST Request Succeeded”,ls_response_text)end if//Done so cleanuploo_xmlhttp.Dis<strong>con</strong>nectObject()catch (RuntimeError rte)MessageBox(“Error”, “RuntimeError - “+ rte.getMessage())end tryList<strong>in</strong>g 4long ll_retval, ll_rowcount, iStr<strong>in</strong>g ls_accesskeyid, ls_subscriptionid, ls_associatetagStr<strong>in</strong>g ls_xmlescap<strong>in</strong>g, ls_validate, ls_responseSoapConnection lsoap_<strong>con</strong>nawsecommerceserviceport lws_amazontns__itemsearchrequest lstr_searchrequesttns__itemsearchrequest lstr_searchrequestarray[]tns__operationrequest lstr_operationrequesttns__items lstr_itemsls_accesskeyid = “[YourAccessKey]”ls_subscriptionid = “”ls_associatetag = “”ls_xmlescap<strong>in</strong>g = “S<strong>in</strong>gle”ls_validate = “True”lstr_searchrequest.search<strong>in</strong>dex = “Music”lstr_searchrequest.keywords = “Butch Walker”lws_amazon = create awsecommerceserviceport//Instantiate SOAP <strong>con</strong>nectionlsoap_<strong>con</strong>n = create SoapConnection// Set trace file to record soap <strong>in</strong>terchange data,ll_retval = lsoap_<strong>con</strong>n.SetOptions(‘SoapLog=’ + &‘“C:\mySoapLog.log”’)ll_retval = lsoap_<strong>con</strong>n.CreateInstance(lws_amazon, &“awsecommerceserviceport”)if ll_retval 0 thenas_errmsg = “Unable to create proxy. “ + &“Error Code: “ + Str<strong>in</strong>g(ll_retval)else// make call to web servicetrylstr_items = lws_amazon.itemsearch(ls_subscriptionid, &ls_accesskeyid, &ls_associatetag, &ls_xmlescap<strong>in</strong>g, &ls_validate, &lstr_searchrequest, &lstr_searchrequestarray, &lstr_operationrequest)ll_rowcount = lstr_items.totalresults//Iterate our response for <strong>in</strong>formationfor i=1 to ll_rowcountls_response = ls_response + &“ASIN: “ + &lstr_items.item[i].as<strong>in</strong> + &“ Artist: “ + &lstr_items.item[i].itemattributes.artist[1] + &“ Title: “ + &lstr_items.item[i].itemattributes.title + “~r~n”nextMessageBox(“Web Service Response”,ls_response)catch ( SoapException e )MessageBox(“Soap Exception”, &“Cannot <strong>in</strong>voke Web Service: “ +e.text)end tryend if//Cleanupif isValid(lsoap_<strong>con</strong>n) thendestroy lsoap_<strong>con</strong>nend ifwww.<strong>SYS</strong>-<strong>CON</strong>.COM/pbdj/PBDJ volume12 issue1133


<strong>PowerBuilder</strong> NewsAll th<strong>in</strong>gs <strong>of</strong> <strong>in</strong>terest to the PB community BY BRUCE ARMSTRONGbruce.armstrong@teamsybase.com<strong>PowerBuilder</strong> Third-PartyEnable 1.2 and SBEEnable, a framework-level tool forthe localization <strong>of</strong> <strong>PowerBuilder</strong>applications, released version 1.2,which <strong>in</strong>troduces Enable Explorer,a powerful runtime utility to viewthe visual structure <strong>of</strong> runn<strong>in</strong>g w<strong>in</strong>dows,select and take notes on<strong>con</strong>trols and DataW<strong>in</strong>dow objects,as well as resize/ move them, andtranslate or modify the translation<strong>of</strong> each item, <strong>in</strong>clud<strong>in</strong>g parametricphrases. Explorer can also bedeployed to end users. In addition,Enable Extractor, a fast parser, hasbeen enhanced to capture argumentsto methods parameters(e.g., 1st and 2nd parameters <strong>of</strong>Messagebox function calls), andthe filter dialog is now easier to use.Among multiple other improvements,Enable now also automaticallytranslates computed fields.With the release <strong>of</strong> version 1.2, aSmall Bus<strong>in</strong>ess Edition (SBE) withfull functionality has also beenpresented to meet the localizationrequirements <strong>of</strong> developers withless complex client/server applications(600 text str<strong>in</strong>gs or fewer).www.enable-pb.comPBL Peeper10/7 – Techno-Kitten.com addednew features to PBL Peeper. Itreads folders <strong>of</strong> export files (thisfeature may be a little raw, i.e.,untested). Command-l<strong>in</strong>e parametersare documented <strong>in</strong> themanual. Otherwise, on the PBLspage, select Export folders underFolder selection and drag a foldereither from Explorer or thedisk/folder list on the left.www.techno-kitten.comSybase CorporateSAP NetWeaver11/14 – Sybase, Inc., announcedthat its highly scalable analyticsserver, Sybase IQ, has receivedcertification for <strong>in</strong>tegration withSAP NetWeaver Bus<strong>in</strong>ess Intelligence(SAP NetWeaver BI), achiev<strong>in</strong>g“Certified for SAP NetWeaver”status. SAP NetWeaver BI, a component<strong>of</strong> SAP NetWeaver’s comprehensive<strong>in</strong>tegration and applicationplatform, helps customers<strong>in</strong>tegrate data from across theenterprise and beyond, and thentransform it <strong>in</strong>to practical, timelybus<strong>in</strong>ess <strong>in</strong>formation to drivesound decision-mak<strong>in</strong>g, targetedaction, and solid bus<strong>in</strong>ess results.Sybase IQ is an analytics serverthat runs on standard hardwareand operat<strong>in</strong>g <strong>sys</strong>tems, especiallydesigned for bus<strong>in</strong>ess <strong>in</strong>telligence.Comb<strong>in</strong><strong>in</strong>g the power <strong>of</strong> SAP withSybase IQ’s unsurpassed queryperformance and storage efficiencyfor structured and unstructureddata, companies can save time,storage capacity, and overall costs.2005 Mobile EnterpriseCompany <strong>of</strong> the Year Award11/9 – Frost & Sullivan presentedSybase with its 2005 MobileEnterprise Company <strong>of</strong> the YearAward. Sybase and its subsidiary,iAnywhere, is credited with <strong>in</strong>troduc<strong>in</strong>gthe <strong>in</strong>dustry’s first mobiledatabase for laptops, the firstmobile synchronization, and thefirst small f<strong>in</strong>gerpr<strong>in</strong>t database forhandheld and memory-<strong>con</strong>stra<strong>in</strong>eddevices.Sybase <strong>con</strong>siders mergers andacquisitions as key to its visionand bus<strong>in</strong>ess strategy. The Avant-Go technology acquisition <strong>in</strong> 2003helped iAnywhere open itsmobile database to Web developersand ga<strong>in</strong> traction <strong>in</strong> the ondemandmobile applications and<strong>con</strong>sumer <strong>con</strong>tent markets. ItsMay 2004 acquisition <strong>of</strong> XcelleNet,a specialist <strong>in</strong> mobile datamanagement, remote devicemanagement, and mobile datasecurity, added 2,200 customersto Sybase’s customer base andre<strong>in</strong>forced partner relationshipswith<strong>in</strong> the mobile eco<strong>sys</strong>tem.Visual Studio 200511/7 – Sybase, Inc., announced its<strong>con</strong>t<strong>in</strong>ued and expanded commitmentand support for theMicros<strong>of</strong>t .NET environment.Sybase, a premier partner <strong>in</strong> theMicros<strong>of</strong>t Visual Studio IndustryPartner (VSIP) program, <strong>of</strong>fersdevelopment and model<strong>in</strong>g productsthat either support or are<strong>in</strong>tegrated <strong>in</strong>to the .NET environment,<strong>in</strong>clud<strong>in</strong>g DataW<strong>in</strong>dow.NET 2.0, PocketBuilder, Power-Builder, PowerDesigner, and SQLAnywhere. In addition, Sybase isexpand<strong>in</strong>g its support for other.NET Framework-based technologies,<strong>in</strong>clud<strong>in</strong>g Sybase AdaptiveServer Enterprise (ASE) 15.0enterprise-class database, Afariamanagement and security formobile platforms, and RFID Anywhere,middleware platform.iAnywhereFaith Footwear Limited11/24 – iAnywhere, a subsidiary<strong>of</strong> Sybase, Inc., announced thataward-w<strong>in</strong>n<strong>in</strong>g UK footwearretailer, Faith Footwear Limited,has extended its use <strong>of</strong> iAnywheretechnology with the deployment<strong>of</strong> iAnywhere Afaria, which hasbeen rolled out throughout head<strong>of</strong>fice as well as to 75 Faith storesand 100 plus <strong>con</strong>cessions acrossthe UK.Afaria has enhanced theremote back-<strong>of</strong>fice managementand transfer <strong>of</strong> <strong>in</strong>formationbetween Faith’s branch <strong>of</strong>ficesand <strong>con</strong>cessions, and its ma<strong>in</strong>headquarters <strong>in</strong>clud<strong>in</strong>g sales figures,<strong>in</strong>ventory details, stockorder<strong>in</strong>g, and customer service<strong>in</strong>formation. It has supersededthe company’s <strong>in</strong>cumbent datamanagement solution – iAnywhereRemoteWare. The latterhad been <strong>in</strong> use at the companyfor five years when Faith decidedto expand the functionality <strong>of</strong> itsback <strong>of</strong>fice <strong>sys</strong>tems to <strong>in</strong>clude anumber <strong>of</strong> additional features.Advantage Database Server 8.011/8 – iAnywhere, a subsidiary <strong>of</strong>Sybase, Inc., announced that it’sstrengthen<strong>in</strong>g its database managementportfolio with therelease <strong>of</strong> Advantage DatabaseServer 8.0. Advantage DatabaseServer is a full-featured, high-performanceclient/server datamanagement <strong>sys</strong>tem targetedtoward Borland Delphi and C++Builder developers. The new features<strong>in</strong> Advantage Data Architect,Advantage Replication,Advantage Onl<strong>in</strong>e Backup andSQL script<strong>in</strong>g will enhanceAdvantage Database Server 8.0with ease-<strong>of</strong>-use, performanceand efficiency. The AdvantageDatabase Server was recentlyacquired by Sybase through itspurchase <strong>of</strong> Extended Systems <strong>in</strong>October 2005.Advantage 8.0 provides developerswith the functionality theyrequire to easily build scalablebus<strong>in</strong>ess applications with lowadm<strong>in</strong>istration requirements.Major new features <strong>in</strong>clude anewly designed Advantage DataArchitect, replication support,onl<strong>in</strong>e backup functionality, andthe addition <strong>of</strong> SQL script<strong>in</strong>g.F<strong>in</strong>ancial FusionF<strong>in</strong>ancial Partners, Inc.11/15 – F<strong>in</strong>ancial Fusion, Inc., aSybase company, announced thatF<strong>in</strong>ancial Partners, Inc. (FPI), hasimplemented F<strong>in</strong>ancial Fusion’sCorporate Bank<strong>in</strong>g Solution. FPIhas deployed Corporate Bank<strong>in</strong>gSolution 2.4 to support a widerange <strong>of</strong> Farm Credit organizations<strong>in</strong>clud<strong>in</strong>g their multiple, diversemarket segments from smallerbus<strong>in</strong>esses to large corporate entities.The new solution was implemented<strong>in</strong> partnership with Data-House, a F<strong>in</strong>ancial Fusion partner.This solution allows bus<strong>in</strong>essesto manage their accounts, access<strong>in</strong>formation services, and performfull-service money movementfunctions <strong>in</strong>clud<strong>in</strong>g ACHand wire transfers all with an<strong>in</strong>tuitive user <strong>in</strong>terface.34 PBDJ volume12 issue11pbdj.<strong>sys</strong>-<strong>con</strong>.com


Forget the wires.We knowthe ropes.Wonder<strong>in</strong>g how to get your Wi-Fi projects<strong>of</strong>f the ground? We can showyou how. We’re iAnywhere Solutions,the lead<strong>in</strong>g provider <strong>of</strong> solutions forthe unwired enterprise.Emerg<strong>in</strong>g wireless technologies suchas Wi-Fi now enable bus<strong>in</strong>esses todeliver a desktop comput<strong>in</strong>g experienceto mobile workers. We havemore than a decade <strong>of</strong> experiencedeliver<strong>in</strong>g "always available" access tocorporate data and applications –keep<strong>in</strong>g your mobile workers productivewhen they don’t have a wireless<strong>con</strong>nection and provid<strong>in</strong>g <strong>in</strong>formationsecurity and synchronization serviceswhen they enter a wireless LAN or hotspot.More than ten thousand companiesand one thousand partners worldwiderely on mobile technology fromiAnywhere Solutions.Let us show you the ropes to get yourWi-Fi solutions <strong>of</strong>f the ground quickly.Call 1-800-801-2069 or visitwww.ianywhere.com.Copyright 2003. iAnywhere Solutions, Inc. All rights reserved. iAnywhere is a trademark <strong>of</strong> Sybase, Inc. or its subsidiaries.All other trademarks are the property <strong>of</strong> their respective owners.www.ianywhere.com

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!