PB API调用指南

The tens of thousands of function calls in the Windows environment can be helpful to PowerBuilder users, but documenting them is nearly impossible. After hundreds of user inquiries, Powersoft Technical Support compiled these technical tips to enable PowerBuilder developers to translate standard Microsoft function calls into PowerBuilder syntax, and to empower developers to use any of the external API calls within their owerBuilder environments..

The following information will help you translate and Windows SDK call to a PowerBuilder API function call. It doesn't matter whether you're using PowerBuilder 4.0, 5.0, 6.0, 7.0 or 8.0 but there are important differences between the 16- and 32-bit versions, as we'll discuss below. 

Step 1: Converting an SDK Call to a PowerBuilder API Call.

First you need to get the syntax that wil be converted. This can be obtained from either a Windows API Bible or the MSDN (Microsoft Developers Network).

Step 2: Determining Whether it is a Function or a Subroutine.

Function calls return a value; subroutines do not.

Here is an example of a Microsoft function:
BOOL GetFileVersionInfo( LPTSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData );

Here is an example of a Microsoft subroutine:
VOID GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer);

Step 3: Converting the datatypes from Microsoft to PowerBuilder.

MICROSOFT

PB(16Bit)

PB(32Bit)

Bool

Boolean

Boolean

Char*

Ref string

Ref String

Colorref

Uint

Ulong

Dword

Uint

Ulong

Handle

Uint

Ulong

Hdc

Uint

Ulong

Hfile

Uint

Ulong

Hinstance

Uint

Ulong

Hwnd

Uint

Ulong

Int

Int

Int

Lparam

Uint

Ulong

Lpbyte

Ref Int

Ref Long

Lpdword

Ref Uint

Ref Ulong

Lpfiletime

Ref Time

Ref Time

Lpint

Ref Int

Ref Long

Lpstr,Lpststr

Ref String

Ref String

Lpvoid

Ref Structstruct_inst

Ref Struct struct_inst

Mcierror

Long

Long

Lpstr,Lpststr

Ref String

Ref String

Lpvoid

Ref Structstruct_inst

Ref Struct struct_inst

Pbyte

