| By Bruce Armstrong | Article Rating: |
|
| April 26, 2005 10:00 AM EDT | Reads: |
29,972 |
How It's Done
The first step is to create a template PBNI nonvisual extension (one that implements the PBX_CreateNonVisualObject method) using the PBNI template wizard provided by Sybase or available from CodeXchange. The source code for this particular example is given in Listings 1 and 2 and is available from CodeXchange at http://powerbuilder.codexchange.sybase.com/files/ documents/67/1875/PBNISetWindowHook.zip.
Listing 1 is the header file for the extension. The template generates prototypes of sample methods in that header file with different names but the same argument list. We'll implement all of the methods within our class following that pattern. Any information that we need within our method, including the arguments that were passed to us from PowerBuilder in the extension call, will be available to us through the methods or properties of those arguments. So we rename one of the template-generated methods to Register, rename another to FilterFileTypes, and then copy one of those prototypes and rename that one SetDefaultFileType.
There are four basic operations our extension will be involved in:
- Registering the hook with the Windows message we are interested in
- Removing unwanted file types from the SaveAs dialog dropdown list
- Setting the new default file type for the SaveAs dialog dropdown list
- Clearing the registration of the hook
There will be corresponding methods on the PowerBuilder object for the first three of those operations, and the three methods in our header file are the internal methods of the C++ class that will be called when the corresponding PowerBuilder object method is called. The fourth operation (clearing the hook) is done automatically in the destructor method for our C++ class, so it doesn't require a separate method. It would be convenient to be able to register the hook automatically in the constructor method for our C++ class as well. However, the SetWindowsHookEx requires information about the instance and thread to limit the scope of the message that we're interested in hooking, and we get that information through the handle of the window the dialog is about to be invoked from. As a result, we have a method on the PBNI extension that takes the window handle as an argument and only then registers the hook.
We're also going to add three members outside of the class in the header file. One (hHook) stores a reference to our hook procedure, which we will use in the destructor to unregister the hook. The others hold the file types that we are planning to remove from the dropdown list and the file type that will be made the default. These are stored as members because the PowerBuilder method calls simply set those values and then the values are accessed separately by the hook procedure when it's run. Finally, we include the prototype for the callback method that we're going to register using the SetWindowsHookEx function.
Turning to the cpp file, the first thing we do is (as with any PBNI extension) provide a description for the objects and their methods that will be exposed to PowerBuilder in the PBX_GetDescription method:
"class CustomSaveAs from nonvisual object\n"
"function long Register ( long windowHandle )\n"
"function long FilterFileTypes ( string fileTypes[] )\n"
"function long SetDefaultFileType ( string fileType )\n"
"end class\n"
In the PBX_CreateNonVisualObject method, we simply create an instance of our class and pass back a reference to it to PowerBuilder.
CPBNISetWindowHook* pCPBNISetWindowHook = NULL;
pCPBNISetWindowHook = new CPBNISetWindowHook(pbsession, pbobj);
*obj = (IPBX_NonVisualObject*)pCPBNISetWindowHook;
The Invoke method is also required by PBNI; it simply maps the PowerBuilder object calls to the internal class method calls.
The Register method of our class is where things start to get interesting. We get the handle of the window that called us, and then use the GetWindowLong Windows API call to get a handle to the application instance:
hWindow = (HWND)ci->pArgs->GetAt(0)->GetLong() ;
hInstance = GetWindowLong ( hWindow, GWL_HINSTANCE ) ;
We then use the GetCurrentThreadId Windows API call to get a handle to the current thread. The application instance tells the SetWindowsHookEx method which application has the callback function that is being passed in. The handle to the thread tells the function to only invoke the callback function if the dialog message we're interested in is from that same thread. Otherwise, we could end up trapping and attempting to respond to messages sent from dialogs in other applications.
Published April 26, 2005 Reads 29,972
Copyright © 2005 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Bruce Armstrong
Bruce Armstrong is a development lead with Integrated Data Services (www.get-integrated.com). A charter member of TeamSybase, he has been using PowerBuilder since version 1.0.B. He was a contributing author to SYS-CON's PowerBuilder 4.0 Secrets of the Masters and the editor of SAMs' PowerBuilder 9: Advanced Client/Server Development.
- 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 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?
- Hot Event in Santa Clara Becomes Cool with the iPhone
- 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
































