Calling DLL functions using PBInvoke |
PBInvoke library documetation > Reference > Calling DLL functions using PBInvoke |
Prototype Declarations
Before a DLL function can be called its DLL and the prototype must be declared.
Prototype declarations in PBInvoke were designed in the way which minimizes steps a developer must perform to write the declaration's code. For most DLL functions there exist C-style declarations available either from the DLL's source code or from the documentation, like MSDN. PBInvoke can parse such C-style declarations as a string directly from PowerBuilder code at run-time.
In order to declare a function prototype, you must at first declare the DLL containing the function, as follows:
n_pi_core lnv_core n_pi_library lnv_user32 lnv_user32 = lnv_core.of_declare_library("user32.dll") |
If an error occures by default a message box is shown and the return value is null. You can disable message boxes globally as follows:
n_pi_core lnv_core lnv_core.of_set_show_error(False) // this setting is applied to all future errors, // even in another instances of n_pi_core or another PBInvoke objects. |
Now, when the library has been declared you can declare the prototype itself:
n_pi_method lnv_SendMessage lnv_SendMessage = lnv_user32.of_declare_method(& "LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) ") |
You can see that the text of the declaration is exactly the same as it's shown in MSDN (except removed newlines). The complete syntax of the declaration string is the following:
result_type [ calling_convention ] function_name([param_type param, ...])
where
Due to the fact that MSDN shows all prototypes without WINAPI modifier (which in fact is
there), PBInvoke has default calling convention WINAPI(__stdcall), which differs from the default C/C++
convention. Be careful when copying declarations from sources other than MSDN.
Note, the default calling convention can be changed as follows:
n_pi_core lnv_core lnv_core.of_set_default_stdcall() // this is enabled by default lnv_core.of_set_default_cdecl() |
If the function prototype references to a custom type, the type must be declared before the prototype:
lnv_core.of_declare(" & typedef void *LPCITEMIDLIST, *LPITEMIDLIST; & typedef int (CALLBACK* BFFCALLBACK)(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData); & typedef struct _browseinfo { & HWND hwndOwner; & LPCITEMIDLIST pidlRoot; & LPTSTR pszDisplayName; /* Return display name of item selected. */ & LPCTSTR lpszTitle; /* text to go in the banner over the tree. */ & UINT ulFlags; /* Flags that control the return stuff */ & BFFCALLBACK lpfn; /* BrowseCallbackProc function pointer */ & LPARAM lParam; /* extra info that's passed back in callbacks */ & int iImage; /* output var: where to return the Image index. */ & } BROWSEINFO, *PBROWSEINFO, *LPBROWSEINFO; & ") lnv_SHBrowseForFolder = lnv_shell32.of_declare_method(& "LPITEMIDLIST SHBrowseForFolder(LPBROWSEINFO lpbi)") |
There is also an alternative way of declaring prototypes (especially when you have many prototypes). At first declare all prototypes in one call to n_pi_core.of_declare() separating them with semicolons. Then call n_pi_library.of_declare_method for each function but passing only the function name.
// predeclare lnv_core.of_declare(" & typedef void *LPCITEMIDLIST, *LPITEMIDLIST; & typedef int (CALLBACK* BFFCALLBACK)(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData); & typedef struct _browseinfo { & HWND hwndOwner; & LPCITEMIDLIST pidlRoot; & LPTSTR pszDisplayName; /* Return display name of item selected. */ & LPCTSTR lpszTitle; /* text to go in the banner over the tree. */ & UINT ulFlags; /* Flags that control the return stuff */ & BFFCALLBACK lpfn; /* BrowseCallbackProc function pointer */ & LPARAM lParam; /* extra info that's passed back in callbacks */ & int iImage; /* output var: where to return the Image index. */ & } BROWSEINFO, *PBROWSEINFO, *LPBROWSEINFO; & BOOL SHGetPathFromIDList(LPCITEMIDLIST pidl, LPTSTR pszPath); & LPITEMIDLIST SHBrowseForFolder(LPBROWSEINFO lpbi); & ") // reuse lnv_SHBrowseForFolder = lnv_shell32.of_declare_method("SHBrowseForFolder") lnv_SHGetPathFromIDList = lnv_shell32.of_declare_method("SHGetPathFromIDList") |
Note, you can mix type and prototype declarations provided you separate them with semicolons.
Using functions
Now, when we declared the prototypes we can call the functions.
To call a function you call n_pi_method.of_invoke() passing all parameters.
The return value is Any, and the actual return type depends on function declaration.
There are 9 overloads of this method with 0 up to 8 parameters. If you need more parameters,
then you call of_invoke_a() method which takes a reference Any as a result and an array of
Any as parameters.
Long ll_result ll_result = lnv_SendMessage.of_invoke(Handle(w_win), n_pi_winapi.WM_KEYDOWN, 9 /*Tab*/, 0) //or Boolean lb_ok Any la_result Any la_params[] la_params[1] = Handle(w_win) la_params[2] = n_pi_winapi.WM_KEYDOWN la_params[3] = 9 /*Tab*/ la_params[4] = 0 lb_ok = lnv_SendMessage.of_invoke_a(ref la_result, la_params[]) |
Working with reference (out) function parameters
PBInvoke supports retrieving parameters declared in C/C++ using * or & modifiers.
Unlike PowerScript, PBInvoke requires separate operations to retrieve returned reference
parameters after invocation. You can use the method n_mi_method.of_get_param(paramname)
to retrieve the value of the paramname.
Example:
//C++: // This sample function has the following semantics: // 1) If bufSize = 0 then bufSize is used to return the needed buffer size and buf is ignored. // 2) If bufSize != 0 then buf is assumed as allocated buffer of bufSize size // In this case buf is filled with a string value. void getString(char* buf, int& bufSize) { char * value = "test"; if (bufSize == 0) bufSize = strlen(value); else strncpy(buf, value, bufSize); } //PB lnv_getString = lnv_somelib.of_declare_method("void CDECL getString(char* buf, int bufSize)") String ls_ret Long ll_len //1: get buffer size lnv_getString.of_invoke(0 /*null string, ignored*/, 0 /* get size marker */) ll_len = lnv_getString.of_get_param("bufSize") //2: retrieve the string lnv_getString.of_invoke(Space(ll_len) /*allocate buffer of ll_len characters*/, ll_len) ls_ret = lnv_getString.of_get_param("buf") |
Calling C run-time (CRT) library functions
In order to call CRT functions they must be declared with CDECL modifier because
unlike C/C++, PBInvoke declares functions with STDCALL by default.
Example:
lnv_crt = lnv_core.of_declare_library("msvcrt.dll") lnv_strlen = lnv_crt.of_declare_method("int CDECL strlen(const char*s)") ll_len = lnv_strlen.of_invoke("test string") |
See also
© 2003-2011 Desta, Ltd. All rights reserved. | SupportDesk |