Ref Int[#]

Ref Long[#]

Short

Int

Int

Structure

Ref Struct struct_inst

Ref Struct Struct_inst

Uint

Uint

Uint

Void**

SUBROUTINE

SUBROUTINE

Word

Int

Ulong

Wparam

Uint

Ulong

Most of the datatypes are listed above, but some may be missing. When in doubt read the datatype description first. If still unsure, it is usually safe to assume a 16 bit datatype is a "uint" and a 32 bit datatype is a "ulong", since they are the most common.

*If the word "Callback appears as a datatype, it cannot be performed by PowerBuilder. Callback routines are functions that are called from within functions.

Step 4: Coding the Global/Local External Function:

This is a Microsoft function:
BOOL GetFileVersionInfo( LPTSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData );

The BOOL represents a boolean return code, which is translated to "Boolean" in PB for both 16 and 32 bit. A LPCTSTR means a pointer to a string (see step 3). In PowerBuilder, simply use the word "ref" before declaring the string in either 16- or 32-bit platofrms. DWORD is translated to "uint" for 16 bit and "ulong" for 32 bit. An LPVOID indicates that a structure is being used. In PowerBuilder, create a structure, assign it to an instance variable of that structure and pass it by reference. As a result, the following function declarations can be derived:

PowerBuilder 16 bit:
FUNCTION boolean GetFileVersionInfo(ref string filename, uint f_handle, uint f_length, ref lpdata lpdata2) LIBRARY "ver.dll"

PowerBuilder 32 bit:
FUNCTION boolean GetFileVersionInfoA(ref string filename, ulong f_handle, ulong f_length, ref lpdata lpdata2) LIBRARY "version.dll"

Note: In the "gotchas" section listed below, you'll get a further explanation why an "A" is appended to the 32-bit function. You'll also find a handy technique to help you locate function calls within the DLLs.

Step 5: Creating a Structure

In this particular example a structure is needed so you'll need information on what elements are contained within this structure. The MSDN provides this information since the function being called is a Windows function.

In the MSDN the structure appears like this:
LPDATA = { DWORD dwSignature ; DWORD dwStrucVersion ; DWORD dwFileVersionMS ; DWORD dwFileVersionLS ; DWORD dwProductVersionMS ; DWORD dwProductVersionLS ; DWORD dwFileFlagsMask ; DWORD dwFileFlags ; DWORD dwFileOS ; DWORD dwFileType ; DWORD dwFileSubtype ; DWORD dwFileDateMS ; DWORD dwFileDateLS }

In PB you would go into the structure painter and in this particular case all of these elements would be converted to ULONG. If one of the elements within the structure was a nested structure or callback routine you would not be able to use this function within PB. In that case the only option would be to create a C DLL that makes the function call and call it from PB.

Step 6: Scripting the Function Call.

Now that you have the function declaration you need to pass it the proper arguments. Taking the function " GetFileVersionInfoA" listed in Step 4 the following script would be needed:

First you'll need to declare the datatypes. Keep in mind the variable names do not have to match the function declaration listed in step 4.

boolean lb_rtn // Return code
string ls_filename // 1st argument - filename
ulong lu_hand // 2nd argument - f_handle
ulong lu_len // 3rd argument - f_length
lpdata lpdata2 // Last argument - assigning an instance of a structure.

Next is the hardest part and that is assigning values to the arguments. This part may require use of the MSDN, API Bible or whatever reference is available that covers the function you are calling. In this particular case the information is contained within the MSDN.

The first argument " ls_filename ", should be set to the path and filename of the target file.

ls_filename = "c:/windows/calc.exe" // The calculator would be a good file to test against.

The second argument "lu_hand" according to the MSDN is ignored. This is probably reserved for a future version of Windows to use. To be safe the argument should be set to null.

setnull(lu_hand)

The third argument "lu_len" contains the size of the buffer that the information will be returned into. It is critical that the buffer size not be too small or the information may overflow into another part of memory causing a GPF or Dr. Watson error. In this particular case since the structure contains 13 elements that are all ulong, the number 256 should be sufficient to contain the information.

lu_len = 256

The last argument "lpdata2" is an instance of the structure "lpdata" and it will be populated by the function call.

The final script will appear as follows:

boolean lb_rtn
string ls_filename
ulong lu_hand, lu_len
lpdata lpdata2
ls_filename = "c:/windows/calc.exe" // The calculator would be a good file to test against.
setnull(lu_hand)
lu_len = 256
lb_rtn = GetFileVersionInfoA(ls_filename, lu_hand, lu_len, lpdata2)

// Viewing the output -------------------------------------------------------------
sle_1.text = string(lpdata2.dwSignature)
sle_2.text = string(lpdata2.dwStrucVersion)
sle_3.text = string(lpdata2.dwFileVersionMS)
sle_4.text = string(lpdata2.dwFileVersionLS)
sle_5.text = string(lpdata2.dwProductVersionMS)
sle_6.text = string(lpdata2.dwProductVersionLS)
sle_7.text = string(lpdata2.dwFileFlagsMask)
sle_8.text = string(lpdata2.dwFileFlags)
sle_9.text = string(lpdata2.dwFileOS)
sle_10.text = string(lpdata2.dwFileType)
sle_11.text = string(lpdata2.dwFileSubtype)
sle_12.text = string(lpdata2.dwFileDateMS)
sle_13.text = string(lpdata2.dwFileDateLS)
Messagebox("Return Code", string(lb_rtn))
// -----------------------------------------------------------------------------------------

Gotcha's to look out for:
1. Make sure the DLL you are referencing is the right bit level. This can sometimes be done by looking at the DLL's properties but most likely you'll need a third party product to determine this.  Remember, a 16 bit application cannot make a 32 bit API call and visaversa.
2. Some functions are cap sensitive. "Findwindowa" might fail whereas "FindWindowA" works.
3. All handles in PowerBuilder 16 bit are UINT and 32 bit are ULONG. Using the datatypes INT or LONG may work but if the handle points to an area in high memory the latter two datatypes may not be able to support such a large number.
4. Make sure you have the correct function name. Under 32 bit many of the functions had an "A" (Whcih stands for Ascii) appended to the function name to make it unique from it's 16 bit counterpart. This allows developers to place both 16 bit and 32 bit function calls in the same application and then making the correct function call based on what bit platform the program is being run from. The real reason why Microsoft named the functions this way was to differentiate between (A)-Ascii and (W)-Unicode format. The MSDN does not always list the proper names for the functions. For example: GetFileVersionInfo is listed as a 32 bit function but it is in fact GetFileVersionInfoA.
5. Global versus Local External Function declaration. If the function is declared globally it can be called from anywhere in your application. If you declare the function as a Local External Function it can only be called from that window where it's declared. Local Function use less resources then globals but the difference is very minimal.

Error Messages and what they mean:
1. Error: Error opening DLL library <filename> for external function at line <line_number> in the <event name> event of object <object_name> of <window_name>.

Possible causes:
> DLL is 16 bit and thus incompatible.
> DLL is not in a searchable directory.
> DLL connects to another DLL that cannot be found.
> DLL has the same name as another already loaded into memory.
> DLL is corrupted or in an incompatible format.

2. Error: Error calling external function <function_name> at line <line_number> in the <event name> event of object <object_name> of <window_name>.

This is probably the result of an incorrectly spelt function name. Be sure to verify that the function name matches what is in the DLL exactly, including the case of the letters.

3. Error: Specified argument type differs from required argument type at runtime in DLL function <function_name>. (Invalid stack pointer on return from function call) at line <line_number> in <event_name> event of object <object_name> of <window_name>.

This error usually indicates the datatypes do not match what the DLL function is expecting.

4. PB050: Caused an Invalid Page Fault in module PBSHR050.DLL @ 0137:1111163e

This error can occur either immediately upon calling the function or when the application closes. The module and memory address may vary but the reason for this is usually the same. If PB is receiving a string and memory isn't allocated in advance using the SPACE( ) that string will overflow into another memory area. To allocate 12 characters to the string "ls_filename" the following code would be used.

ls_filename = space(13) // You may want to give it an extra space just to be safe.

5. Receiving garbage from the DLL. i.e. Last name populated as: "*#^&Ryan"

This problem is most likely the result of the byte alignment being set incorrectly. PowerBuilder expects the byte alignment to be set to one and if you are using MSVC++ compiler the default setting is four. To set the byte alignment to one you would need to do the following prior to compiling to a dll.

- Select the desired target
- Right mouse click and select Settings
- Select the C/C++ tabpage
- Select Code Generation from the Category dropdown list
- Select desired byte alignment from the Struct Member Alignment dropdown list.

The DOS switch to set the byte alignment to one is: /zp1

A handy trick to find functions quickly:

1. On Win95,Win98 or NT 4.0 click on the START button and select "Find", then "Files or Folders".
2. In the SLE entitled "Named" enter "c:/*.dll". If this is a Windows DLL that you'll be calling enter "c:/windows/*.dll".
3. Click on the "Advanced" tab and in the "Containing Text" SLE enter the exact function name you are looking for. For example: FindWindowA
4. There will usually be a lot of DLL's that contain the function you are looking for but try to use the main Windows DLL's whenever possible since they are already loaded into memory.

Related Faxlines:
47626 - External Functions Calls to the DLLs created using Visual C++
44596 - 16 Bit - Windows API Calls for PowerBuilder 4.0, 5.0 & 6.0
44545 - 32 Bit - Windows API Calls for PowerBuilder 5.0
44648 - Prototyping API Calls for PowerBuilder 4.0, 5.0 and 6.0
44588 - Dynamically Closing a Non-PowerBuilder Application
47703 - GPF's and The PowerBuilder Memory Defragger
47704 - Windows 3.10 and 3.11 Functions - Krnl386.exe, User.exe, Gdi.exe
47707 - 16 Bit - Win95 and NT Functions - Krnl386.exe, User.exe, Gdi.exe
47705 - 32 Bit - Win95 and NT Functions - Kernel32.dll, User32.dll, Gdi32.dll
44474 - External Function Calls
44538 - Passing a 32-bit PowerBuilder structure to a 32-bit C DLL Created in Power++

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值