| By Xue-song Wu | Article Rating: |
|
| October 1, 2002 12:00 AM EDT | Reads: |
320 |
From the PowerBuilder forums I've discovered that quite a few people are requesting a feature that allows them to write console applications with PowerBuilder. PowerBuilder doesn't support this feature natively right now, but we can already do it with PowerBuilder 9Swith the help of PBNI.
There are two reasons you can't create console applications with the PowerBuilder IDE. One, PowerBuilder doesn't provide functions or classes for writing strings to a console and getting input from the console; two, the executables created by the PowerBuilder IDE are always for Windows GUI applications.
Fortunately, both problems can be solved using PBNI technology. First we write a PBNI extension that exposes a PB native class named console that provides functions for getting input from the console and writing output to the console. Then we write a small console stub in C++ that loads the PBVM (PowerBuilder Virtual Machine) and runs a PB application that utilizes the console native class.
This article shows how to write the console native class and a generic console stub in C++ that run a PB application, and how to use them to create PB console applications.
The article includes a .zip file, console.zip, that contains the source code for the console PBNI extension and the C++ console stub, and a PB application demonstrating how to create a PB console application. This file can be downloaded from www.sys-con.com/pbdj/ sourcec.cfm. The .zip file contains four subdirectories - bin, ext, pb, and test - under the console directory. The bin directory contains the compiled binary files: console.pbx, console.pbd, and pb.exe. The ext directory contains the source file and project file for the console extension. The pb directory contains both the source and project files for the C++ console stub. The test directory contains a PB application for testing the console extension and the C++ console stub.
Figure 1 shows the relationships between the console stub
pb.exe, PBVM, console.pbx, and PB application.
The Console PBNI Extension
The console extension provides a native class called console.
The description of the extension is as follows:
static const TCHAR desc[] = {
"class console from nonvisualobject
"
"function int read()
"
"function string readline()
"
"subroutine write(string s)
"
"subroutine writeline(string s)
"
"end class
"
};
The read() function gets a character from the input stream; the readLine() function gets a line from the input stream; the write() function puts a string to the output stream; and the writeLine() function puts a string followed by a newline to the output stream.
We create a C++ class, PBConsole, that implements the IPBX_NonVisualObject interface. Listing 1 provides the declaration for the PBConsole class.
The four private functions - read(), readLine(), write(), and writeLine() - correspond to the four functions of the console native class, respectively. We use the standard C++ iostream to implement the four functions. Standard C++ defines two global variables: cin and cout. cin is for controlling extractions from the standard input as a byte stream; cout is for controlling insertions to the standard output as a byte stream. The code is rather simple (see Listing 2).
You may notice that tcin and tcout are used in this listing instead of cin and cout. This makes it possible to compile the PBNI extension in both ANSI and Unicode versions. When _UNICODE is defined, the Visual C++ compiler will compile the extension in the Unicode version, and the global variables wcin and wcout will be used instead of cin and cout. Likewise, the type wstring will be used instead of string.
To make the coding easier, we define a set of macros starting with "t," including tstring, tcin, and tcout. When _UNICODE is defined, they will map to wstring, wcin, and wcout, respectively. The three macros are defined as follows:
#if defined(_UNICODE)
#define PBTEXT(s) L##s
#define tstring std::wstring
#define tcin std::wcin
#define tcout std::wcout
#define
#else
#define PBTEXT(s) s
#define tstring std::string
#define tcin std::cin
#define tcout std::cout
#endif
The macro PBTEXT is for making a constant string to a Unicode string if _UNICODE is defined. PowerBuilder 10 will support Unicode. To make your PBNI extensions able to be compiled in both ANSI and Unicode versions, the above mentioned technique is a common way to achieve this.
The source file of the console extension, console.cpp, is located in the ext directory. Open the Visual C++ project file, console.dsp, with Visual Studio 6 and build the project; you'll get the console.pbx in the bin directory. Run pbx2pbd90.exe to generate the .pbd file, console.pbd, for the extension.
Write the C++ Console Stub
You may wonder if we can use the console extension in normal
PB applications to create console applications. The answer is no,
because a normal PB application is a Windows GUI application that
doesn't open a console window. Calling functions of the console
native class in a GUI application will not have any effect.
The C++ console stub is pretty simple. It just loads the PBVM, gets the pointer to the IPB_VM interface, and calls the RunApplication() function on the interface pointer. The only thing we need to consider is how to make the stub generic.
Each PB application has an application-derived class and a list of PBL (or PBD) files (called library list in PB's terminology). The RunApplication() function takes the name of the application-derived class and the library list as parameters. After some initialization work, the function will trigger the open event of the application object, causing the script of the open event to be executed.
If the name of the application class and the library list can be passed to the console stub through the command line, the console stub will be able to load all PB console applications. Java.exe is very likely doing it the same way.
Listing 3 provides the source code for the console stub.
The parseOptions() function gets the application name and the library list from the command line.
The LibList helper class converts the vector of strings to a C array of pointers to zero-terminated strings, which is required by the RunApplication() function.
The source file, pb.cpp, is located in the pb directory. Building the Visual C++ project, pb.dsp, will generate pb.exe located in the bin directory. The usage of pb.exe is:
pb application_name library_list
If there is more than one library in the library list, use a semicolon ";" to separate them. For example, pb testconsole testconsole.pbl;console.pbd.
Creating PB Console Applications
You can do virtually everything in a PB console application
except open windows. You can create a nonvisual object and call
functions on the object; you can also create a DataStore and retrieve
data from a database. If you need to get a user's input or want to
print something to the console, you can use the console native class.
The following PowerScript code is an example:
console con
con = create console
con.writeline("PB console application")
con.write("Input your name please: ")
string s
s = con.readLine()
con.writeLine("Hello, " + s)
First, create an instance of the console class, then call the writeline() function to print a line of text, "PB console application", to the console, followed by printing "Input your name please:" to the console by calling the write() function. After that, call the readline() function to get the user's input. Finally print the hello message to the console.
To run the PB console application, you need to add the bin subdirectory to the PATH, then open a Command console, go to the directory where the PB application is located, and type the command:
pb testconsole testconsole.pbl;console.pbd
When the application asks to input your name, input PBDJ, and
you'll get the result shown in Figure 2.
If you want to convert the PBL files, e.g., the testconsole.pbl file, to PBD files, you can create a normal application project to create an executable file, but without appending the PBD files to the .exe file. That way, you can get the PBD files you want. The .exe file generated is actually a stub for a Windows GUI application, and the pb.exe is for replacing it.
Conclusion
As you can see in this article, PBNI enables you to do a lot
of creative things. Although the future versions of the PowerBuilder
IDE might support creating console applications directly, you can use
the technique described in this article with PowerBuilder 9.
The console native class can be further enhanced; for example, we could add a readXXX function for each PB data type, or we could add a write function for each PB data type. With the enhanced console class in hand, it would be quite easy for you to write PB console applications.
Published October 1, 2002 Reads 320
Copyright © 2002 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Xue-song Wu
Xue-song Wu, a staff software engineer in Sybase Asia Development Center, Singapore, team leader of PowerBuilder Virtual Machine and Compiler team.
- Why SOA Needs Cloud Computing - Part 1
- Cloud Expo and The End of Tech Recession
- The Transition to Cloud Computing: What Does It Mean For You?
- A Rules Engine Built in PowerBuilder
- Sybase Named “Silver Sponsor” of iPhone Developer Summit
- How PowerBuilder Got Its Groove Back
- The Cloud Has Cross-Border Ambitions
- Ulitzer Names The World's 30 Most Influential Virtualization Bloggers
- Ulitzer Named "New Media" Partner of Greatly Anticipated iStrategy Event in Berlin
- Risks and Enterprise Mobility?
- Steps for Success in Enterprise Mobility?
- Are Mobile Luddites Resisting Mobility?
- The Difference Between Web Hosting and Cloud Computing
- Sybase CTO to Speak at 4th International Cloud Computing Expo
- Why SOA Needs Cloud Computing - Part 1
- Cloud Expo and The End of Tech Recession
- The Transition to Cloud Computing: What Does It Mean For You?
- Five Reasons to Choose a Private Cloud
- Seeding The Cloud: The Future of Data Management
- The Threat Behind the Firewall
- Economy Drives Adoption of Virtual Lab Technology
- Tips for Efficient PaaS Application Design
- A Rules Engine Built in PowerBuilder
- Sybase Named “Silver Sponsor” of iPhone Developer Summit
- Where Are RIA Technologies Headed in 2008?
- PowerBuilder History - How Did It Evolve?
- The Top 250 Players in the Cloud Computing Ecosystem
- Custom Common Dialogs Using SetWindowsHookEx
- DDDW Tips and Tricks
- OLE - Extending the Capabilities of PowerBuilder
- DataWindow.NET How To: Data Entry Form
- Book Excerpt: Sybase Adaptive Server Anywhere
- Sybase ASE 12.5 Performance and Tuning
- Working with SOA & Web Services in PowerBuilder
- Office 2003 Toolbar: A New Look For Your Old PowerBuilder App
- Dynamically Creating DataWindow Objects































