├── pbsrc ├── b.cmd ├── Samples │ ├── BrowseForFolder │ │ ├── bb.cmd │ │ ├── debug │ │ │ ├── 1 │ │ │ ├── fa.exe │ │ │ ├── aaaaa.exe │ │ │ ├── fa1.exe │ │ │ ├── pbinvoke.pbd │ │ │ ├── libPBInvoke.dll │ │ │ ├── browseforfolder.pbd │ │ │ └── browseforfolder_demo.pbd │ │ ├── pbinvoke.pbl │ │ ├── libPBInvoke.dll │ │ ├── 2054_EBrowseF.zip │ │ ├── browseforfolder.pbl │ │ ├── browseforfolder_demo.pbl │ │ ├── update.cmd │ │ ├── browseforfolder.pbt │ │ ├── readme.txt │ │ └── default.pbc │ ├── SetWindowHook │ │ ├── pbinvoke.pbl │ │ ├── customsaveas.pbl │ │ ├── libPBInvoke.dll │ │ ├── setwindowshookdemo.pbl │ │ ├── update.cmd │ │ ├── setwindowshookdemo.pbt │ │ ├── readme.txt │ │ └── default.pbc │ └── enumwindows │ │ ├── pbinvoke.pbl │ │ ├── enumwindows.pbl │ │ ├── libPBInvoke.dll │ │ ├── enumwindows.pbt │ │ └── update.cmd ├── tester │ └── tester.pbl ├── pbinvoke │ ├── pbinvoke.pbl │ ├── build_pbinvoke.pbl │ ├── build_pbinvoke.pbt │ └── default.pbc ├── tester.pbt ├── w.pbw └── default.pbc ├── src ├── types │ ├── BoolType.cpp │ ├── IntType.cpp │ ├── BoolType.h │ ├── VoidType.h │ ├── RefType.cpp │ ├── RefType.h │ ├── ShortType.h │ ├── ArrayType.h │ ├── Int64Type.h │ ├── DoubleType.h │ ├── FloatType.h │ ├── TypeFactory.h │ ├── FloatType.cpp │ ├── Int64Type.cpp │ ├── DoubleType.cpp │ ├── IntType.h │ ├── ArrayType.cpp │ ├── DataTypes.h │ ├── PointerType.h │ ├── PointerType.cpp │ ├── StringType.h │ ├── RawType.h │ ├── MethodType.h │ ├── RawType.cpp │ ├── TypeFactory.cpp │ ├── StructType.h │ ├── CharType.h │ ├── StringType.cpp │ └── CharType.cpp ├── version.rc ├── parser │ ├── CParser.output │ ├── Declaration.cpp │ ├── Declaration.h │ ├── PrototypeDeclaration.cpp │ ├── build_lexer.cmd │ ├── PrototypeDeclaration.h │ ├── build_parser.cmd │ ├── CParser.hlp.h │ ├── clexer.h │ ├── stack.hh │ ├── clexer.l │ ├── location.hh │ ├── position.hh │ ├── ASTNode.h │ └── ASTNode.cpp ├── StdAfx.cpp ├── MethodInstance.h ├── PBException.cpp ├── PBException.h ├── Objects │ ├── Structure.h │ └── Structure.cpp ├── resource.h ├── WinHooks.cpp ├── DLLMethodInstance.h ├── WinHooks.h ├── DLLMethodInstance.cpp ├── PBCallback.h ├── Compiler.h ├── MethodInstance.cpp ├── PBInvoke.def ├── libPBInvoke.cpp ├── DynCallback.h ├── StdAfx.h ├── Core.h ├── Compiler.cpp ├── PBCallback.cpp ├── CallbackData.cpp └── Runtime.h ├── develdoc ├── net.txt ├── packing.txt ├── types.txt ├── synopsis.txt ├── marshalling.txt └── value-semantics.txt ├── doc ├── pbinvoke_en.chm ├── build_help.cmd ├── license.html ├── help.hhk ├── genhelp │ ├── help.hhk │ ├── help.hhp │ ├── unsupported.html │ ├── winapi.html │ ├── handling-tchar.html │ ├── help.hhc │ ├── supported-data-types.html │ ├── quick-start-guide.html │ ├── handling-strings.html │ ├── index.html │ ├── license.html │ ├── style.css │ └── working-with-structures.html ├── _template_help.html ├── help.hhp ├── _template_site.html ├── doc.html ├── unsupported.html ├── winapi.html ├── handling-tchar.html ├── gen_help.pl ├── handling-strings.html ├── supported-data-types.html ├── quick-start-guide.html ├── help.hhc ├── index.html ├── working-with-structures.html ├── style.css └── working-with-callbacks.html ├── .gitignore └── projects ├── libPBInvoke_vc9 ├── build_all.cmd ├── DLLMethodAddr.cpp ├── postbuild.cmd ├── ReadMe.txt └── libPBInvoke.sln └── tester1 ├── tester1.cpp ├── stdafx.cpp ├── stdafx.h └── ReadMe.txt /pbsrc/b.cmd: -------------------------------------------------------------------------------- 1 | call pb9 2 | pbc -p default.pbc -b -------------------------------------------------------------------------------- /pbsrc/Samples/BrowseForFolder/bb.cmd: -------------------------------------------------------------------------------- 1 | pbc -p default.pbc -r -b -------------------------------------------------------------------------------- /src/types/BoolType.cpp: -------------------------------------------------------------------------------- 1 | #include "../stdafx.h" 2 | 3 | #include "BoolType.h" -------------------------------------------------------------------------------- /src/types/IntType.cpp: -------------------------------------------------------------------------------- 1 | #include "../stdafx.h" 2 | 3 | #include "IntType.h" -------------------------------------------------------------------------------- /src/version.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/src/version.rc -------------------------------------------------------------------------------- /develdoc/net.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/develdoc/net.txt -------------------------------------------------------------------------------- /develdoc/packing.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/develdoc/packing.txt -------------------------------------------------------------------------------- /develdoc/types.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/develdoc/types.txt -------------------------------------------------------------------------------- /doc/pbinvoke_en.chm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/doc/pbinvoke_en.chm -------------------------------------------------------------------------------- /develdoc/synopsis.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/develdoc/synopsis.txt -------------------------------------------------------------------------------- /develdoc/marshalling.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/develdoc/marshalling.txt -------------------------------------------------------------------------------- /pbsrc/tester/tester.pbl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/tester/tester.pbl -------------------------------------------------------------------------------- /src/parser/CParser.output: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/src/parser/CParser.output -------------------------------------------------------------------------------- /pbsrc/pbinvoke/pbinvoke.pbl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/pbinvoke/pbinvoke.pbl -------------------------------------------------------------------------------- /develdoc/value-semantics.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/develdoc/value-semantics.txt -------------------------------------------------------------------------------- /doc/build_help.cmd: -------------------------------------------------------------------------------- 1 | set hhc=C:\Usr\App2\MsHtmlHelp\hhc.exe 2 | perl gen_help.pl 3 | pushd genhelp 4 | %HHC% help.hhp 5 | popd -------------------------------------------------------------------------------- /pbsrc/pbinvoke/build_pbinvoke.pbl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/pbinvoke/build_pbinvoke.pbl -------------------------------------------------------------------------------- /pbsrc/Samples/SetWindowHook/pbinvoke.pbl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/SetWindowHook/pbinvoke.pbl -------------------------------------------------------------------------------- /pbsrc/Samples/enumwindows/pbinvoke.pbl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/enumwindows/pbinvoke.pbl -------------------------------------------------------------------------------- /pbsrc/Samples/BrowseForFolder/debug/fa.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/BrowseForFolder/debug/fa.exe -------------------------------------------------------------------------------- /pbsrc/Samples/BrowseForFolder/pbinvoke.pbl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/BrowseForFolder/pbinvoke.pbl -------------------------------------------------------------------------------- /pbsrc/Samples/enumwindows/enumwindows.pbl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/enumwindows/enumwindows.pbl -------------------------------------------------------------------------------- /pbsrc/Samples/enumwindows/libPBInvoke.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/enumwindows/libPBInvoke.dll -------------------------------------------------------------------------------- /pbsrc/Samples/BrowseForFolder/debug/aaaaa.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/BrowseForFolder/debug/aaaaa.exe -------------------------------------------------------------------------------- /pbsrc/Samples/BrowseForFolder/debug/fa1.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/BrowseForFolder/debug/fa1.exe -------------------------------------------------------------------------------- /pbsrc/Samples/BrowseForFolder/libPBInvoke.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/BrowseForFolder/libPBInvoke.dll -------------------------------------------------------------------------------- /pbsrc/Samples/SetWindowHook/customsaveas.pbl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/SetWindowHook/customsaveas.pbl -------------------------------------------------------------------------------- /pbsrc/Samples/SetWindowHook/libPBInvoke.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/SetWindowHook/libPBInvoke.dll -------------------------------------------------------------------------------- /pbsrc/Samples/BrowseForFolder/2054_EBrowseF.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/BrowseForFolder/2054_EBrowseF.zip -------------------------------------------------------------------------------- /pbsrc/Samples/BrowseForFolder/browseforfolder.pbl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/BrowseForFolder/browseforfolder.pbl -------------------------------------------------------------------------------- /pbsrc/Samples/BrowseForFolder/debug/pbinvoke.pbd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/BrowseForFolder/debug/pbinvoke.pbd -------------------------------------------------------------------------------- /pbsrc/Samples/SetWindowHook/setwindowshookdemo.pbl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/SetWindowHook/setwindowshookdemo.pbl -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .svn 2 | *.log 3 | *.aps 4 | *.obj 5 | *.user 6 | *.suo 7 | *.ncb 8 | *.opt 9 | *.plg 10 | Release 11 | Debug 12 | ReleaseDemo 13 | -------------------------------------------------------------------------------- /pbsrc/Samples/BrowseForFolder/debug/libPBInvoke.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/BrowseForFolder/debug/libPBInvoke.dll -------------------------------------------------------------------------------- /pbsrc/Samples/BrowseForFolder/browseforfolder_demo.pbl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/BrowseForFolder/browseforfolder_demo.pbl -------------------------------------------------------------------------------- /pbsrc/Samples/BrowseForFolder/debug/browseforfolder.pbd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/BrowseForFolder/debug/browseforfolder.pbd -------------------------------------------------------------------------------- /pbsrc/Samples/BrowseForFolder/debug/browseforfolder_demo.pbd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amoskovsky/pb-pbinvoke/HEAD/pbsrc/Samples/BrowseForFolder/debug/browseforfolder_demo.pbd -------------------------------------------------------------------------------- /doc/license.html: -------------------------------------------------------------------------------- 1 |
3 | 4 | Author: Anatoly Moskovsky <avm@sqlbatch.com> 5 | License: Public Domain 6 | 7 |8 | -------------------------------------------------------------------------------- /projects/libPBInvoke_vc9/build_all.cmd: -------------------------------------------------------------------------------- 1 | pushd %~dp0 2 | 3 | @rem set MS VC9 build environment 4 | @call vcv9 5 | 6 | devenv libPBInvoke.sln /build Release /project libPBInvoke 7 | 8 | popd -------------------------------------------------------------------------------- /projects/libPBInvoke_vc9/DLLMethodAddr.cpp: -------------------------------------------------------------------------------- 1 | #include "DLLMethodAddr.h" 2 | 3 | DLLMethodAddr::DLLMethodAddr(void) 4 | { 5 | } 6 | 7 | DLLMethodAddr::~DLLMethodAddr(void) 8 | { 9 | } 10 | -------------------------------------------------------------------------------- /src/parser/Declaration.cpp: -------------------------------------------------------------------------------- 1 | #include "../stdafx.h" 2 | #include "Declaration.h" 3 | 4 | IDeclaration::IDeclaration(void) 5 | { 6 | } 7 | 8 | IDeclaration::~IDeclaration(void) 9 | { 10 | } 11 | -------------------------------------------------------------------------------- /pbsrc/Samples/SetWindowHook/update.cmd: -------------------------------------------------------------------------------- 1 | set root=..\..\.. 2 | set vcdir=%root%\projects\libPBInvoke_vc8 3 | set pbdir=..\.. 4 | 5 | 6 | copy %vcdir%\ReleaseDemo\libPBInvoke.dll /y 7 | copy %pbdir%\PbInvoke\PbInvoke.pbl /y -------------------------------------------------------------------------------- /pbsrc/Samples/enumwindows/enumwindows.pbt: -------------------------------------------------------------------------------- 1 | Save Format v3.0(19990112) 2 | @begin Projects 3 | @end; 4 | appname "enumwindowsapp"; 5 | applib "enumwindows.pbl"; 6 | LibList "enumwindows.pbl;pbinvoke.pbl"; 7 | type "pb"; 8 | -------------------------------------------------------------------------------- /pbsrc/Samples/enumwindows/update.cmd: -------------------------------------------------------------------------------- 1 | set root=..\..\.. 2 | set vcdir=%root%\projects\libPBInvoke_vc8 3 | set pbdir=..\.. 4 | 5 | 6 | copy %vcdir%\ReleaseDemo\libPBInvoke.dll /y 7 | copy %pbdir%\PbInvoke\PbInvoke.pbl /y -------------------------------------------------------------------------------- /pbsrc/pbinvoke/build_pbinvoke.pbt: -------------------------------------------------------------------------------- 1 | Save Format v3.0(19990112) 2 | @begin Projects 3 | @end; 4 | appname "build_pbinvoke"; 5 | applib "build_pbinvoke.pbl"; 6 | LibList "build_pbinvoke.pbl;pbinvoke.pbl"; 7 | type "pb"; 8 | -------------------------------------------------------------------------------- /pbsrc/Samples/BrowseForFolder/update.cmd: -------------------------------------------------------------------------------- 1 | set root=..\..\.. 2 | set vcdir=%root%\projects\libPBInvoke_vc8 3 | set pbdir=..\.. 4 | 5 | 6 | copy %vcdir%\ReleaseDemo\libPBInvoke.dll /y 7 | copy %pbdir%\PbInvoke\PbInvoke.pbl /y -------------------------------------------------------------------------------- /pbsrc/tester.pbt: -------------------------------------------------------------------------------- 1 | Save Format v3.0(19990112) 2 | @begin Projects 3 | @end; 4 | appname "a_tester"; 5 | applib "tester\\tester.pbl"; 6 | LibList "tester\\tester.pbl;pbinvoke\\pbinvoke.pbl;tester\\debug.pbl"; 7 | type "pb"; 8 | -------------------------------------------------------------------------------- /src/types/BoolType.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RawType.h" 4 | 5 | class BoolType: public RawType { 6 | public: 7 | BoolType() : RawType("bool", sizeof(bool)) {} 8 | virtual int getPBTypeClass() { return TC_BOOL_TYPE; } 9 | }; 10 | -------------------------------------------------------------------------------- /src/types/VoidType.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RawType.h" 4 | 5 | class VoidType: public RawType { 6 | public: 7 | VoidType() : RawType("void", sizeof(char)) {} 8 | virtual int getPBTypeClass() { return TC_VOID_TYPE; } 9 | }; 10 | -------------------------------------------------------------------------------- /doc/help.hhk: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
Only P-code (PBD) builds are supported. 11 | 12 |
WinAPI is most widely used as external functions in PowerBuilder. 4 | 5 |
PBInvoke provides an object with many WinAPI constants, n_pi_winapi.
7 | The constants can be used without instantiation of the object via syntax:
8 |
Example:
13 |
22 | TCHAR, TSTR, LPTSTR, LPCTSTR, WCHAR, WSTR, LPWSTR, LPCWSTR, CHAR, STR, LPSTR, LPCSTR, BYTE,BOOL, HWND, HINSTANCE, 23 | LPBOOL, INT, UINT, UINT_PTR, DWORD, LPDWORD, HANDLE, LRESULT, LONG, ULONG, WPARAM, LPARAM, HMODULE, HHOOK, 24 | WORD, LPWORD, SHORT, USHORT, VOID, PVOID, LPVOID, LPCVOID, FLOAT, LPSECURITY_ATTRIBUTES 25 |26 | 27 |
When at least one of parameter types or return type of a declared DLL function is based on TCHAR type, 3 | then PBInvoke automatically appends a suffix "A" or "W" to the function's name and treats TCHAR as char or wchar_t 4 | depending on PowerBuilder version. 5 |
In Unicode versions (PB10 and above), the "W" suffix is appended and TCHAR=wchar_t, 6 |
In ANSI version (PB9 and below) , the "A" suffix is appended and TCHAR=char. 7 | 8 |
If the function with the suffix does not exist in the DLL, then PBInvoke tries to find the function without the prefix. 9 | 10 |
Example:
11 |
'. colorize($2). ''!gsie; 43 | 44 | # remove 1st empty line in
45 | $text =~ s/(\]*\>)\s+/$1/gsi;
46 |
47 | mkpath($outDir);
48 | WriteFile("$outDir/$file", $text);
49 | }
50 |
51 | sub colorize {
52 | my ($text) = @_;
53 | $text =~ s!(//.*)$!$1!gm;
54 | $text =~ s!(/\*.*?\*/)!$1!gms;
55 | return $text;
56 | }
--------------------------------------------------------------------------------
/projects/tester1/ReadMe.txt:
--------------------------------------------------------------------------------
1 | ========================================================================
2 | CONSOLE APPLICATION : tester1 Project Overview
3 | ========================================================================
4 |
5 | AppWizard has created this tester1 application for you.
6 |
7 | This file contains a summary of what you will find in each of the files that
8 | make up your tester1 application.
9 |
10 |
11 | tester1.vcproj
12 | This is the main project file for VC++ projects generated using an Application Wizard.
13 | It contains information about the version of Visual C++ that generated the file, and
14 | information about the platforms, configurations, and project features selected with the
15 | Application Wizard.
16 |
17 | tester1.cpp
18 | This is the main application source file.
19 |
20 | /////////////////////////////////////////////////////////////////////////////
21 | Other standard files:
22 |
23 | StdAfx.h, StdAfx.cpp
24 | These files are used to build a precompiled header (PCH) file
25 | named tester1.pch and a precompiled types file named StdAfx.obj.
26 |
27 | /////////////////////////////////////////////////////////////////////////////
28 | Other notes:
29 |
30 | AppWizard uses "TODO:" comments to indicate parts of the source code you
31 | should add to or customize.
32 |
33 | /////////////////////////////////////////////////////////////////////////////
34 |
--------------------------------------------------------------------------------
/src/types/RawType.h:
--------------------------------------------------------------------------------
1 |
2 | #pragma once
3 |
4 | #include "BaseType.h"
5 |
6 | // Generic plain C type
7 | class RawType: public BaseType
8 | {
9 | private:
10 | protected:
11 | RawType(const string &typeSignature, size_t sizeOf = sizeof(DWORD));
12 | size_t m_sizeOf;
13 | string m_typeSignature;
14 |
15 | void setSizeOf(size_t sizeOf) { m_sizeOf = sizeOf; }
16 | public:
17 | virtual int getSizeOf() { return m_sizeOf; }
18 | //virtual void setData(ExecutionContext *context, BYTE * cBuf, BYTE * pbBuf);
19 | //virtual void getData(ExecutionContext *context, BYTE * cBuf, BYTE *pbBuf);
20 | virtual void executeMethod(ExecutionContext *context, DWORD methodAddr, BYTE * retBuf, BYTE *paramBuf, int paramBufSize, bool isStdCall);
21 | virtual int getItemOffset(int itemIndex) {return 0;}
22 | virtual void allocateBuffer(ExecutionContext *context, BYTE * &buf, int itemCount = 1);
23 | virtual string getTypeSignature(const string& pointerSig = "");
24 | virtual void setZeroData(ExecutionContext *context, BYTE * buf);
25 | virtual int getExplicitAlign() { return 0; }
26 | virtual int getAlign() { return getSizeOf(); }
27 | // unimplemented (throw)
28 | virtual void getArrayData(ExecutionContext *context, BYTE * cBuf, BYTE *pbBuf, int &arrayLen, DataCharset charset);
29 | virtual void setArrayData(ExecutionContext *context, BYTE * &cBuf, BYTE *pbBuf, int arrayLen, DataCharset charset);
30 | virtual size_t strLen(ExecutionContext *context, BYTE * buf, int arrayLen, DataCharset charset) { return 0;}
31 | };
32 |
--------------------------------------------------------------------------------
/projects/libPBInvoke_vc9/ReadMe.txt:
--------------------------------------------------------------------------------
1 | ========================================================================
2 | DYNAMIC LINK LIBRARY : libPBInvoke
3 | ========================================================================
4 |
5 |
6 | AppWizard has created this libPBInvoke DLL for you.
7 |
8 | This file contains a summary of what you will find in each of the files that
9 | make up your libPBInvoke application.
10 |
11 | libPBInvoke.dsp
12 | This file (the project file) contains information at the project level and
13 | is used to build a single project or subproject. Other users can share the
14 | project (.dsp) file, but they should export the makefiles locally.
15 |
16 | libPBInvoke.cpp
17 | This is the main DLL source file.
18 |
19 | When created, this DLL does not export any symbols. As a result, it
20 | will not produce a .lib file when it is built. If you wish this project
21 | to be a project dependency of some other project, you will either need to
22 | add code to export some symbols from the DLL so that an export library
23 | will be produced, or you can check the "doesn't produce lib" checkbox in
24 | the Linker settings page for this project.
25 |
26 | /////////////////////////////////////////////////////////////////////////////
27 | Other standard files:
28 |
29 | StdAfx.h, StdAfx.cpp
30 | These files are used to build a precompiled header (PCH) file
31 | named libPBInvoke.pch and a precompiled types file named StdAfx.obj.
32 |
33 |
34 | /////////////////////////////////////////////////////////////////////////////
35 | Other notes:
36 |
37 | AppWizard uses "TODO:" to indicate parts of the source code you
38 | should add to or customize.
39 |
40 |
41 | /////////////////////////////////////////////////////////////////////////////
42 |
--------------------------------------------------------------------------------
/projects/libPBInvoke_vc9/libPBInvoke.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 10.00
3 | # Visual Studio 2008
4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libPBInvoke", "libPBInvoke.vcproj", "{9585C981-9C24-4AAC-A7CA-43D2844F02B3}"
5 | EndProject
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tester1", "..\tester1\tester1.vcproj", "{7E21D89F-5276-45A4-91E4-61D5C170FF0E}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Win32 = Debug|Win32
11 | Release|Win32 = Release|Win32
12 | ReleaseDemo|Win32 = ReleaseDemo|Win32
13 | EndGlobalSection
14 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
15 | {9585C981-9C24-4AAC-A7CA-43D2844F02B3}.Debug|Win32.ActiveCfg = Debug|Win32
16 | {9585C981-9C24-4AAC-A7CA-43D2844F02B3}.Debug|Win32.Build.0 = Debug|Win32
17 | {9585C981-9C24-4AAC-A7CA-43D2844F02B3}.Release|Win32.ActiveCfg = Release|Win32
18 | {9585C981-9C24-4AAC-A7CA-43D2844F02B3}.Release|Win32.Build.0 = Release|Win32
19 | {9585C981-9C24-4AAC-A7CA-43D2844F02B3}.ReleaseDemo|Win32.ActiveCfg = ReleaseDemo|Win32
20 | {9585C981-9C24-4AAC-A7CA-43D2844F02B3}.ReleaseDemo|Win32.Build.0 = ReleaseDemo|Win32
21 | {7E21D89F-5276-45A4-91E4-61D5C170FF0E}.Debug|Win32.ActiveCfg = Debug|Win32
22 | {7E21D89F-5276-45A4-91E4-61D5C170FF0E}.Debug|Win32.Build.0 = Debug|Win32
23 | {7E21D89F-5276-45A4-91E4-61D5C170FF0E}.Release|Win32.ActiveCfg = Release|Win32
24 | {7E21D89F-5276-45A4-91E4-61D5C170FF0E}.Release|Win32.Build.0 = Release|Win32
25 | {7E21D89F-5276-45A4-91E4-61D5C170FF0E}.ReleaseDemo|Win32.ActiveCfg = ReleaseDemo|Win32
26 | {7E21D89F-5276-45A4-91E4-61D5C170FF0E}.ReleaseDemo|Win32.Build.0 = ReleaseDemo|Win32
27 | EndGlobalSection
28 | GlobalSection(SolutionProperties) = preSolution
29 | HideSolutionNode = FALSE
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/doc/genhelp/unsupported.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Unsupported and unimplemented PBInvoke features
4 |
5 |
6 |
7 |
8 |
9 | PBInvoke documentation. Version 1.X. Visit http://sqlbatch.com/pbinvoke for updates.
10 |
11 | Unsupported and unimplemented PBInvoke features
12 |
13 |
14 | Unsupported usage of PBInvoke
15 | The following modes may (or may not) work but are not supported officially.
16 | Using PBInvoke with PowerBuilder 5 (PBInvoke supports only PB 6 and above)
17 | Machine code targets (DLL builds)
18 | Web and .Net targets (WinForm, WebForm, JSP, Web services ...)
19 |
20 | Only P-code (PBD) builds are supported.
21 |
22 |
Unimplemented features
23 |
24 | The following features will be implemented in one of the future versions of PBInvoke.
25 |
26 | .Net interop (calls to external .Net classes, not under .Net targets)
27 | Java interop (calls to external Java classes)
28 | Calls via function pointers (now only named DLL functions and PB callbacks can be called)
29 | Double, float as a return type for callbacks. However pointers to such types are supported as a return type.
30 | Any struct of size of more than 4 bytes as a return type for any function.
31 | However pointers to such structures are supported as a return type.
32 | C++ classes, structures inherited from other structures.
33 |
34 | See also
35 | Supported data types
36 | WinAPI constants and types
37 |
38 |
39 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/doc/genhelp/winapi.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | WinAPI constants and types
4 |
5 |
6 |
7 |
8 |
9 | PBInvoke documentation. Version 1.X. Visit http://sqlbatch.com/pbinvoke for updates.
10 |
11 | WinAPI constants and types
12 |
13 | WinAPI is most widely used as external functions in PowerBuilder.
14 |
15 |
WinAPI constants
16 | PBInvoke provides an object with many WinAPI constants, n_pi_winapi.
17 | The constants can be used without instantiation of the object via syntax:
18 |
n_pi_winapi.CONSTANT_NAME
19 |
20 |
21 | Example:
22 |
lnv_SendMessage.of_invoke(Handle(w_win), n_pi_winapi.WM_KEYDOWN, 9 /*Tab*/, 0)
23 |
24 |
25 |
26 | WinAPI types
27 |
28 | PBInvoke has built-in support for the following WinAPI types:
29 |
30 | TCHAR, TSTR, LPTSTR, LPCTSTR, WCHAR, WSTR, LPWSTR, LPCWSTR, CHAR, STR, LPSTR, LPCSTR, BYTE,BOOL, HWND, HINSTANCE,
31 | LPBOOL, INT, UINT, UINT_PTR, DWORD, LPDWORD, HANDLE, LRESULT, LONG, ULONG, WPARAM, LPARAM, HMODULE, HHOOK,
32 | WORD, LPWORD, SHORT, USHORT, VOID, PVOID, LPVOID, LPCVOID, FLOAT, LPSECURITY_ATTRIBUTES
33 |
34 |
35 | See also
36 | Calling DLL functions using PBInvoke
37 | Handling TCHAR and TSTR. Unicode/ANSI function name suffixes
38 | Supported data types
39 | Working with callbacks
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/src/libPBInvoke.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "stdafx.h"
3 | #include "types/DataTypes.h"
4 | #include "Compiler.h"
5 | #include "Runtime.h"
6 | #include "types/TypeFactory.h"
7 | #include "Core.h"
8 | //#include
9 | //#pragma comment(lib, "Psapi.lib")
10 | //#include
11 |
12 | #define IMP __declspec(dllimport)
13 | #define A __declspec(align(4))
14 |
15 | //typedef int iii;
16 | //struct S {char a;};
17 |
18 | //int unsigned a;
19 | //int IMP A unsigned aa;
20 | //int unsigned IMP aaa;
21 | //IMP unsigned b;
22 | //unsigned IMP int bb;
23 | //iii IMP c;
24 | //IMP iii cc;
25 | //S IMP d;
26 | //IMP S A dd;
27 | //IMP struct {int b;} e;
28 | // struct {int b;} IMP ee;
29 | //unsigned __int8 f;
30 | //const int al = __alignof(dd);
31 | //signed unsigned g;
32 |
33 | int ff[][2][2][2];
34 |
35 | TCHAR * CUtil::logFile = TEXT("libPbInvoke.log");
36 |
37 |
38 | BOOL APIENTRY DllMain( HANDLE hModule,
39 | DWORD ul_reason_for_call,
40 | LPVOID lpReserved
41 | )
42 | {
43 | switch (ul_reason_for_call)
44 | {
45 | case DLL_PROCESS_ATTACH:
46 | truncatelog();
47 | dprintf("DllMain\n");
48 | #ifdef _DEBUG
49 | dprintf(" DEBUG DLL\n");
50 | #else
51 | dprintf(" RELEASE DLL\n");
52 | #endif
53 | Core::resetState();
54 | break;
55 | case DLL_THREAD_ATTACH:
56 | case DLL_THREAD_DETACH:
57 | case DLL_PROCESS_DETACH:
58 | break;
59 | }
60 | return TRUE;
61 | }
62 |
63 |
64 |
65 | /// debug
66 |
67 | BOOL PBCALL core_setAppHandle(DWORD handle);
68 |
69 | void debug() {
70 | //FN fn;
71 | //fn();
72 | //void a(void i);
73 | //aaa a;
74 | //string exe = "pb600.012420654296875";
75 | //printf("md5=%s\n", CRC::md5(exe.c_str(), exe.size()).c_str());
76 | //return;
77 | try {
78 | CoreInstance.setUnicode(false);
79 | core_setAppHandle(1);
80 | Compiler cc;
81 | string name = cc.compileAsC("int fn(int a[]); struct S{ char a; int b[]; }");
82 | dprintf("last name='%s'\n", name.c_str());
83 | }
84 | catch(RuntimeException &e) {
85 | printf("'%s'\n", e.getMessage().c_str());
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/types/MethodType.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "RawType.h"
4 | #include
5 | using namespace stdext;
6 |
7 |
8 | class IndexedMethodType: public RawType {
9 | public:
10 | IndexedMethodType(Type returnType, vector ¶mTypes, bool isStdCall = true, DWORD methodAddr = 0);
11 | virtual ~IndexedMethodType();
12 | virtual int getPBTypeClass() { return TC_METHOD_TYPE; }
13 | inline vector &getParamTypes() { return m_paramTypes; }
14 | inline Type &getReturnType() { return m_returnType; }
15 | inline bool isStdCall() { return m_isStdCall; }
16 | inline void setStdCall(bool isStdCall) { m_isStdCall = isStdCall; }
17 | virtual string getTypeSignature(const string& pointerSig = "");
18 | virtual bool hasTChar();
19 | private:
20 | vector m_paramTypes;
21 | Type m_returnType;
22 | bool m_isStdCall;
23 | Library * m_library;
24 | string m_methodName;
25 | DWORD m_methodAddr;
26 | static string buildTypeSignature(const string &pointerName, const string &methodName, Type returnType, vector ¶mTypes, bool isStdCall = true);
27 |
28 | };
29 |
30 |
31 | class MethodType: public RawType {
32 | public:
33 | MethodType(Type returnType, vector ¶ms, bool isStdCall = true);
34 | virtual int getPBTypeClass() { return TC_METHOD_TYPE; }
35 | inline vector &getParams() { return m_params; }
36 | inline Type &getReturnType() { return m_indexedMethodType->getReturnType(); }
37 | inline bool isStdCall() { return m_indexedMethodType->isStdCall(); }
38 | inline void setStdCall(bool isStdCall) {m_indexedMethodType->setStdCall(isStdCall); }
39 | virtual string getTypeSignature(const string& pointerSig = "");
40 | virtual bool isCompatible(BaseType* type);
41 | virtual int getItemIndex(const string& itemName);
42 | virtual bool hasTChar() { return m_indexedMethodType->hasTChar(); }
43 | private:
44 | IndexedMethodType *m_indexedMethodType;
45 | vector m_params;
46 | string buildTypeSignature(const string &pointerName);
47 | hash_map m_paramNameMap;
48 | void init();
49 | };
50 |
51 |
--------------------------------------------------------------------------------
/doc/genhelp/handling-tchar.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Handling TCHAR and TSTR. Unicode/ANSI function name suffixes
4 |
5 |
6 |
7 |
8 |
9 | PBInvoke documentation. Version 1.X. Visit http://sqlbatch.com/pbinvoke for updates.
10 |
11 | Handling TCHAR and TSTR. Unicode/ANSI function name suffixes
12 | When at least one of parameter types or return type of a declared DLL function is based on TCHAR type,
13 | then PBInvoke automatically appends a suffix "A" or "W" to the function's name and treats TCHAR as char or wchar_t
14 | depending on PowerBuilder version.
15 |
In Unicode versions (PB10 and above), the "W" suffix is appended and TCHAR=wchar_t,
16 |
In ANSI version (PB9 and below) , the "A" suffix is appended and TCHAR=char.
17 |
18 |
If the function with the suffix does not exist in the DLL, then PBInvoke tries to find the function without the prefix.
19 |
20 |
Example:
21 |
lnv_CreateDirectory = lnv_kernel32.of_declare_method(&
22 | "BOOL CreateDirectory(LPCTSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes);")
23 | // The exact meaning of the declaration above depends on PB version:
24 | // in PB9: BOOL CreateDirectoryA(const char *lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
25 | // in PB10: BOOL CreateDirectoryW(const wchar_t *lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
26 |
27 |
28 | See also
29 | Handling strings (char*, wchar_t*)
30 | WinAPI constants and types
31 | Working with callbacks
32 |
33 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/DynCallback.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 |
8 | #define DYNCALLBACKVERSION "1.4.0"
9 | /*
10 | history
11 |
12 | 1.4.0
13 | - added method for calling __int64 functions
14 |
15 | 1.3.0
16 | - added method for calling float functions
17 |
18 | 1.2.0
19 | - added methods for calling functions dynamically
20 |
21 | 1.1.0
22 | - added calling convention arg (stdCall=true) to ctor
23 |
24 | 1.0.1
25 | - disabled optimization
26 | - added dumpThunk debug method
27 |
28 | 1.0.0
29 | - initial version
30 | */
31 |
32 |
33 | class InvalidCallbackTemplateException {
34 | public:
35 | std::string msg;
36 | InvalidCallbackTemplateException(const std::string &msg) {
37 | this->msg = msg;
38 | }
39 |
40 | };
41 |
42 | struct Callback {
43 | virtual int CALLBACK callback() = 0;
44 | virtual ~Callback() {}
45 | };
46 |
47 | class CallbackData : public Callback
48 | {
49 | private:
50 | enum {
51 | THIS_MARKER = 0x45454545,
52 | CALLBACK_MARKER = 0x23232323,
53 | };
54 | std::vector m_thunk;
55 | static int CALLBACK thunk_templ(int dummy);
56 | void dump();
57 | void adjustConstant(DWORD marker, DWORD newValue);
58 | static int CALLBACK staticCallback(CallbackData * thisPtr, DWORD *argsPtr);
59 | protected:
60 | int m_argc;
61 | DWORD *m_argsPtr;
62 | public:
63 | virtual ~CallbackData();
64 | CallbackData(int argc, bool stdCall = true);
65 | DWORD getCallbackAddr();
66 |
67 | int runCallback();
68 | int runCallback(int arg1);
69 | int runCallback(int arg1, int arg2);
70 |
71 | std::string dumpThunk();
72 |
73 | // interface Callback
74 | virtual int CALLBACK callback();
75 | };
76 |
77 |
78 | DWORD runDynamicMethod(DWORD addr, DWORD *argv, int argc, bool isStdCall = true);
79 |
80 | double runDynamicDoubleMethod(DWORD addr, DWORD *argv, int argc, bool isStdCall = true);
81 | float runDynamicFloatMethod(DWORD addr, DWORD *argv, int argc, bool isStdCall = true);
82 | __int64 runDynamicInt64Method(DWORD addr, DWORD *argv, int argc, bool isStdCall = true);
83 |
--------------------------------------------------------------------------------
/src/types/RawType.cpp:
--------------------------------------------------------------------------------
1 | #include "../stdafx.h"
2 |
3 | #include "RawType.h"
4 | #include "../DynCallback.h"
5 | #include "../Runtime.h"
6 | #include "../PBException.h"
7 |
8 |
9 | RawType::RawType(const string &typeSignature, size_t sizeOf)
10 | : m_typeSignature(typeSignature)
11 | , m_sizeOf(sizeOf)
12 | {
13 | }
14 |
15 |
16 | //void RawType::setData(ExecutionContext *context, BYTE * cBuf, BYTE * pbBuf)
17 | //{
18 | // dprintf("+RawType::setData cBuf=%p, pbBuf=%p\n", cBuf, pbBuf);
19 | // memcpy(cBuf, pbBuf, m_sizeOf);
20 | // dprintf("-RawType::setData\n");
21 | //}
22 | //
23 | //
24 | //void RawType::getData(ExecutionContext *context, BYTE * cBuf, BYTE *pbBuf)
25 | //{
26 | // memcpy(pbBuf, cBuf, m_sizeOf);
27 | //}
28 |
29 | void RawType::executeMethod(ExecutionContext *context, DWORD methodAddr, BYTE * retBuf, BYTE *paramBuf, int paramBufSize, bool isStdCall)
30 | {
31 | dprintf("+RawType::executeMethod paramBuf=%p, paramBufSize=%i\n", paramBuf, paramBufSize);
32 | dprintf("+RawType::executeMethod paramBuf data=%p %p\n", ((DWORD *)paramBuf)[0], ((DWORD *)paramBuf)[1]);
33 | DWORD *argv = (DWORD *)paramBuf;
34 | int argc = paramBufSize / sizeof(DWORD);
35 | *(DWORD*)retBuf = runDynamicMethod(methodAddr, argv, argc, isStdCall);
36 | dprintf("-RawType::executeMethod");
37 | }
38 |
39 | void RawType::getArrayData(ExecutionContext *context, BYTE * cBuf, BYTE *pbBuf, int &arrayLen, DataCharset charset)
40 | {
41 | //throw RuntimeException(context, "getStringData() is not implemented for this type");
42 | memcpy(pbBuf, cBuf, getSizeOf() * arrayLen);
43 |
44 | }
45 |
46 | void RawType::setArrayData(ExecutionContext *context, BYTE * &cBuf, BYTE *pbBuf, int arrayLen, DataCharset charset)
47 | {
48 | if (cBuf == NULL) {
49 | allocateBuffer(context, /*out*/ cBuf, arrayLen);
50 | }
51 | memcpy(cBuf, pbBuf, getSizeOf() * arrayLen);
52 | }
53 |
54 | void RawType::allocateBuffer(ExecutionContext *context, BYTE * &buf, int itemCount)
55 | {
56 | int byteSize = getSizeOf() * itemCount;
57 | buf = context->allocateBuffer(byteSize, getAlign());
58 | if (buf != NULL)
59 | memset(buf, 0, byteSize);
60 | }
61 |
62 | void RawType::setZeroData(ExecutionContext *context, BYTE * buf)
63 | {
64 | if (buf != NULL)
65 | memset(buf, 0, m_sizeOf);
66 | }
67 |
68 |
69 | string RawType::getTypeSignature(const string& pointerSig)
70 | {
71 | if (pointerSig != "")
72 | return m_typeSignature + pointerSig;
73 | else
74 | return m_typeSignature;
75 | }
76 |
--------------------------------------------------------------------------------
/src/StdAfx.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #pragma warning(disable: 4786)
3 | #pragma warning(disable: 4800)
4 | #pragma warning(disable: 4996)
5 |
6 | //#define _DEBUG_MSG
7 |
8 | #define NOMINMAX
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | using namespace std;
16 |
17 |
18 | #define DLLEXPORT __declspec(dllexport)
19 | #define PBCALL __stdcall
20 |
21 |
22 | #ifdef _DEBUG_MSG
23 | #define dprintf CUtil::putMsg
24 | #define dwprintf CUtil::wputMsg
25 | #define truncatelog CUtil::deleteLog
26 | #else
27 | #define dprintf if (0) CUtil::nullMsg
28 | #define dwprintf if (0) CUtil::wnullMsg
29 | #define truncatelog if (0) CUtil::deleteLog
30 | #endif
31 |
32 | #define IsUnicode(marker) (marker[1] == 0)
33 |
34 | class CUtil
35 | {
36 | public:
37 | static TCHAR * logFile;
38 | static TCHAR * clone(TCHAR * src);
39 | CUtil();
40 | virtual ~CUtil();
41 |
42 | static void deleteLog() {
43 | _tunlink(logFile);
44 | }
45 | static void putMsg(TCHAR * fmt, ...) {
46 | FILE *f = openLog();
47 | va_list marker;
48 | va_start( marker, fmt );
49 | _vftprintf(f, fmt, marker);
50 | _vtprintf(fmt, marker);
51 | if (fmt[0]==TEXT('-') ) {
52 | _tprintf("\n\n");
53 | _ftprintf(f, "\n\n");
54 | }
55 | va_end( marker );
56 | closeLog(f);
57 | }
58 | static void wputMsg(wchar_t * fmt, ...) {
59 | FILE *f = openLog();
60 | va_list marker;
61 | va_start( marker, fmt );
62 | vfwprintf(f, fmt, marker);
63 | va_end( marker );
64 | closeLog(f);
65 | }
66 | static inline void nullMsg(TCHAR * fmt, ...) {
67 | }
68 | static inline void wnullMsg(wchar_t * fmt, ...) {
69 | }
70 | static inline char * toString(int v) {
71 | static char buf[20];
72 | sprintf(buf, "%i", v);
73 | return buf;
74 | }
75 | static wstring toLower(const wstring &s) {
76 | wstring res = s;
77 | _wcslwr((wchar_t*)res.c_str());
78 | return res;
79 | }
80 | static string toLower(const string &s) {
81 | string res = s;
82 | strlwr((char*)res.c_str());
83 | return res;
84 | }
85 | private:
86 | static FILE * openLog() {
87 | FILE *f = _tfopen(logFile, TEXT("at+"));
88 | #ifdef _UNICODE
89 | //_ftprintf(f, TEXT("W>"));
90 | #else
91 | //_ftprintf(f, TEXT("A>"));
92 | #endif
93 | return f;
94 | }
95 | static void closeLog(FILE*f) {
96 | if (f)
97 | fclose(f);
98 | }
99 |
100 |
101 |
102 | };
103 |
104 |
--------------------------------------------------------------------------------
/doc/handling-strings.html:
--------------------------------------------------------------------------------
1 | Handling strings (char*, wchar_t*)
2 |
3 | Charset conversion
4 | When a function parameter is declared as char* or wchar_t*,
5 | PBInvoke automatically converts the charset of the string if PowerBuilder
6 | native strings have different charset.
7 |
8 |
9 | lnv_fn1 = lnv_somelib.of_declare_method("int strlen(char*s)")
10 | lnv_fn2 = lnv_somelib.of_declare_method("int wcslen(wchar_t*s)")
11 |
12 | // in PB9
13 | ll_len = lnv_fn1.of_invoke("test") // no conversion, both caller and callee are ANSI
14 | ll_len = lnv_fn2.of_invoke("test") // implicitly converts the string from ANSI to Unicode
15 |
16 | // in PB10+
17 | ll_len = lnv_fn1.of_invoke("test") // implicitly converts the string from Unicode to ANSI
18 | ll_len = lnv_fn2.of_invoke("test") // no conversion, both caller and callee are Unicode
19 |
20 |
21 | Combinations of char and wchar_t in one function are supported as well.
22 |
23 | lnv_fn = lnv_somelib.of_declare_method("void some_fn(char*s1, wchar_t*s2)")
24 | // in PB9
25 | lb_res = lnv_fn.of_invoke("test1", "test2") // "test1" - no conversion
26 | // "test2" - ANSI -> Unicode
27 | // in PB10 - vice versa
28 |
29 |
30 |
31 | Special handling is performed for TCHAR based parameters.
32 | See Handling TCHAR and TSTR. Unicode/ANSI function name suffixes.
33 |
34 |
Passing numeric address of string instead of string
35 |
36 | If you got an address of some string as a numeric value, for example as a result of calling another function,
37 | you can pass this number instead of a PB string value. Passing 0 or null value gives NULL string pointers.
38 | If a numeric address is passed instead of a string then no charset conversion is done.
39 |
40 |
41 | lnv_fn = lnv_somelib.of_declare_method("void some_fn(char*s)")
42 |
43 | lnv_s = lnv_core.of_create_value_of(LPSTR) // LPSTR is char* in WinAPI
44 | lnv_fn.of_invoke(lnv_s.of_get_ptr()) // of_get_ptr() gets the numeric value of the pointer
45 |
46 | // incorrect use:
47 | lnv_s = lnv_core.of_create_value_of(LPWSTR) // LPWSTR is wchar_t* in WinAPI
48 | lnv_fn.of_invoke(lnv_s.of_get_ptr()) // WRONG! because no conversion is done,
49 | // and the function expects char* and not wchar_t*
50 | // passing NULL
51 | lnv_fn.of_invoke(0)
52 | SetNull(ls_null)
53 | lnv_fn.of_invoke(ls_null)
54 |
55 |
56 |
57 |
See also
58 | Handling TCHAR and TSTR. Unicode/ANSI function name suffixes
59 |
60 |
--------------------------------------------------------------------------------
/doc/supported-data-types.html:
--------------------------------------------------------------------------------
1 | Supported data types
2 |
3 | Simple types
4 |
5 | The folowing C/C++ types are supported
6 |
7 | - short, int, long, longlong and their signed/unsigned versions
8 |
- char, wchar_t - character types
9 |
- double, float
10 |
- void - return type for procedures
11 |
12 |
13 | Structure types
14 |
15 |
16 | - struct - a record of fields of any type
17 |
- union - a struct whose fields share the same memory.
18 |
19 | For structs/unions the packing attribute can be specified. See the reference.
20 |
21 | Pointer types
22 |
23 | - pointer to type (*)
24 |
- reference to type (&)
25 |
26 |
27 |
28 | Function prototypes
29 |
30 | - external function prototype
31 |
- pointer to function (callback).
32 |
33 | For functions and function pointers a few attributes are supported. See the reference.
34 |
35 |
36 | User-defined types
37 | A developer can declare any custom C type using one or more C typedef operators separated by ";" and
38 | passed as a string to n_pi_core.of_declare(), as follows:
39 |
40 | n_pi_core lnv_core
41 | lnv_core.of_declare(" &
42 | typedef void *LPCITEMIDLIST, *LPITEMIDLIST; &
43 | typedef int (CALLBACK* BFFCALLBACK)(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData); &
44 | ")
45 |
46 |
47 |
48 | WinAPI types
49 | The most widely used WinAPI types are predeclared in PBInvoke.
50 |
These are:
51 | TCHAR, TSTR, LPTSTR, LPCTSTR, WCHAR, WSTR, LPWSTR, LPCWSTR, CHAR, STR, LPSTR, LPCSTR, BYTE,BOOL, HWND, HINSTANCE,
52 | LPBOOL, INT, UINT, UINT_PTR, DWORD, LPDWORD, HANDLE, LRESULT, LONG, ULONG, WPARAM, LPARAM, HMODULE, HHOOK,
53 | WORD, LPWORD, SHORT, USHORT, VOID, PVOID, LPVOID, LPCVOID, FLOAT, LPSECURITY_ATTRIBUTES
54 |
55 |
56 |
Not supported
57 | Double, float as a return type for callbacks. However pointers to such types are supported as a return type.
58 | Any struct of size of more than 4 bytes as a return type for any function.
59 | However pointers to such structures are supported as a return type.
60 | Classes.
61 | Structures inherited from other structures.
62 |
63 | See also
64 | Handling strings (char*, wchar_t*)
65 | Handling TCHAR and TSTR. Unicode/ANSI function name suffixes
66 | WinAPI constants and types
67 | Working with C/C++ structures/unions
68 | Working with callbacks
69 | Unsupported and unimplemented PBInvoke features
70 |
71 |
--------------------------------------------------------------------------------
/src/types/TypeFactory.cpp:
--------------------------------------------------------------------------------
1 | #include "../stdafx.h"
2 |
3 | #include "TypeFactory.h"
4 | #include "../Runtime.h"
5 | #include "../Core.h"
6 | #include "DataTypes.h"
7 | #include "../PBException.h"
8 | #include "../Compiler.h"
9 |
10 |
11 |
12 | TypeFactory * TypeFactory::m_instance = NULL;
13 |
14 |
15 | Type TypeFactory::createType(const string &typeName)
16 | {
17 | return CoreInstance.findType("", typeName);
18 | }
19 |
20 |
21 |
22 |
23 | TypeFactory& TypeFactory::getInstance()
24 | {
25 | if (m_instance == NULL)
26 | m_instance = new TypeFactory();
27 | return *m_instance;
28 | }
29 |
30 | BaseType* PBCALL bt_create(char *typeName, DataCharset charset)
31 | {
32 | PBExceptionStorageInstance.clearLastExceptionMessage();
33 | ParamStorage ps;
34 | if (charset == DC_UNICODE)
35 | typeName = ps.convertWtoA((wchar_t*)typeName);
36 | try {
37 | Type typeRef = CoreInstance.findType("", typeName);
38 | return typeRef.get();
39 | }
40 | catch (...) {
41 | return NULL;
42 | }
43 | }
44 |
45 |
46 | Type TypeFactory::createMethodType(const char* methodDecl)
47 | {
48 | // try 1st if method ptr name was passed
49 | string methodPtrName = methodDecl;
50 | Type methodPtrType = CoreInstance.findType("", methodPtrName, false);
51 | if (methodPtrType.get() == NULL) {
52 | // no method with methodDecl name
53 | // compile declaration
54 | Compiler compiler("");
55 | methodPtrName = compiler.compileAsCTypedef(methodDecl);
56 | if (methodPtrName == "")
57 | throw RuntimeException("Declaration does not contain function declarations: '" + string(methodDecl) + "'");
58 | methodPtrType = CoreInstance.findType("", methodPtrName);
59 | }
60 | dprintf("TypeFactory::createMethodType: class=%i, decl='%s', sig='%s'\n", methodPtrType->getPBTypeClass(), methodPtrName.c_str(), methodPtrType->getTypeSignature().c_str());
61 | if (methodPtrType->getPBTypeClass() == TC_METHOD_TYPE) {
62 | return methodPtrType;
63 | }
64 | else if (methodPtrType->isPointerToMethod()) {
65 | return ((PointerType*)methodPtrType.get())->getDataType();
66 | }
67 | else {
68 | throw RuntimeException("Name '" + methodPtrName + "' is not a 'function' declaration");
69 | }
70 |
71 | }
72 |
73 | MethodType* PBCALL tf_createMethodType(const char *methodDecl, DataCharset charset)
74 | {
75 | dprintf("tf_createMethodType charset=%i\n", charset);
76 | PBExceptionStorageInstance.clearLastExceptionMessage();
77 | try {
78 | ParamStorage ps;
79 | if (charset == DC_UNICODE) {
80 | methodDecl = ps.convertWtoA((wchar_t*)methodDecl);
81 | }
82 | return (MethodType*)TypeFactory::getInstance().createMethodType(methodDecl).get();
83 | }
84 | catch(...) {
85 | return NULL;
86 | }
87 | }
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/src/Core.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #pragma warning(disable: 4786)
4 |
5 | #include "Runtime.h"
6 | #include "WinHooks.h"
7 |
8 | #include
9 |
10 | // breaks VC6 compatibility
11 | #include
12 | using namespace stdext;
13 |
14 |
15 | #define PBM_CUSTOM01 (WM_USER + 0)
16 |
17 |
18 | class Core : public ExecutionContext
19 | {
20 | public:
21 | Type& registerType(Type &typeRef);
22 | static Core& getInstance();
23 | /** Gets current packing for structures */
24 | int getPack();
25 | void setPack(int pack);
26 | void pushPack(int pack);
27 | void popPack();
28 | void setCallbackMessageHandler(HWND callbackMessageHandler);
29 | void setCallbackMessageId(UINT callbackMessageId);
30 | inline HWND getCallbackMessageHandler() { return m_callbackMessageHandler; }
31 | inline UINT getCallbackMessageId() { return m_callbackMessageId; }
32 | Type& findType(const string &nameSpace, const string& typeName, bool throwNotFound = true);
33 | Type& defineType(const string &nameSpace, const string& typeName, Type &typeRef);
34 | Type& findName(const string &nameSpace, const string& name, bool throwNotFound = true);
35 | Type& defineName(const string &nameSpace, const string& name, Type &typeRef);
36 | void compile(const string &nameSpace, const string& source);
37 | static void resetState();
38 | void initTChar();
39 | inline bool isUnicode() { return m_isUnicode; }
40 | inline void setUnicode(bool isUnicode) { m_isUnicode = isUnicode; }
41 | inline vector& getWinHookHelpers() { return m_winHookHelpers;}
42 | inline bool getDefCallingConvention() { return m_defCallingConvention;}
43 | inline void setDefCallingConvention(bool isStdCall) { m_defCallingConvention = isStdCall;}
44 | private:
45 | static Core * m_instance;
46 | Core();
47 | virtual ~Core();
48 | Core(Core&) {}
49 | Core& operator=(Core&) {}
50 |
51 | /** All types seen by PBInvoke */
52 | vector m_types;
53 | /** Map typesig -> type index in m_types */
54 | hash_map m_typeMap;
55 | /** Map typename -> type index in m_types */
56 | hash_map m_typeDefs;
57 | /** Map var or fn name -> type index in m_types */
58 | hash_map m_names;
59 |
60 | vector m_winHookHelpers;
61 | int m_pack;
62 |
63 | stack m_packStack;
64 | HWND m_callbackMessageHandler;
65 | UINT m_callbackMessageId;
66 | int m_maxInternalTypeIndex;
67 | void initInternalTypes(void);
68 | void initInternalNames(void);
69 | inline void registerType(Type &typeRef, int &typeIndex);
70 | bool m_isTCharInitialized;
71 | bool m_isUnicode;
72 | bool m_defCallingConvention;
73 |
74 | void initWinAPI();
75 | void initWinHookHelpers();
76 |
77 | };
78 |
79 | #define CoreInstance Core::getInstance()
80 |
81 |
82 |
--------------------------------------------------------------------------------
/doc/quick-start-guide.html:
--------------------------------------------------------------------------------
1 | PBInvoke quick start guide
2 |
3 | Add PBInvoke library to your project
4 |
5 | - Unpack PbInvoke.PBL and libPbInvoke.DLL for your PowerBuilder version (or closest older version) to your project folder.
6 |
- Add PbInvoke.PBL to application's library list.
7 |
- Make a migration.
8 |
- Make a full build.
9 |
10 |
11 | Initialize PBInvoke
12 | If libPbInvoke.DLL is not in the PATH nor in the current directory then you'll need to specify the path to it
13 | in application's open event before any other call to the library:
14 |
15 | n_pi_loader lnv_loader // autoinstantiated
16 | lnv_loader.of_preload_dll("modules\libPBInvoke.dll")
17 |
18 | Note, you can change the path only, and not the DLL name because it is hard-coded in the external function declarations.
19 |
20 |
21 | Declare DLL function
22 |
23 | This code can be placed in any convenient script. Usually it's executed once per application session
24 | and its results are cached somewhere (e.g. in instance/shared variables).
25 |
26 | n_pi_core lnv_core
27 | n_pi_library lnv_user32
28 | n_pi_method lnv_SendMessage
29 |
30 | lnv_user32 = lnv_core.of_declare_library("user32.dll")
31 |
32 | lnv_SendMessage = lnv_user32.of_declare_method(&
33 | "LRESULT WINAPI SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) ")
34 |
35 |
36 | Note, that the declaration is a C function prototype which can be directly copied from C header files
37 | or from documentation such as MSDN.
38 |
39 | HWND, UINT etc. are Windows types. Many such types are predefined in PBInvoke.
40 | But if you get "Type 'XXXX' not found" error message, then you'll need to define the type yourself
41 | before using it in declarations.
42 |
43 | n_pi_core lnv_core
44 | lnv_core.of_declare("typedef int NEWTYPE"); // this is just an example; for real typedef you'll need to
45 | // see the documentation or header files for DLL you call.
46 |
47 | ...of_declare_method(...)
48 |
49 |
50 |
51 |
Call DLL function
52 |
53 |
54 | long ll_result
55 | ll_result = lnv_SendMessage.of_invoke(Handle(w_somewin), n_pi_winapi.WM_KEYDOWN, 9 /*Tab*/, 0)
56 |
57 | n_pi_winapi provides some WinAPI constants.
58 |
59 | More samples
60 | See the Samples folder in the archive for more complex examples with structures, callbacks etc.
61 |
62 | See also
63 | Calling DLL functions using PBInvoke
64 | Handling strings (char*, wchar_t*)
65 | WinAPI constants and types
66 | Working with C/C++ structures/unions
67 | Working with callbacks
68 |
--------------------------------------------------------------------------------
/src/Compiler.cpp:
--------------------------------------------------------------------------------
1 | // this must be included before stdafx.h
2 | #include "parser/CParser.tab.h"
3 |
4 | #include "stdafx.h"
5 | #include "Compiler.h"
6 | #include
7 | #include "parser/CLexer.h"
8 | #include "Runtime.h"
9 | #include "PBException.h"
10 |
11 | //typedef int *FN1(), FN2();
12 | //int *fn();
13 | //FN1 v1;
14 | //FN2 v2;
15 |
16 | Compiler::Compiler(const string &nameSpace, bool enableTCharSuffix)
17 | : m_nameSpace(nameSpace)
18 | , m_enableTCharSuffix(m_enableTCharSuffix)
19 | {
20 | //v1();
21 | }
22 |
23 | Compiler::~Compiler()
24 | {
25 |
26 | }
27 |
28 |
29 | string Compiler::compileAsC(const char* source)
30 | {
31 | dprintf("compileAsC\n%s\n", source);
32 | yy::CParser parser(*this);
33 | istrstream is(source);
34 | CLexer lexer(&is);
35 | int result = parser.parse();
36 | if (result != 0)
37 | throw RuntimeException(/*"Syntax error: " + */ m_errorMessage);
38 | if (m_names.size() == 0)
39 | return "";
40 | else
41 | return m_names[m_names.size() - 1];
42 | }
43 | string Compiler::compileAsCTypedef(const string &source)
44 | {
45 | string typedefSource = "typedef " + source;
46 | dprintf("compileAsCTypedef: %s\n", typedefSource.c_str());
47 | yy::CParser parser(*this);
48 | istrstream is(typedefSource.c_str());
49 | CLexer lexer(&is);
50 | int result = parser.parse();
51 | if (result != 0)
52 | throw RuntimeException(/*"Syntax error: " + */ m_errorMessage);
53 | if (m_typeDefs.size() == 0)
54 | return "";
55 | else
56 | return m_typeDefs[m_typeDefs.size() - 1];
57 | }
58 | Type Compiler::findType(const string& typeName, bool throwNotFound)
59 | {
60 | Type type = m_tags[typeName];
61 | if (type.get() == NULL)
62 | type = CoreInstance.findType(m_nameSpace, typeName, throwNotFound);
63 | return type;
64 | }
65 |
66 | Type Compiler::defineType(const string& typeName, Type &typeRef)
67 | {
68 | if (typeName != "") {
69 | Type type = CoreInstance.defineType(m_nameSpace, typeName, typeRef);
70 | m_typeDefs.push_back(typeName);
71 | return type;
72 | }
73 | else {
74 | return typeRef;
75 | }
76 | }
77 | Type Compiler::defineTag(const string& typeName, Type &typeRef)
78 | {
79 | if (typeName != "") {
80 | m_tags[typeName] = typeRef;
81 | }
82 | return typeRef;
83 | }
84 |
85 | Type Compiler::defineName(string name, Type &typeRef)
86 | {
87 | if (typeRef->isVoid())
88 | throw RuntimeException("Illegal use of 'void' type for declaring '" + name + "'");
89 | if (m_enableTCharSuffix && typeRef->hasTChar()) {
90 | if (CoreInstance.isUnicode()) {
91 | name += "W";
92 | }
93 | else {
94 | name += "A";
95 | }
96 | }
97 | Type type = CoreInstance.defineName(m_nameSpace, name, typeRef);
98 | m_names.push_back(name);
99 | return type;
100 | }
101 |
--------------------------------------------------------------------------------
/src/parser/stack.hh:
--------------------------------------------------------------------------------
1 | /* A Bison parser, made by GNU Bison 2.1. */
2 |
3 | /* stack handling for Bison C++ parsers,
4 | Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
5 |
6 | This program is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2, or (at your option)
9 | any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program; if not, write to the Free Software
18 | Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 | Boston, MA 02110-1301, USA. */
20 |
21 | #ifndef BISON_STACK_HH
22 | # define BISON_STACK_HH
23 |
24 | #include
25 |
26 | namespace yy
27 | {
28 | template >
29 | class stack
30 | {
31 | public:
32 |
33 | // Hide our reversed order.
34 | typedef typename S::reverse_iterator iterator;
35 | typedef typename S::const_reverse_iterator const_iterator;
36 |
37 | stack () : seq_ ()
38 | {
39 | }
40 |
41 | stack (unsigned int n) : seq_ (n)
42 | {
43 | }
44 |
45 | inline
46 | T&
47 | operator [] (unsigned int i)
48 | {
49 | return seq_[i];
50 | }
51 |
52 | inline
53 | const T&
54 | operator [] (unsigned int i) const
55 | {
56 | return seq_[i];
57 | }
58 |
59 | inline
60 | void
61 | push (const T& t)
62 | {
63 | seq_.push_front (t);
64 | }
65 |
66 | inline
67 | void
68 | pop (unsigned int n = 1)
69 | {
70 | for (; n; --n)
71 | seq_.pop_front ();
72 | }
73 |
74 | inline
75 | unsigned int
76 | height () const
77 | {
78 | return seq_.size ();
79 | }
80 |
81 | inline const_iterator begin () const { return seq_.rbegin (); }
82 | inline const_iterator end () const { return seq_.rend (); }
83 |
84 | private:
85 |
86 | S seq_;
87 | };
88 |
89 | /// Present a slice of the top of a stack.
90 | template >
91 | class slice
92 | {
93 | public:
94 |
95 | slice (const S& stack,
96 | unsigned int range) : stack_ (stack),
97 | range_ (range)
98 | {
99 | }
100 |
101 | inline
102 | const T&
103 | operator [] (unsigned int i) const
104 | {
105 | return stack_[range_ - i];
106 | }
107 |
108 | private:
109 |
110 | const S& stack_;
111 | unsigned int range_;
112 | };
113 | }
114 |
115 | #endif // not BISON_STACK_HH
116 |
--------------------------------------------------------------------------------
/doc/help.hhc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 | -
15 |
16 | -
21 |
-
26 |
27 | -
30 |
31 | -
36 |
-
41 |
-
46 |
-
51 |
-
56 |
57 | -
60 |
61 | -
66 |
-
71 |
72 | -
77 |
-
82 |
83 |
84 |
--------------------------------------------------------------------------------
/doc/index.html:
--------------------------------------------------------------------------------
1 | PBInvoke library
2 |
3 | Summary
4 | PBInvoke is a PowerBuilder library for calling external DLL functions with arbitrary
5 | parameter and return types - structures, unions, pointers, etc. including
6 | function pointers to PowerBuilder methods callable from DLL code as callbacks.
7 |
8 |
9 | PBInvoke goals
10 |
11 |
12 | - Allow PowerBuilder developers to work in PowerScript with complex data structures without
13 | writing wrapper DLLs in other languages such as C/C++.
14 |
15 |
- Make declarations of external functions ANSI/Unicode-independent which avoids migration issues
16 | when using the same code across ANSI and Unicode versions of PowerBuilder.
17 |
18 |
- Support any C/C++ data type (except classes). This includes complex nested data types involving
19 | structs, unions, pointers, simple types and their combinations.
20 |
21 |
- Support not only STDCALL calling convention, but also CDECL which is default in C/C++ programs.
22 |
23 |
- Allow PB code to be called from external functions as callbacks with full access to passed parameters.
24 |
25 |
- Support wide range of PowerBuilder versions from PB 6 to PB 11.5 and any future version.
26 |
27 |
28 |
29 |
30 | Why not use native PowerBuilder external functions?
31 |
32 | PowerBuilder support of external functions has the following restrictions
33 | which make developers write wrapper code in C/C++ and compile it with third party compilers.
34 |
35 | - No support for PowerBuilder callbacks.
36 |
- No support for unions and pointers to complex data types in structures.
37 |
- External function declarations depend on string encoding expected by functions.
38 | Often a charset conversion is required between ANSI PB and Unicode DLL and vice versa.
39 | PowerScript attrubute ';ansi' is available only in PB10+ and makes the source code incompatible with older PB versions.
40 | PBInvoke automatically handles the encoding stuff (including function name suffixes such as A/W in WinAPI).
41 |
42 |
43 |
44 | Why not use PowerBuilder extensions (PBNI)?
45 |
46 |
47 | - PBNI is available only as of PB9.
48 |
- PBNI requires knowledge of C++.
49 |
- PBNI extensions are quite hard to write and debug.
50 |
- PBNI requires separate DLLs for ANSI and Unicode versions.
51 |
52 |
53 |
54 |
55 | See also
56 | Quick Start Guide
57 | Calling DLL functions using PBInvoke
58 | Handling strings (char*, wchar_t*)
59 | Handling TCHAR and TSTR. Unicode/ANSI function name suffixes
60 | Supported data types
61 | WinAPI constants and types
62 | Working with C/C++ structures/unions
63 | Working with callbacks
64 | Unsupported and unimplemented PBInvoke features
65 | PBInvoke library license agreement
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/doc/genhelp/help.hhc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 | -
15 |
16 | -
21 |
-
26 |
27 | -
30 |
31 | -
36 |
-
41 |
-
46 |
-
51 |
-
56 |
57 | -
60 |
61 | -
66 |
-
71 |
72 | -
77 |
-
82 |
83 |
84 |
--------------------------------------------------------------------------------
/doc/genhelp/supported-data-types.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Supported data types
4 |
5 |
6 |
7 |
8 |
9 | PBInvoke documentation. Version 1.X. Visit http://sqlbatch.com/pbinvoke for updates.
10 |
11 | Supported data types
12 |
13 | Simple types
14 |
15 | The folowing C/C++ types are supported
16 |
17 | - short, int, long, longlong and their signed/unsigned versions
18 |
- char, wchar_t - character types
19 |
- double, float
20 |
- void - return type for procedures
21 |
22 |
23 | Structure types
24 |
25 |
26 | - struct - a record of fields of any type
27 |
- union - a struct whose fields share the same memory.
28 |
29 | For structs/unions the packing attribute can be specified. See the reference.
30 |
31 | Pointer types
32 |
33 | - pointer to type (*)
34 |
- reference to type (&)
35 |
36 |
37 |
38 | Function prototypes
39 |
40 | - external function prototype
41 |
- pointer to function (callback).
42 |
43 | For functions and function pointers a few attributes are supported. See the reference.
44 |
45 |
46 | User-defined types
47 | A developer can declare any custom C type using one or more C typedef operators separated by ";" and
48 | passed as a string to n_pi_core.of_declare(), as follows:
49 | n_pi_core lnv_core
50 | lnv_core.of_declare(" &
51 | typedef void *LPCITEMIDLIST, *LPITEMIDLIST; &
52 | typedef int (CALLBACK* BFFCALLBACK)(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData); &
53 | ")
54 |
55 |
56 |
57 | WinAPI types
58 | The most widely used WinAPI types are predeclared in PBInvoke.
59 |
These are:
60 | TCHAR, TSTR, LPTSTR, LPCTSTR, WCHAR, WSTR, LPWSTR, LPCWSTR, CHAR, STR, LPSTR, LPCSTR, BYTE,BOOL, HWND, HINSTANCE,
61 | LPBOOL, INT, UINT, UINT_PTR, DWORD, LPDWORD, HANDLE, LRESULT, LONG, ULONG, WPARAM, LPARAM, HMODULE, HHOOK,
62 | WORD, LPWORD, SHORT, USHORT, VOID, PVOID, LPVOID, LPCVOID, FLOAT, LPSECURITY_ATTRIBUTES
63 |
64 |
65 |
Not supported
66 | Double, float as a return type for callbacks. However pointers to such types are supported as a return type.
67 | Any struct of size of more than 4 bytes as a return type for any function.
68 | However pointers to such structures are supported as a return type.
69 | Classes.
70 | Structures inherited from other structures.
71 |
72 | See also
73 | Handling strings (char*, wchar_t*)
74 | Handling TCHAR and TSTR. Unicode/ANSI function name suffixes
75 | WinAPI constants and types
76 | Working with C/C++ structures/unions
77 | Working with callbacks
78 | Unsupported and unimplemented PBInvoke features
79 |
80 |
81 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/src/parser/clexer.l:
--------------------------------------------------------------------------------
1 | %{
2 | #include "CLexer.h"
3 | #include
4 |
5 | //#define YY_DECL int CLexer::yylex(YYSTYPE* yylval)
6 | //#define YY_DECL int yyFlexLexer::yylex(YYSTYPE* yylval)
7 |
8 | #define YY_DECL int yylex(YYSTYPE* yylval)
9 | #define YY_INPUT(buf,result,max_size) \
10 | { \
11 | CLexer::in()->read(buf, max_size);\
12 | result = CLexer::in()->bad() ? YY_NULL : CLexer::in()->gcount();\
13 | }
14 |
15 |
16 | stack m_buffers;
17 |
18 |
19 | %}
20 |
21 | %option 8bit
22 |
23 | /*%option c++ */
24 | /*%option yyclass="CLexer"*/
25 | %option outfile="CLexer.cpp"
26 | %option nounistd
27 | /*%option prefix="CLexer" */
28 |
29 | id0 [a-zA-Z_]
30 | id {id0}({id0}|[0-9@])*
31 | int [0-9]+
32 | num1 {int}("."{int})?([eE][+-]?{int})?
33 | num2 "."{int}([eE][+-]?{int})?
34 | num {num1}|{num2}
35 | sp [ \t]*
36 | sp1 [ \t]+
37 |
38 |
39 | %x COMM
40 |
41 | %%
42 |
43 | [ \t\r\n]+ /*skip spaces*/
44 | "//"[^\n]* /*// comments*/
45 | "/*" { BEGIN(COMM); } /* / * * / comments*/
46 | [^\*]+ { }
47 | "*"+ { }
48 | "*"+"/" { BEGIN(INITIAL); }
49 | NEAR|FAR|near|far {}
50 | typedef { return T_TYPEDEF; }
51 | __cdecl|CDECL { return ATTR_CDECL; }
52 | __stdcall|CALLBACK|WINAPI|STDCALL|PASCAL|pascal { return ATTR_STDCALL; }
53 | struct { return T_STRUCT; }
54 | union { return T_UNION; }
55 | enum { return T_ENUM; }
56 | const /* ignore */
57 | unsigned { return T_UNSIGNED; }
58 | signed { return T_SIGNED; }
59 | char { return T_CHAR;}
60 | wchar_t { return T_WCHAR_T;}
61 | int { return T_INT;}
62 | __int8 { return T_INT8;}
63 | __int16 { return T_INT16;}
64 | __int32 { return T_INT32;}
65 | __int64 { return T_INT64;}
66 | short { return T_SHORT;}
67 | long { return T_LONG;}
68 | longlong { return T_LONGLONG;}
69 | double { return T_DOUBLE;}
70 | float { return T_FLOAT;}
71 | void { return T_VOID;}
72 | __declspec { return ATTR_DECLSPEC; }
73 | ";" { return SEMICOLON; }
74 | "::" { return DBLCOLON; }
75 | "=" { return ASSIGN; }
76 | "," { return COMMA; }
77 | "(" { return LPAREN; }
78 | ")" { return RPAREN; }
79 | "{" { return LCURL; }
80 | "}" { return RCURL; }
81 | "[" { return LBRACKET; }
82 | "]" { return RBRACKET; }
83 | "*" { return STAR; }
84 | "&" { return ADDR; }
85 | {id} { yylval->text = yytext; return ID; }
86 | {num} { yylval->text = yytext; return NUM; }
87 | "#"{sp}pragma{sp1}pack { return T_PRAGMA_PACK; }
88 | "#"{sp}pragma[^\n]* /* ignore unknown pragmas */
89 | . /* ignore */
90 | %%
91 |
92 |
93 | int yywrap()
94 | {
95 | return 1; // terminate on eof
96 | }
97 |
98 | istream * CLexer::m_inputStream;
99 |
100 | void CLexer::pushInput()
101 | {
102 | m_prevInputStream = m_inputStream;
103 | m_buffers.push(YY_CURRENT_BUFFER);
104 | yy_switch_to_buffer(yy_create_buffer(NULL, YY_BUF_SIZE));
105 | }
106 | void CLexer::popInput()
107 | {
108 | yy_delete_buffer(YY_CURRENT_BUFFER);
109 | m_inputStream = m_prevInputStream;
110 | yy_switch_to_buffer(m_buffers.top());
111 | m_buffers.pop();
112 | }
113 |
114 |
--------------------------------------------------------------------------------
/doc/genhelp/quick-start-guide.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | PBInvoke quick start guide
4 |
5 |
6 |
7 |
8 |
9 | PBInvoke documentation. Version 1.X. Visit http://sqlbatch.com/pbinvoke for updates.
10 |
11 | PBInvoke quick start guide
12 |
13 | Add PBInvoke library to your project
14 |
15 | - Unpack PbInvoke.PBL and libPbInvoke.DLL for your PowerBuilder version (or closest older version) to your project folder.
16 |
- Add PbInvoke.PBL to application's library list.
17 |
- Make a migration.
18 |
- Make a full build.
19 |
20 |
21 | Initialize PBInvoke
22 | If libPbInvoke.DLL is not in the PATH nor in the current directory then you'll need to specify the path to it
23 | in application's open event before any other call to the library:
24 | n_pi_loader lnv_loader // autoinstantiated
25 | lnv_loader.of_preload_dll("modules\libPBInvoke.dll")
26 |
27 | Note, you can change the path only, and not the DLL name because it is hard-coded in the external function declarations.
28 |
29 |
30 | Declare DLL function
31 |
32 | This code can be placed in any convenient script. Usually it's executed once per application session
33 | and its results are cached somewhere (e.g. in instance/shared variables).
34 | n_pi_core lnv_core
35 | n_pi_library lnv_user32
36 | n_pi_method lnv_SendMessage
37 |
38 | lnv_user32 = lnv_core.of_declare_library("user32.dll")
39 |
40 | lnv_SendMessage = lnv_user32.of_declare_method(&
41 | "LRESULT WINAPI SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) ")
42 |
43 |
44 | Note, that the declaration is a C function prototype which can be directly copied from C header files
45 | or from documentation such as MSDN.
46 |
47 | HWND, UINT etc. are Windows types. Many such types are predefined in PBInvoke.
48 | But if you get "Type 'XXXX' not found" error message, then you'll need to define the type yourself
49 | before using it in declarations.
50 |
n_pi_core lnv_core
51 | lnv_core.of_declare("typedef int NEWTYPE"); // this is just an example; for real typedef you'll need to
52 | // see the documentation or header files for DLL you call.
53 |
54 | ...of_declare_method(...)
55 |
56 |
57 |
58 | Call DLL function
59 |
60 | long ll_result
61 | ll_result = lnv_SendMessage.of_invoke(Handle(w_somewin), n_pi_winapi.WM_KEYDOWN, 9 /*Tab*/, 0)
62 |
63 | n_pi_winapi provides some WinAPI constants.
64 |
65 | More samples
66 | See the Samples folder in the archive for more complex examples with structures, callbacks etc.
67 |
68 | See also
69 | Calling DLL functions using PBInvoke
70 | Handling strings (char*, wchar_t*)
71 | WinAPI constants and types
72 | Working with C/C++ structures/unions
73 | Working with callbacks
74 |
75 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/src/types/StructType.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "RawType.h"
4 | #include
5 | using namespace stdext;
6 |
7 | class IndexedStructType: public RawType {
8 | public:
9 | IndexedStructType(vector &itemTypes, int pack = 8, int explicitAlign = 0, bool isUnion = false, bool isArgStack = false);
10 | IndexedStructType(const string& body, int pack = 8, int explicitAlign = 0, bool isUnion = false, bool isArgStack = false);
11 |
12 | virtual int getPBTypeClass() {return TC_STRUCT_TYPE; }
13 | virtual int getSizeOf() {return m_sizeOf; }
14 |
15 | virtual int getItemOffset(int itemIndex) {return m_itemOffsets[itemIndex]; }
16 | inline vector& getItemTypes() { return m_itemTypes; }
17 | inline vector& getItemOffsets() { return m_itemOffsets; }
18 | inline int getPack() { return m_pack; }
19 | virtual string getTypeSignature(const string& pointerSig = "");
20 | virtual int getExplicitAlign() { return m_explicitAlign; }
21 | virtual int getAlign() { return m_align; }
22 | inline bool isArgStack() { return m_isArgStack; }
23 | inline bool isUnion() { return m_isUnion; }
24 | virtual bool hasTChar();
25 |
26 | private:
27 |
28 | /** Item types */
29 | vector m_itemTypes;
30 |
31 | /** Item offsets in the structure */
32 | vector m_itemOffsets;
33 |
34 | /** Is the structure a union (all offsets == 0)? */
35 | bool m_isUnion;
36 |
37 | /** Packing of items, the value of #pragma pack(n) */
38 | int m_pack;
39 |
40 | /** Explicitly given alignment of the structure in memory, the value of __declspec(align(n)) for struct */
41 | int m_explicitAlign;
42 |
43 | /** Is the structure for arg stack storage. */
44 | bool m_isArgStack;
45 |
46 | /** Effective alignment of the structure in memory */
47 | int m_align;
48 |
49 |
50 | string buildTypeSignature(const string &pointerSig);
51 | void parseBody(const string &body);
52 | protected:
53 | void init();
54 | };
55 |
56 |
57 | class StructType: public RawType {
58 | public:
59 | StructType(vector &items, int pack = 8, int explicitAlign = 0, bool isUnion = false, bool isArgStack = false);
60 | //incomplete struct def
61 | StructType(const string &tagName);
62 | void complete(vector &items, int pack = 8, int explicitAlign = 0, bool isUnion = false, bool isArgStack = false);
63 |
64 | virtual int getPBTypeClass() {return TC_STRUCT_TYPE; }
65 | virtual int getSizeOf() {return m_indexedStructType->getSizeOf(); }
66 |
67 | virtual int getItemOffset(int itemIndex) {return m_indexedStructType->getItemOffset(itemIndex); }
68 | inline vector& getItems() { return m_items; }
69 | inline vector& getItemOffsets() { return m_indexedStructType->getItemOffsets(); }
70 | inline int getPack() { return m_indexedStructType->getPack(); }
71 | virtual string getTypeSignature(const string& pointerSig = "");
72 | virtual int getExplicitAlign() { return m_indexedStructType->getExplicitAlign(); }
73 | virtual int getAlign() { return m_indexedStructType->getAlign(); }
74 | virtual bool isComplete() { return m_indexedStructType != NULL; }
75 | virtual string getTagName() { return m_tagName; }
76 | virtual bool isCompatible(BaseType* type);
77 | virtual int getItemIndex(const string& itemName) ;
78 | virtual bool hasTChar() { return m_indexedStructType->hasTChar(); }
79 |
80 | private:
81 |
82 | IndexedStructType *m_indexedStructType;
83 |
84 | /** Item names and types*/
85 | vector m_items;
86 |
87 | hash_map m_itemNameMap;
88 | string m_tagName;
89 |
90 | string buildTypeSignature(const string &pointerSig);
91 | void init();
92 | };
93 |
--------------------------------------------------------------------------------
/doc/genhelp/handling-strings.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Handling strings (char*, wchar_t*)
4 |
5 |
6 |
7 |
8 |
9 | PBInvoke documentation. Version 1.X. Visit http://sqlbatch.com/pbinvoke for updates.
10 |
11 | Handling strings (char*, wchar_t*)
12 |
13 | Charset conversion
14 | When a function parameter is declared as char* or wchar_t*,
15 | PBInvoke automatically converts the charset of the string if PowerBuilder
16 | native strings have different charset.
17 |
18 | lnv_fn1 = lnv_somelib.of_declare_method("int strlen(char*s)")
19 | lnv_fn2 = lnv_somelib.of_declare_method("int wcslen(wchar_t*s)")
20 |
21 | // in PB9
22 | ll_len = lnv_fn1.of_invoke("test") // no conversion, both caller and callee are ANSI
23 | ll_len = lnv_fn2.of_invoke("test") // implicitly converts the string from ANSI to Unicode
24 |
25 | // in PB10+
26 | ll_len = lnv_fn1.of_invoke("test") // implicitly converts the string from Unicode to ANSI
27 | ll_len = lnv_fn2.of_invoke("test") // no conversion, both caller and callee are Unicode
28 |
29 |
30 | Combinations of char and wchar_t in one function are supported as well.
31 | lnv_fn = lnv_somelib.of_declare_method("void some_fn(char*s1, wchar_t*s2)")
32 | // in PB9
33 | lb_res = lnv_fn.of_invoke("test1", "test2") // "test1" - no conversion
34 | // "test2" - ANSI -> Unicode
35 | // in PB10 - vice versa
36 |
37 |
38 |
39 | Special handling is performed for TCHAR based parameters.
40 | See Handling TCHAR and TSTR. Unicode/ANSI function name suffixes.
41 |
42 |
Passing numeric address of string instead of string
43 |
44 | If you got an address of some string as a numeric value, for example as a result of calling another function,
45 | you can pass this number instead of a PB string value. Passing 0 or null value gives NULL string pointers.
46 | If a numeric address is passed instead of a string then no charset conversion is done.
47 |
48 |
lnv_fn = lnv_somelib.of_declare_method("void some_fn(char*s)")
49 |
50 | lnv_s = lnv_core.of_create_value_of(LPSTR) // LPSTR is char* in WinAPI
51 | lnv_fn.of_invoke(lnv_s.of_get_ptr()) // of_get_ptr() gets the numeric value of the pointer
52 |
53 | // incorrect use:
54 | lnv_s = lnv_core.of_create_value_of(LPWSTR) // LPWSTR is wchar_t* in WinAPI
55 | lnv_fn.of_invoke(lnv_s.of_get_ptr()) // WRONG! because no conversion is done,
56 | // and the function expects char* and not wchar_t*
57 | // passing NULL
58 | lnv_fn.of_invoke(0)
59 | SetNull(ls_null)
60 | lnv_fn.of_invoke(ls_null)
61 |
62 |
63 |
64 | See also
65 | Handling TCHAR and TSTR. Unicode/ANSI function name suffixes
66 |
67 |
68 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/doc/genhelp/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | PBInvoke library
4 |
5 |
6 |
7 |
8 |
9 | PBInvoke documentation. Version 1.X. Visit http://sqlbatch.com/pbinvoke for updates.
10 |
11 | PBInvoke library
12 |
13 | Summary
14 | PBInvoke is a PowerBuilder library for calling external DLL functions with arbitrary
15 | parameter and return types - structures, unions, pointers, etc. including
16 | function pointers to PowerBuilder methods callable from DLL code as callbacks.
17 |
18 |
19 | PBInvoke goals
20 |
21 |
22 | - Allow PowerBuilder developers to work in PowerScript with complex data structures without
23 | writing wrapper DLLs in other languages such as C/C++.
24 |
25 |
- Make declarations of external functions ANSI/Unicode-independent which avoids migration issues
26 | when using the same code across ANSI and Unicode versions of PowerBuilder.
27 |
28 |
- Support any C/C++ data type (except classes). This includes complex nested data types involving
29 | structs, unions, pointers, simple types and their combinations.
30 |
31 |
- Support not only STDCALL calling convention, but also CDECL which is default in C/C++ programs.
32 |
33 |
- Allow PB code to be called from external functions as callbacks with full access to passed parameters.
34 |
35 |
- Support wide range of PowerBuilder versions from PB 6 to PB 11.5 and any future version.
36 |
37 |
38 |
39 |
40 | Why not use native PowerBuilder external functions?
41 |
42 | PowerBuilder support of external functions has the following restrictions
43 | which make developers write wrapper code in C/C++ and compile it with third party compilers.
44 |
45 | - No support for PowerBuilder callbacks.
46 |
- No support for unions and pointers to complex data types in structures.
47 |
- External function declarations depend on string encoding expected by functions.
48 | Often a charset conversion is required between ANSI PB and Unicode DLL and vice versa.
49 | PowerScript attrubute ';ansi' is available only in PB10+ and makes the source code incompatible with older PB versions.
50 | PBInvoke automatically handles the encoding stuff (including function name suffixes such as A/W in WinAPI).
51 |
52 |
53 |
54 | Why not use PowerBuilder extensions (PBNI)?
55 |
56 |
57 | - PBNI is available only as of PB9.
58 |
- PBNI requires knowledge of C++.
59 |
- PBNI extensions are quite hard to write and debug.
60 |
- PBNI requires separate DLLs for ANSI and Unicode versions.
61 |
62 |
63 |
64 |
65 | See also
66 | Quick Start Guide
67 | Calling DLL functions using PBInvoke
68 | Handling strings (char*, wchar_t*)
69 | Handling TCHAR and TSTR. Unicode/ANSI function name suffixes
70 | Supported data types
71 | WinAPI constants and types
72 | Working with C/C++ structures/unions
73 | Working with callbacks
74 | Unsupported and unimplemented PBInvoke features
75 | PBInvoke library license agreement
76 |
77 |
78 |
79 |
80 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/src/types/CharType.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "PointerType.h"
4 | #include "../Runtime.h"
5 |
6 | class CharType: public RawType {
7 | protected:
8 | CharType(const string &typeSignature, size_t sizeOf);
9 | public:
10 | virtual int getPBTypeClass() { return TC_CHAR_TYPE; };
11 | //inline void setPBUnicode(bool isPBUnicode) { m_isPBUnicode = isPBUnicode;}
12 | protected:
13 | //bool m_isPBUnicode;
14 | string TypeName;
15 | string StringFormat;
16 | };
17 |
18 | class ACharType: public CharType {
19 | protected:
20 | typedef char type_t;
21 | typedef wchar_t inv_type_t;
22 | enum {CHARSET = DC_ANSI, INV_CHARSET = DC_UNICODE };
23 | inline size_t tstrlen(const type_t* s) { return strlen(s);}
24 | inline size_t tstrnlen(const type_t* s, size_t n) { return strnlen(s, n);}
25 | inline size_t strlenStoT(ExecutionContext* ctx, const type_t *srcString, int strLen = -1) {
26 | return ctx->strlenAtoW(srcString, strLen);
27 | }
28 | inline size_t strlenTtoS(ExecutionContext* ctx, const inv_type_t *srcString, int strLen = -1) {
29 | return ctx->strlenWtoA(srcString, strLen);
30 | }
31 | inline inv_type_t* convertStoT(ExecutionContext* ctx, const type_t *srcString, int strLen = -1, inv_type_t *buf = NULL) {
32 | return ctx->convertAtoW(srcString, strLen, buf);
33 | }
34 | inline type_t* convertTtoS(ExecutionContext* ctx, const inv_type_t *srcString, int strLen = -1, type_t *buf = NULL) {
35 | return ctx->convertWtoA(srcString, strLen, buf);
36 | }
37 | public:
38 |
39 | ACharType() : CharType("char", sizeof(char)) { TypeName = "ACharType"; StringFormat = "s"; }
40 | virtual void setArrayData(ExecutionContext *context, BYTE * &cBuf, BYTE *pbBuf, int strLen, DataCharset charset);
41 | virtual void getArrayData(ExecutionContext *context, BYTE * cBuf, BYTE *pbBuf, int &strLen, DataCharset charset);
42 | virtual size_t strLen(ExecutionContext *context, BYTE * buf, int arrayLen, DataCharset charset);
43 | };
44 | class WCharType: public CharType {
45 | protected:
46 | typedef wchar_t type_t;
47 | typedef char inv_type_t;
48 | enum {CHARSET = DC_UNICODE, INV_CHARSET = DC_ANSI };
49 | inline size_t tstrlen(const type_t* s) { return wcslen(s);}
50 | inline size_t tstrnlen(const type_t* s, size_t n) { return wcsnlen(s, n);}
51 | inline size_t strlenStoT(ExecutionContext* ctx, const type_t *srcString, int strLen = -1) {
52 | return ctx->strlenWtoA(srcString, strLen);
53 | }
54 | inline size_t strlenTtoS(ExecutionContext* ctx, const inv_type_t *srcString, int strLen = -1) {
55 | return ctx->strlenAtoW(srcString, strLen);
56 | }
57 | inline inv_type_t* convertStoT(ExecutionContext* ctx, const type_t *srcString, int strLen = -1, inv_type_t *buf = NULL) {
58 | return ctx->convertWtoA(srcString, strLen, buf);
59 | }
60 | inline type_t* convertTtoS(ExecutionContext* ctx, const inv_type_t *srcString, int strLen = -1, type_t *buf = NULL) {
61 | return ctx->convertAtoW(srcString, strLen, buf);
62 | }
63 |
64 | public:
65 | WCharType() : CharType("wchar_t", sizeof(wchar_t)) { TypeName = "WCharType"; StringFormat = "S"; }
66 | virtual void setArrayData(ExecutionContext *context, BYTE * &cBuf, BYTE *pbBuf, int strLen, DataCharset charset);
67 | virtual void getArrayData(ExecutionContext *context, BYTE * cBuf, BYTE *pbBuf, int &strLen, DataCharset charset);
68 | virtual size_t strLen(ExecutionContext *context, BYTE * buf, int arrayLen, DataCharset charset);
69 | };
70 |
71 |
72 | class TACharType: public ACharType {
73 | public:
74 | virtual string getTypeSignature(const string& pointerSig = "") { return "tchar_t" + pointerSig;}
75 | virtual bool hasTChar() { return true; }
76 | };
77 |
78 | class TWCharType: public WCharType {
79 | public:
80 | virtual string getTypeSignature(const string& pointerSig = "") { return "tchar_t" + pointerSig;}
81 | virtual bool hasTChar() { return true; }
82 | };
83 |
84 |
--------------------------------------------------------------------------------
/src/parser/location.hh:
--------------------------------------------------------------------------------
1 | /* A Bison parser, made by GNU Bison 2.1. */
2 |
3 | /* Location class for Bison C++ parsers,
4 | Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
5 |
6 | This program is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2, or (at your option)
9 | any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program; if not, write to the Free Software
18 | Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 | Boston, MA 02110-1301, USA. */
20 |
21 | /**
22 | ** \file location.hh
23 | ** Define the location class.
24 | */
25 |
26 | #ifndef BISON_LOCATION_HH
27 | # define BISON_LOCATION_HH
28 |
29 | # include
30 | # include
31 | # include "position.hh"
32 |
33 | namespace yy
34 | {
35 |
36 | /// Abstract a location.
37 | class location
38 | {
39 | /** \name Ctor & dtor.
40 | ** \{ */
41 | public:
42 | /// Construct a location.
43 | location () :
44 | begin (),
45 | end ()
46 | {
47 | }
48 | /** \} */
49 |
50 |
51 | /** \name Line and Column related manipulators
52 | ** \{ */
53 | public:
54 | /// Reset initial location to final location.
55 | inline void step ()
56 | {
57 | begin = end;
58 | }
59 |
60 | /// Extend the current location to the COUNT next columns.
61 | inline void columns (unsigned int count = 1)
62 | {
63 | end += count;
64 | }
65 |
66 | /// Extend the current location to the COUNT next lines.
67 | inline void lines (unsigned int count = 1)
68 | {
69 | end.lines (count);
70 | }
71 | /** \} */
72 |
73 |
74 | public:
75 | /// Beginning of the located region.
76 | position begin;
77 | /// End of the located region.
78 | position end;
79 | };
80 |
81 | /// Join two location objects to create a location.
82 | inline const location operator+ (const location& begin, const location& end)
83 | {
84 | location res = begin;
85 | res.end = end.end;
86 | return res;
87 | }
88 |
89 | /// Add two location objects.
90 | inline const location operator+ (const location& begin, unsigned int width)
91 | {
92 | location res = begin;
93 | res.columns (width);
94 | return res;
95 | }
96 |
97 | /// Add and assign a location.
98 | inline location& operator+= (location& res, unsigned int width)
99 | {
100 | res.columns (width);
101 | return res;
102 | }
103 |
104 | /** \brief Intercept output stream redirection.
105 | ** \param ostr the destination output stream
106 | ** \param loc a reference to the location to redirect
107 | **
108 | ** Avoid duplicate information.
109 | */
110 | inline std::ostream& operator<< (std::ostream& ostr, const location& loc)
111 | {
112 | position last = loc.end - 1;
113 | ostr << loc.begin;
114 | if (last.filename
115 | && (!loc.begin.filename
116 | || *loc.begin.filename != *last.filename))
117 | ostr << '-' << last;
118 | else if (loc.begin.line != last.line)
119 | ostr << '-' << last.line << '.' << last.column;
120 | else if (loc.begin.column != last.column)
121 | ostr << '-' << last.column;
122 | return ostr;
123 | }
124 |
125 | }
126 |
127 | #endif // not BISON_LOCATION_HH
128 |
--------------------------------------------------------------------------------
/src/parser/position.hh:
--------------------------------------------------------------------------------
1 | /* A Bison parser, made by GNU Bison 2.1. */
2 |
3 | /* Position class for Bison C++ parsers,
4 | Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
5 |
6 | This program is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2, or (at your option)
9 | any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program; if not, write to the Free Software
18 | Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 | Boston, MA 02110-1301, USA. */
20 |
21 | /**
22 | ** \file position.hh
23 | ** Define the position class.
24 | */
25 |
26 | #ifndef BISON_POSITION_HH
27 | # define BISON_POSITION_HH
28 |
29 | # include
30 | # include
31 |
32 | namespace yy
33 | {
34 | /// Abstract a position.
35 | class position
36 | {
37 | public:
38 | /// Initial column number.
39 | static const unsigned int initial_column = 0;
40 | /// Initial line number.
41 | static const unsigned int initial_line = 1;
42 |
43 | /** \name Ctor & dtor.
44 | ** \{ */
45 | public:
46 | /// Construct a position.
47 | position () :
48 | filename (0),
49 | line (initial_line),
50 | column (initial_column)
51 | {
52 | }
53 | /** \} */
54 |
55 |
56 | /** \name Line and Column related manipulators
57 | ** \{ */
58 | public:
59 | /// (line related) Advance to the COUNT next lines.
60 | inline void lines (int count = 1)
61 | {
62 | column = initial_column;
63 | line += count;
64 | }
65 |
66 | /// (column related) Advance to the COUNT next columns.
67 | inline void columns (int count = 1)
68 | {
69 | int leftmost = initial_column;
70 | int current = column;
71 | if (leftmost <= current + count)
72 | column += count;
73 | else
74 | column = initial_column;
75 | }
76 | /** \} */
77 |
78 | public:
79 | /// File name to which this position refers.
80 | std::string* filename;
81 | /// Current line number.
82 | unsigned int line;
83 | /// Current column number.
84 | unsigned int column;
85 | };
86 |
87 | /// Add and assign a position.
88 | inline const position&
89 | operator+= (position& res, const int width)
90 | {
91 | res.columns (width);
92 | return res;
93 | }
94 |
95 | /// Add two position objects.
96 | inline const position
97 | operator+ (const position& begin, const int width)
98 | {
99 | position res = begin;
100 | return res += width;
101 | }
102 |
103 | /// Add and assign a position.
104 | inline const position&
105 | operator-= (position& res, const int width)
106 | {
107 | return res += -width;
108 | }
109 |
110 | /// Add two position objects.
111 | inline const position
112 | operator- (const position& begin, const int width)
113 | {
114 | return begin + -width;
115 | }
116 |
117 | /** \brief Intercept output stream redirection.
118 | ** \param ostr the destination output stream
119 | ** \param pos a reference to the position to redirect
120 | */
121 | inline std::ostream&
122 | operator<< (std::ostream& ostr, const position& pos)
123 | {
124 | if (pos.filename)
125 | ostr << *pos.filename << ':';
126 | return ostr << pos.line << '.' << pos.column;
127 | }
128 |
129 | }
130 | #endif // not BISON_POSITION_HH
131 |
--------------------------------------------------------------------------------
/doc/genhelp/license.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | PBInvoke library license agreement
4 |
5 |
6 |
7 |
8 |
9 | PBInvoke documentation. Version 1.X. Visit http://sqlbatch.com/pbinvoke for updates.
10 |
11 | PBInvoke library license agreement
12 | Using the product indicates your acknowledgment that you have read this
13 | license and agree to its terms.
14 |
15 | By installing, copying or otherwise using the SOFTWARE, you agree to be
16 | bound by the terms of this LICENSE.
17 |
18 | Warning: The SOFTWARE is protected by copyright laws and international
19 | copyright treaties, as well as other intellectual property laws and treaties.
20 | The SOFTWARE is licensed, not sold.
21 |
22 | The copyright holder of the SOFTWARE is Anatoly Moskovsky <avm@sqlbatch.com>
23 |
24 | The program is a shareware. You may evaluate it for period of 30 days.
25 | After this period you may not use the Software unless you pay the
26 | registration fee. You may share the unregistered Software with other
27 | people only if the Software is distributed in this original setup package.
28 | You may not give the registration numbers or registered versions of
29 | this software to other people nor use other people's registration/registered
30 | version.
31 |
32 | GRANT OF LICENSE
33 |
34 | This LICENSE grants you the following rights:
35 |
36 | a. Single Application License. You may create commercial applications based on
37 | PBInvoke and distribute them with your executables. No royalties required.
38 | One license is required per application. This is enforced by binding
39 | PBInvoke to application's executable name.
40 | You may NOT create a distributable component/library that include PBInvoke.
41 |
42 | b. Multi Application License. You may create commercial applications based on
43 | PBInvoke and distribute them with your executables. No royalties required.
44 | Any number of applications are allowed with one license.
45 | You may NOT create a distributable component/library that include PBInvoke.
46 |
47 | c. Library License. You may create unlimited number of commercial applications,
48 | components or libraries based on PBInvoke and distribute them in any form,
49 | provided the original PBInvoke code is not modified. No royalties required.
50 |
51 | d. You may use the product by any number of developers in your organization
52 | at a time.
53 |
54 | e. You may use the trial version for the limited purposes of
55 | demonstrations, trials and design time evaluations and running a
56 | product tour. You may not use the trial version to produce commercial
57 | works.
58 |
59 | f. You may not decompile, disassemble or otherwise reverse engineer
60 | the SOFTWARE.
61 |
62 | g. You may not rent or lease the SOFTWARE.
63 |
64 | h. You may NOT transfer any of your rights under this LICENSE.
65 |
66 | i. Without prejudice to any other rights, the copyright holder may terminate
67 | this LICENSE if you fail to comply with the terms and conditions of
68 | this LICENSE. In such event, you must destroy all copies of the SOFTWARE
69 | and provide sufficient proof thereof to the copyright holder.
70 |
71 |
72 | NO WARRANTIES.
73 | The copyright holder expressly disclaims any warranty for the SOFTWARE PRODUCT.
74 | THE SOFTWARE PRODUCT AND ANY RELATED DOCUMENTATION IS PROVIDED "AS IS"
75 | WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
76 | WITHOUT LIMITATION, THE IMPLIED WARRANTIES OR MERCHANTABILITY, FITNESS
77 | FOR A PARTICULAR PURPOSE, OR NONINFRINGEMENT.
78 | THE ENTIRE RISK ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE PRODUCT
79 | REMAINS WITH YOU.
80 | NO LIABILITY FOR CONSEQUENTIAL DAMAGES. IN NO EVENT SHALL THE COPYRIGHT HOLDER
81 | OR ITS SUPPLIERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR
82 | CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES
83 | FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS
84 | INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF
85 | OR INABILITY TO USE THE SOFTWARE PRODUCT
86 |
87 |
88 |
89 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/src/types/StringType.cpp:
--------------------------------------------------------------------------------
1 | #include "../stdafx.h"
2 |
3 | #include "StringType.h"
4 |
5 | #include "../Runtime.h"
6 | #include "../PBException.h"
7 |
8 | //StringType::StringType(const string &typeSignature)
9 | // : PointerType(typeSignature)
10 | //{
11 | //}
12 | //
13 | //
14 | //int StringType::getPBTypeClass()
15 | //{
16 | // return TC_STRING_TYPE;
17 | //}
18 | //
19 | //
20 | //
21 | //void AStringType::setStringData(ExecutionContext *context, BYTE * cBuf, BYTE * pbBuf, int strLen, DataCharset charset)
22 | //
23 | //{
24 | // dprintf("\n+AStringType::setStringData str=[%s]\n", pbBuf);
25 | //
26 | // // copy string value
27 | // if (pbBuf != NULL) {
28 | // if (charset == DC_ANSI || charset == DC_BINARY) {
29 | // BYTE *strValue = context->allocateBuffer((strLen + (charset == DC_BINARY ? 0 : 1)) * sizeof(char), __alignof(char));
30 | // memcpy(strValue, pbBuf, (strLen + (charset == DC_BINARY ? 0 : 1)) * sizeof(char));
31 | // pbBuf = strValue;
32 | // }
33 | // else {
34 | // pbBuf = (BYTE *)context->convertWtoA((wchar_t*)pbBuf, strLen);
35 | // }
36 | // }
37 | //
38 | // // copy ptr value
39 | // setData(context, cBuf, (BYTE*)&pbBuf);
40 | //
41 | // dprintf("-AStringType::setStringData\n\n");
42 | //}
43 | //
44 | //void AStringType::getStringData(ExecutionContext *context, BYTE * cBuf, BYTE *pbBuf, int &strLen, DataCharset charset)
45 | //{
46 | // dprintf("+AStringType::getStringData\n");
47 | //
48 | // char *strValue = *(char* *)cBuf;
49 | // if (strValue == NULL) {
50 | // strLen = -1;
51 | // }
52 | // else {
53 | // dprintf("strLen=%i, strValue=%p, strValue='%s'\n", strLen, strValue, strValue);
54 | // int len;
55 | // if (charset == DC_UNICODE) {
56 | // len = context->strlenAtoW(strValue);
57 | // }
58 | // else if (charset == DC_ANSI){
59 | // len = strlen(strValue);
60 | // }
61 | // else { // DC_BINARY
62 | // len = strLen;
63 | // }
64 | // if (strLen > 0) {
65 | // if (len > strLen) // copy max strLen chars
66 | // len = strLen;
67 | // dprintf("len=%i\n", len);
68 | // if (charset == DC_UNICODE) {
69 | // context->convertAtoW(strValue, len, /*out*/(wchar_t*)pbBuf);
70 | // }
71 | // else {
72 | // memcpy(pbBuf, strValue, len * sizeof(char));
73 | // }
74 | // }
75 | // strLen = len;
76 | // }
77 | // dprintf("-AStringType::getStringData\n");
78 | //}
79 | //
80 | //
81 | //void WStringType::setStringData(ExecutionContext *context, BYTE * cBuf, BYTE * pbBuf, int strLen, DataCharset charset)
82 | //
83 | //{
84 | // dprintf("\n+WStringType::setStringData\n");
85 | //
86 | // // copy string value
87 | // if (pbBuf != NULL) {
88 | // if (charset == DC_UNICODE || charset == DC_BINARY) {
89 | // BYTE *strValue = context->allocateBuffer((strLen + (charset == DC_BINARY ? 0 : 1)) * sizeof(wchar_t), __alignof(wchar_t));
90 | // memcpy(strValue, pbBuf, (strLen + (charset == DC_BINARY ? 0 : 1)) * sizeof(wchar_t));
91 | // pbBuf = strValue;
92 | // }
93 | // else {
94 | // pbBuf = (BYTE *)context->convertAtoW((char*)pbBuf, strLen);
95 | // }
96 | // }
97 | //
98 | // // copy ptr value
99 | // setData(context, cBuf, (BYTE*)&pbBuf);
100 | //
101 | // dprintf("-WStringType::setStringData\n\n");
102 | //}
103 | //
104 | //void WStringType::getStringData(ExecutionContext *context, BYTE * cBuf, BYTE *pbBuf, int &strLen, DataCharset charset)
105 | //{
106 | // dprintf("+WStringType::getStringData\n");
107 | //
108 | // wchar_t *strValue = *(wchar_t* *)cBuf;
109 | // if (strValue == NULL) {
110 | // strLen = -1;
111 | // }
112 | // else {
113 | // dprintf("strLen=%i, strValue=%p, strValue='%S'\n", strLen, strValue, strValue);
114 | // int len;
115 | // if (charset == DC_ANSI) {
116 | // len = context->strlenWtoA(strValue);
117 | // }
118 | // else if (charset == DC_UNICODE) {
119 | // len = wcslen(strValue);
120 | // }
121 | // else { // DC_BINARY
122 | // len = strLen;
123 | // }
124 | // if (strLen > 0) {
125 | // if (len > strLen) // copy max strLen chars
126 | // len = strLen;
127 | // dprintf("len=%i\n", len);
128 | // if (charset == DC_ANSI) {
129 | // context->convertWtoA(strValue, len, /*out*/(char*)pbBuf);
130 | // }
131 | // else {
132 | // memcpy(pbBuf, strValue, len * sizeof(wchar_t));
133 | // }
134 | // }
135 | // strLen = len;
136 | // }
137 | // dprintf("-WStringType::getStringData\n");
138 | //}
139 | //
140 | //
141 |
--------------------------------------------------------------------------------
/src/types/CharType.cpp:
--------------------------------------------------------------------------------
1 | #include "../stdafx.h"
2 |
3 | #include "CharType.h"
4 |
5 | #include "../Runtime.h"
6 | #include "../PBException.h"
7 |
8 | CharType::CharType(const string &typeSignature, size_t sizeOf)
9 | : RawType(typeSignature, sizeOf)
10 | {
11 | }
12 |
13 | template
14 | class Convertor: public T {
15 | public:
16 | inline size_t strLen(ExecutionContext *context, BYTE * buf, int arrayLen, DataCharset charset);
17 | inline void setArrayData(ExecutionContext *context, BYTE * &cBuf, BYTE * pbBuf, int strLen, DataCharset charset);
18 | inline void getArrayData(ExecutionContext *context, BYTE * cBuf, BYTE *pbBuf, int &strLen, DataCharset charset);
19 | };
20 |
21 | template
22 | inline size_t Convertor::strLen(ExecutionContext *context, BYTE * buf, int arrayLen, DataCharset charset)
23 | {
24 | size_t strLen = 0;
25 | if (buf != NULL) {
26 | if (charset == CHARSET) {
27 | strLen = tstrnlen((type_t*) buf, arrayLen);
28 | }
29 | else {
30 | strLen = strlenTtoS(context, (inv_type_t*)buf, arrayLen);
31 | }
32 | }
33 | return strLen;
34 | }
35 |
36 | template
37 | inline void Convertor::setArrayData(ExecutionContext *context, BYTE * &cBuf, BYTE * pbBuf, int strLen, DataCharset charset)
38 | {
39 | dprintf("+%s::setArrayData cBuf=%p, strLen=%i, s='%s'\n", TypeName.c_str(), cBuf ,strLen, pbBuf);
40 |
41 | if (pbBuf == NULL)
42 | throw RuntimeException(context, TypeName+ "::setArrayData pbBuf == NULL");
43 |
44 |
45 | if (pbBuf != NULL) {
46 | if (charset == CHARSET || charset == DC_BINARY) {
47 | if (cBuf == NULL) {
48 | strLen += 1;
49 | allocateBuffer(context, cBuf, strLen);
50 | }
51 | memcpy(cBuf, pbBuf, strLen * sizeof(type_t));
52 | }
53 | else {
54 | cBuf = (BYTE*)convertTtoS(context, (inv_type_t*)pbBuf, strLen, (type_t*)cBuf);
55 | }
56 | }
57 |
58 | dprintf("-%s::setArrayData\n", TypeName.c_str());
59 | }
60 |
61 | template
62 | inline void Convertor::getArrayData(ExecutionContext *context, BYTE * cBuf, BYTE *pbBuf, int &strLen, DataCharset charset)
63 | {
64 | dprintf("+%s::getArrayData cBuf=%p, strLen=%i\n", TypeName.c_str(), cBuf ,strLen);
65 | if (cBuf == NULL)
66 | throw RuntimeException(context, TypeName + "::getArrayData cBuf == NULL");
67 |
68 | type_t *strValue = (type_t*)cBuf;
69 | dprintf("strLen=%i, strValue=%p, strValue='%s'\n", strLen, strValue, strValue);
70 | int len;
71 | if (charset == INV_CHARSET) {
72 | len = strlenStoT(context, strValue);
73 | }
74 | else if (charset == CHARSET) {
75 | len = tstrlen(strValue);
76 | }
77 | else { // DC_BINARY
78 | len = strLen;
79 | }
80 | if (strLen > 0) {
81 | if (len > strLen) // copy max strLen chars
82 | len = strLen;
83 | dprintf("len=%i\n", len);
84 | if (charset == INV_CHARSET) {
85 | convertStoT(context, strValue, len, /*out*/(inv_type_t*)pbBuf);
86 | }
87 | else {
88 | memcpy(pbBuf, strValue, len * sizeof(type_t));
89 | }
90 | }
91 | strLen = len;
92 | dprintf("-%s::getArrayData\n", TypeName.c_str());
93 |
94 | }
95 |
96 | static Convertor convA;
97 | static Convertor convW;
98 |
99 | size_t ACharType::strLen(ExecutionContext *context, BYTE * buf, int arrayLen, DataCharset charset)
100 | {
101 | return convA.strLen(context, buf, arrayLen, charset);
102 | }
103 |
104 | size_t WCharType::strLen(ExecutionContext *context, BYTE * buf, int arrayLen, DataCharset charset)
105 | {
106 | return convW.strLen(context, buf, arrayLen, charset);
107 | }
108 |
109 |
110 | void ACharType::setArrayData(ExecutionContext *context, BYTE * &cBuf, BYTE * pbBuf, int strLen, DataCharset charset)
111 | {
112 | convA.setArrayData(context, cBuf, pbBuf, strLen, charset);
113 | }
114 |
115 |
116 | void WCharType::setArrayData(ExecutionContext *context, BYTE * &cBuf, BYTE * pbBuf, int strLen, DataCharset charset)
117 | {
118 | convW.setArrayData(context, cBuf, pbBuf, strLen, charset);
119 | }
120 |
121 |
122 | void ACharType::getArrayData(ExecutionContext *context, BYTE * cBuf, BYTE *pbBuf, int &strLen, DataCharset charset)
123 | {
124 | convA.getArrayData(context, cBuf, pbBuf, strLen, charset);
125 | }
126 |
127 |
128 |
129 | void WCharType::getArrayData(ExecutionContext *context, BYTE * cBuf, BYTE *pbBuf, int &strLen, DataCharset charset)
130 | {
131 | convW.getArrayData(context, cBuf, pbBuf, strLen, charset);
132 | }
133 |
134 |
135 |
--------------------------------------------------------------------------------
/doc/working-with-structures.html:
--------------------------------------------------------------------------------
1 | Working with C/C++ structures/unions
2 |
3 | PBInvoke supports full access to C++ structs/unions from PowerBuilder.
4 |
5 |
Because there is no equivalents for unions and field types such
6 | as pointers to structures and function pointers in PowerBuilder,
7 | PBInvoke have a special object for storing such values: n_pi_value.
8 |
9 |
Working with nested structures and unions.
10 | Suppose you have the following structure declaration:
11 | n_pi_core lnv_core
12 | lnv_core.of_declare("struct MYSTR { union { int ival; char* sval;} u; char ch;}")
13 |
14 | This is a structure MYSTR which has a field of type char, 'ch', and a field of type union 'u',
15 | which itself has two fields 'ival' and 'sval', which share the same memory.
16 |
17 |
Some examples of working with the structure:
18 | n_pi_core lnv_core
19 | n_pi_value lnv_str
20 |
21 | // Create an instance of the structure in memory
22 | // In C++: MYSTR str;
23 | lnv_str = lnv_core.of_create_value_of("MYSTR");
24 |
25 | // Fill the structure's memory with zero bytes.
26 | // Note, however, that of_create_value_of() does it anyway.
27 | // C++: memset(&str, sizeof(MYSTR), 0);
28 | lnv_str.of_set(0)
29 |
30 | // Assign to sval field of the union
31 | // C++: str.u.sval = "test";
32 | lnv_str.of_item("u").of_set("sval", "test")
33 |
34 | A few words regarding what does n_pi_value.of_item do.
35 | When you call of_item("fieldname"), a n_pi_value is returned which is a reference to the field.
36 | No data is copied. When you modify this reference, the original structure is modified.
37 |
of_item() is used most often for accessing nested structures.
38 | If you have a field of a simple type (string, numeric) you use of_get("field")/of_set("field", value)
39 | instead of of_item("field").
40 |
Also note, that field name in of_item(), of_get(), of_set() is case sensitive.
41 |
42 | // Read the value of ival which now holds the pointer to the string "test" because ival and sval share their memory.
43 | // C++: int i = str.u.ival;
44 | ll_i = lnv_str.of_item("u").of_get("ival")
45 |
46 | // Assign to ch field of the structure
47 | // C++: str.ch = 'A';
48 | lnv_str.of_set("ch", "A")
49 | lnv_str.of_set(2, "A") // Fields can also be accessed by a 1-based index in order of their declarations.
50 |
51 | // Pass the structure as a parameter to a function:
52 | // C++: void fn1(MYSTR s) { }
53 | // fn1(str)
54 | n_pi_method lnv_fn1
55 | lnv_fn1 = lnv_somedll.of_declare_method("void fn1(MYSTR s)")
56 | lnv_fn1.of_invoke(lnv_str) // lnv_str's value is copied.
57 |
58 | // Pass the structure as a pointer parameter to a function:
59 | // C++: void fn2(MYSTR *s) { s->u.sval = "fn2"; };
60 | // fn2(&str)
61 | lnv_fn2 = lnv_somedll.of_declare_method("void fn2(MYSTR *s)")
62 | lnv_fn2.of_invoke(lnv_str) // implicitly gets the address of the structure
63 | //or
64 | lnv_fn2.of_invoke(lnv_str.of_get_addr()) // which is the same, but explicit.
65 |
66 | // If the structure is modified in fn2 we'll see those changes
67 | String ls_mod
68 | ls_mod = lnv_str.of_item("u").of_get("sval") // returns "fn2"
69 |
70 |
71 |
72 |
Working with pointers to structures as fields.
73 | Pointers to a type require dereferencing in order to allow access to the value they point to.
74 |
75 |
76 | lnv_core.of_declare("struct N { int a;}") // declare a struct
77 | lnv_core.of_declare("struct S { N* n;}") // declare a struct with nested pointer to a struct
78 | // create an instance
79 | // C++: S str;
80 | lnv_str = lnv_core.of_create_value_of("S")
81 |
82 | // init the pointer n with the address of an instance of N
83 | // C++: s.n = new N();
84 | lnv_str.of_set("n", lnv_core.of_create_value_of("N"))
85 |
86 | // access the nested field, a
87 | // C++: str.n->a = 123;
88 | lnv_str.of_item("n").of_deref().of_set("a", 123)
89 |
90 | // get the nested structure as separate reference
91 | // C++: N &n = *str.n;
92 | lnv_n = lnv_str.of_item("n").of_deref() // note this is just a reference, not a copy.
93 |
94 | //Now lnv_n.of_get("a") is the same as lnv_str.of_item("n").of_deref().of_get("a")
95 |
96 |
97 | See also
98 | Handling strings (char*, wchar_t*)
99 | Handling TCHAR and TSTR. Unicode/ANSI function name suffixes
100 | Working with callbacks
101 |
102 |
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/src/PBCallback.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "PBCallback.h"
3 | #include "Runtime.h"
4 | #include "Core.h"
5 | #include "PBException.h"
6 |
7 | PBCallback::PBCallback(UINT callbackId, Method *defaultMethodContext)
8 | : CallbackData(defaultMethodContext->getArgStackSize() / sizeof(DWORD), defaultMethodContext->getMethodType()->isStdCall())
9 | , m_callbackId(callbackId)
10 | , m_methodType(defaultMethodContext->getMethodType())
11 | , m_inCall(0)
12 | , m_currentContext(NULL)
13 | , m_hookId(-1)
14 | , m_hhk(NULL)
15 | , m_enable(true)
16 | {
17 | dprintf("PBCallback::PBCallback\n");
18 |
19 | }
20 |
21 | PBCallback::~PBCallback()
22 | {
23 | dprintf("PBCallback::~PBCallback\n");
24 | }
25 |
26 | void PBCallback::createCallbackContext(BYTE *argsPtr)
27 | {
28 | m_inCall ++;
29 | if (m_inCall > 1 || m_contexts.empty()) {
30 | m_contexts.push(MethodContextPtr(new Method(m_methodType, argsPtr)));
31 | }
32 | else {
33 | m_contexts.top()->setArgsPtr(argsPtr);
34 | }
35 | m_currentContext = m_contexts.top().get();
36 |
37 | }
38 | void PBCallback::destroyCallbackContext()
39 | {
40 | if (m_inCall > 1) {
41 | m_contexts.pop();
42 | m_currentContext = m_contexts.top().get();
43 | }
44 | m_inCall --;
45 | }
46 |
47 | void PBCallback::setHookFilter(HHOOK hhk, int hookId, UINT messageFilter[], size_t messageFilterSize)
48 | {
49 | dprintf("PBCallback::setHookFilter\n");
50 | vector& helpers = CoreInstance.getWinHookHelpers();
51 | if (hookId < 0 || hookId >= (int)helpers.size() || helpers[hookId].get() == NULL) {
52 | m_enable = false;
53 | throw RuntimeException("Message filter for this type of hooks is not implemented yet");
54 | }
55 | m_hookId = hookId;
56 | m_hhk = hhk;
57 | m_messageFilter.insert(m_messageFilter.end(), &messageFilter[0], &messageFilter[messageFilterSize]);
58 | m_enable = true;
59 | }
60 | BOOL PBCALL cb_setHookFilter(PBCallback *callback, HHOOK hhk, int hookId, UINT messageFilter[], size_t messageFilterSize)
61 | {
62 | try {
63 | callback->setHookFilter(hhk, hookId, messageFilter, messageFilterSize);
64 | return true;
65 | }
66 | catch (...) {
67 | return false;
68 | }
69 | }
70 |
71 | //this method must NOT throw any exception
72 | int CALLBACK PBCallback::callback()
73 | {
74 | LRESULT result;
75 | if (!m_enable)
76 | return 0;
77 | if (m_hookId >= 0 && m_hhk != NULL) {
78 | vector& helpers = CoreInstance.getWinHookHelpers();
79 | if (m_hookId < (int)helpers.size() && helpers[m_hookId].get() != NULL) {
80 | if (helpers[m_hookId]->skip(m_hhk, (PHookProcArgs)m_argsPtr, m_messageFilter, result))
81 | return result;
82 | }
83 | }
84 |
85 | dprintf("+PBCallback::callback\n");
86 | static int counter = 0;
87 | counter ++;
88 | int callbackRetVal = 0;
89 | Method *methodContext = NULL;
90 | try {
91 | HWND messageHandler = CoreInstance.getCallbackMessageHandler();
92 | if (messageHandler == NULL)
93 | throw RuntimeException("Callback message handler is not specified");
94 |
95 | createCallbackContext((BYTE*)m_argsPtr);
96 | dprintf("context=%p, m_argsPtr=%p\n", m_currentContext, m_argsPtr);
97 |
98 | dprintf("SendMessage incall=%i, counter=%i, messageHandler=%i, messageId=%i, m_callbackId=%i\n",
99 | m_inCall, counter, messageHandler, CoreInstance.getCallbackMessageId(), m_callbackId);
100 | result = SendMessage(messageHandler, CoreInstance.getCallbackMessageId(), m_callbackId, (LPARAM)m_currentContext);
101 | dprintf("SendMessage result=%i\n", result);
102 | if (result == 1) {
103 | // executed OK
104 | callbackRetVal = *((int*)m_currentContext->getReturnValueAddr());
105 | }
106 | else {
107 | // callback id or message handler was not found
108 | callbackRetVal = 0;
109 | }
110 | destroyCallbackContext();
111 | }
112 | catch (...) {
113 | destroyCallbackContext();
114 | dprintf("-PBCallback::callback with exception\n");
115 | }
116 | dprintf("-PBCallback::callback\n");
117 | return callbackRetVal;
118 | }
119 |
120 | PBCallback* PBCALL cb_create(UINT callbackId, Method* methodContext)
121 | {
122 | PBExceptionStorageInstance.clearLastExceptionMessage();
123 | try {
124 | return new PBCallback(callbackId, methodContext);
125 | }
126 | catch (...) {
127 | return NULL;
128 | }
129 | }
130 |
131 | void PBCALL cb_destroy(PBCallback* instance)
132 | {
133 | PBExceptionStorageInstance.clearLastExceptionMessage();
134 | if (instance != NULL)
135 | delete instance;
136 | }
137 |
138 | DWORD PBCALL cb_getAddr(PBCallback* instance)
139 | {
140 | PBExceptionStorageInstance.clearLastExceptionMessage();
141 | return instance->getCallbackAddr();
142 | }
143 |
144 | DWORD PBCallback::getMethodAddr()
145 | {
146 | return getCallbackAddr();
147 | }
148 |
--------------------------------------------------------------------------------
/doc/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: arial, sans-serif;
3 | }
4 |
5 | h1, h2, h3 {
6 | font-family: tahoma;
7 | }
8 |
9 | h1 {
10 | }
11 | h1, h1 a {
12 | background-color1: #9ebad2;
13 | border1: dotted 1px #6e8aa2;
14 | color: #5e7a92;
15 | }
16 |
17 | h2 {
18 | border1: 1px solid #6e8aa2;
19 | background-color1: #9ebad2;
20 | color: #3e5a72;
21 | padding-top: 4px;
22 | padding-bottom: 4px;
23 | margin-bottom: 2px;
24 | border-bottom: 2px solid ;
25 | padding-left: 0;
26 | }
27 |
28 | h3 {
29 | margin: 1em 0 3px 0;
30 | padding-left: 0;
31 | color: #3e5a72;
32 | }
33 |
34 | #container {
35 | padding: 0;
36 | margin: 1% auto 0 auto;
37 | position: relative;
38 | }
39 | #main {
40 | margin-left: 0;
41 | }
42 |
43 | #footer, #header {
44 | border-top: 2px solid #3e5a72;
45 | border-bottom: 2px solid #3e5a72;
46 | margin-top: 1%;
47 | position: relative;
48 | clear: both;
49 | font-size: 70%;
50 | }
51 |
52 | #copyright {
53 | display: inline;
54 | padding-left: 2%;
55 | padding-rgiht: 2%;
56 | }
57 | #report {
58 | display: inline;
59 | padding-left: 2%;
60 | padding-rgiht: 2%;
61 | }
62 |
63 | hr {
64 | }
65 |
66 |
67 | table {
68 | border: 1px solid #808080;
69 | border-collapse: collapse;
70 | margin: 0;
71 | }
72 | td, th {
73 | border: 1px solid #8080a0;
74 | margin: 0;
75 | padding: 2px;
76 | }
77 | th {
78 | background-color: #eeeeff;
79 | color: #3e5a72;
80 | }
81 |
82 |
83 |
84 | div.section {
85 | border: 1px dotted #EEEEEE;
86 | padding: 1em;
87 | background-color1: #fffff7;
88 |
89 | }
90 | .section p {
91 | }
92 |
93 | #main p {
94 | }
95 |
96 | td.product {
97 | text-align: left;
98 | }
99 | td.price {
100 | text-align: center;
101 | }
102 | td.order {
103 | text-align: center;
104 | }
105 |
106 | a img {
107 | border: none;
108 | }
109 |
110 | .topmenu {
111 | border: 1px dotted green;
112 | padding-left: 1%;
113 | margin-top: 1%;
114 | margin-bottom: 1%;
115 | font-size: 110%;
116 | font-weight: bold;
117 | background-color: #bedaf2;
118 | width: 98.9%;
119 | display: block;
120 | position: relative;
121 | }
122 |
123 | .topmenu ol {
124 | border1: 1px dotted blue;
125 | display: inline;
126 | padding: 0;
127 | margin: 0;
128 | float: left;
129 | }
130 | .topmenu li {
131 | display: inline;
132 | border: 1px solid #8eaac2;
133 | margin: 0;
134 | padding1: 0.3em 0.8em;
135 | padding: 0;
136 | background-color: #9ebad2;
137 | list-style: none;
138 | float: left;
139 | }
140 | .topmenu a:visited, .topmenu a:link, .topmenu a:active {
141 | color: #3e5a72;
142 | text-decoration: none;
143 | }
144 | .topmenu a:hover {
145 | color: #3e5a72;
146 | text-decoration: underline;
147 | }
148 |
149 |
150 |
151 | .floatmenu {
152 | border: 1px solid #bedaf2;
153 | font-size: 110%;
154 | font-weight: bold;
155 | background-color1: #bedaf2;
156 | background-color: white;
157 | display: block;
158 | margin: 2.5em 10px 4px 10px;
159 | padding: 4px;
160 | float: right;
161 | }
162 |
163 | .floatmenu ol {
164 | border1: 1px dotted blue;
165 | display: block;
166 | padding: 0;
167 | margin: 0;
168 | }
169 | .floatmenu li {
170 | display: block;
171 | border: 2px solid ;
172 | border-color: #bedaf2 #7e9ab2 #7e9ab2 #bedaf2;
173 | margin: 0.3em 0.4em;
174 | background-color: #9ebad2;
175 | padding: 0.2em 0.6em;
176 | list-style: none;
177 | text-align: center;
178 | }
179 | .floatmenu a:visited, .floatmenu a:link, .floatmenu a:active {
180 | color: #3e5a72;
181 | text-decoration: none;
182 | }
183 | .floatmenu a:hover {
184 | color: #3e5a72;
185 | text-decoration: underline;
186 | }
187 |
188 | .floatmenu, .topmenu {
189 | font-family: Tahoma;
190 | }
191 |
192 |
193 | div.download {
194 | margin: 0.3em;
195 | padding: 0.3em;
196 | border: solid 1px #bedaf2;
197 | width: auto;
198 | color: #3e5a72;
199 | float1: left;
200 | }
201 |
202 | table.download {
203 | border: solid 1px green;
204 | font-weight: bold;
205 | margin-left: 0.5em;
206 | background1: #CCFFCC;
207 | }
208 |
209 | .download td {
210 | border: 1px solid #00CC00;
211 | padding: 10px;
212 | vertical-align: middle;
213 | }
214 |
215 | .download td, .download a:visited, .download a:link, .download a:active {
216 | color1: #3e5a72;
217 | color: #3e725a;
218 | text-decoration: none;
219 | }
220 | .download a:hover {
221 | color1: #3e5a72;
222 | color: #3e725a;
223 | text-decoration: underline;
224 | }
225 | .download td.icon {
226 | background: url(downg.png) no-repeat right center;
227 | padding-right: 0;
228 | }
229 | .download td.icon a {
230 | padding-right: 32px;
231 | margin-right: 0;
232 | border1: 1px solid red;
233 | }
234 |
235 | pre.pb {
236 | margin-left: 0.3em;
237 | padding: 0.3em;
238 | background-color1: #ccd6e0;
239 | background-color: #ffffee;
240 | border: 1px solid #ccd6e0;
241 | }
242 | pre {
243 | margin-left: 0.3em;
244 | padding: 0.3em;
245 | }
246 |
247 | .cmt {
248 | color: #5e7a92;
249 | }
250 |
251 |
--------------------------------------------------------------------------------
/doc/genhelp/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: arial, sans-serif;
3 | }
4 |
5 | h1, h2, h3 {
6 | font-family: tahoma;
7 | }
8 |
9 | h1 {
10 | }
11 | h1, h1 a {
12 | background-color1: #9ebad2;
13 | border1: dotted 1px #6e8aa2;
14 | color: #5e7a92;
15 | }
16 |
17 | h2 {
18 | border1: 1px solid #6e8aa2;
19 | background-color1: #9ebad2;
20 | color: #3e5a72;
21 | padding-top: 4px;
22 | padding-bottom: 4px;
23 | margin-bottom: 2px;
24 | border-bottom: 2px solid ;
25 | padding-left: 0;
26 | }
27 |
28 | h3 {
29 | margin: 1em 0 3px 0;
30 | padding-left: 0;
31 | color: #3e5a72;
32 | }
33 |
34 | #container {
35 | padding: 0;
36 | margin: 1% auto 0 auto;
37 | position: relative;
38 | }
39 | #main {
40 | margin-left: 0;
41 | }
42 |
43 | #footer, #header {
44 | border-top: 2px solid #3e5a72;
45 | border-bottom: 2px solid #3e5a72;
46 | margin-top: 1%;
47 | position: relative;
48 | clear: both;
49 | font-size: 70%;
50 | }
51 |
52 | #copyright {
53 | display: inline;
54 | padding-left: 2%;
55 | padding-rgiht: 2%;
56 | }
57 | #report {
58 | display: inline;
59 | padding-left: 2%;
60 | padding-rgiht: 2%;
61 | }
62 |
63 | hr {
64 | }
65 |
66 |
67 | table {
68 | border: 1px solid #808080;
69 | border-collapse: collapse;
70 | margin: 0;
71 | }
72 | td, th {
73 | border: 1px solid #8080a0;
74 | margin: 0;
75 | padding: 2px;
76 | }
77 | th {
78 | background-color: #eeeeff;
79 | color: #3e5a72;
80 | }
81 |
82 |
83 |
84 | div.section {
85 | border: 1px dotted #EEEEEE;
86 | padding: 1em;
87 | background-color1: #fffff7;
88 |
89 | }
90 | .section p {
91 | }
92 |
93 | #main p {
94 | }
95 |
96 | td.product {
97 | text-align: left;
98 | }
99 | td.price {
100 | text-align: center;
101 | }
102 | td.order {
103 | text-align: center;
104 | }
105 |
106 | a img {
107 | border: none;
108 | }
109 |
110 | .topmenu {
111 | border: 1px dotted green;
112 | padding-left: 1%;
113 | margin-top: 1%;
114 | margin-bottom: 1%;
115 | font-size: 110%;
116 | font-weight: bold;
117 | background-color: #bedaf2;
118 | width: 98.9%;
119 | display: block;
120 | position: relative;
121 | }
122 |
123 | .topmenu ol {
124 | border1: 1px dotted blue;
125 | display: inline;
126 | padding: 0;
127 | margin: 0;
128 | float: left;
129 | }
130 | .topmenu li {
131 | display: inline;
132 | border: 1px solid #8eaac2;
133 | margin: 0;
134 | padding1: 0.3em 0.8em;
135 | padding: 0;
136 | background-color: #9ebad2;
137 | list-style: none;
138 | float: left;
139 | }
140 | .topmenu a:visited, .topmenu a:link, .topmenu a:active {
141 | color: #3e5a72;
142 | text-decoration: none;
143 | }
144 | .topmenu a:hover {
145 | color: #3e5a72;
146 | text-decoration: underline;
147 | }
148 |
149 |
150 |
151 | .floatmenu {
152 | border: 1px solid #bedaf2;
153 | font-size: 110%;
154 | font-weight: bold;
155 | background-color1: #bedaf2;
156 | background-color: white;
157 | display: block;
158 | margin: 2.5em 10px 4px 10px;
159 | padding: 4px;
160 | float: right;
161 | }
162 |
163 | .floatmenu ol {
164 | border1: 1px dotted blue;
165 | display: block;
166 | padding: 0;
167 | margin: 0;
168 | }
169 | .floatmenu li {
170 | display: block;
171 | border: 2px solid ;
172 | border-color: #bedaf2 #7e9ab2 #7e9ab2 #bedaf2;
173 | margin: 0.3em 0.4em;
174 | background-color: #9ebad2;
175 | padding: 0.2em 0.6em;
176 | list-style: none;
177 | text-align: center;
178 | }
179 | .floatmenu a:visited, .floatmenu a:link, .floatmenu a:active {
180 | color: #3e5a72;
181 | text-decoration: none;
182 | }
183 | .floatmenu a:hover {
184 | color: #3e5a72;
185 | text-decoration: underline;
186 | }
187 |
188 | .floatmenu, .topmenu {
189 | font-family: Tahoma;
190 | }
191 |
192 |
193 | div.download {
194 | margin: 0.3em;
195 | padding: 0.3em;
196 | border: solid 1px #bedaf2;
197 | width: auto;
198 | color: #3e5a72;
199 | float1: left;
200 | }
201 |
202 | table.download {
203 | border: solid 1px green;
204 | font-weight: bold;
205 | margin-left: 0.5em;
206 | background1: #CCFFCC;
207 | }
208 |
209 | .download td {
210 | border: 1px solid #00CC00;
211 | padding: 10px;
212 | vertical-align: middle;
213 | }
214 |
215 | .download td, .download a:visited, .download a:link, .download a:active {
216 | color1: #3e5a72;
217 | color: #3e725a;
218 | text-decoration: none;
219 | }
220 | .download a:hover {
221 | color1: #3e5a72;
222 | color: #3e725a;
223 | text-decoration: underline;
224 | }
225 | .download td.icon {
226 | background: url(downg.png) no-repeat right center;
227 | padding-right: 0;
228 | }
229 | .download td.icon a {
230 | padding-right: 32px;
231 | margin-right: 0;
232 | border1: 1px solid red;
233 | }
234 |
235 | pre.pb {
236 | margin-left: 0.3em;
237 | padding: 0.3em;
238 | background-color1: #ccd6e0;
239 | background-color: #ffffee;
240 | border: 1px solid #ccd6e0;
241 | }
242 | pre {
243 | margin-left: 0.3em;
244 | padding: 0.3em;
245 | }
246 |
247 | .cmt {
248 | color: #5e7a92;
249 | }
250 |
251 |
--------------------------------------------------------------------------------
/pbsrc/Samples/BrowseForFolder/debug/1:
--------------------------------------------------------------------------------
1 | Comparing files libPBInvoke.dll and LIBPBINVOKE.1
2 | 0005C168: 39 36
3 | 0005C169: 38 34
4 | 0005C16A: 65 35
5 | 0005C16C: 65 62
6 | 0005C16D: 62 30
7 | 0005C16E: 38 33
8 | 0005C16F: 66 32
9 | 0005C170: 36 63
10 | 0005C171: 33 31
11 | 0005C172: 30 39
12 | 0005C173: 30 37
13 | 0005C175: 30 61
14 | 0005C176: 33 36
15 | 0005C177: 62 36
16 | 0005C178: 35 39
17 | 0005C179: 37 31
18 | 0005C17A: 37 38
19 | 0005C17B: 38 62
20 | 0005C17C: 32 33
21 | 0005C17D: 64 39
22 | 0005C17E: 62 61
23 | 0005C17F: 64 33
24 | 0005C180: 30 31
25 | 0005C181: 33 35
26 | 0005C182: 30 64
27 | 0005C183: 62 33
28 | 0005C185: 37 31
29 | 0005C186: 64 37
30 | 0005C187: 61 39
31 | 0005C188: 34 30
32 | 0005C189: 33 38
33 | 0005C18A: 63 37
34 | 0005C18D: 38 37
35 | 0005C18E: 33 64
36 | 0005C190: 37 64
37 | 0005C191: 35 61
38 | 0005C192: 30 64
39 | 0005C193: 32 62
40 | 0005C194: 38 39
41 | 0005C195: 36 34
42 | 0005C196: 32 30
43 | 0005C197: 63 62
44 | 0005C198: 39 38
45 | 0005C199: 34 31
46 | 0005C19A: 38 30
47 | 0005C19B: 31 62
48 | 0005C19C: 65 32
49 | 0005C19D: 32 36
50 | 0005C19E: 62 63
51 | 0005C19F: 34 62
52 | 0005C1A0: 36 30
53 | 0005C1A1: 30 31
54 | 0005C1A3: 33 65
55 | 0005C1A4: 62 32
56 | 0005C1A5: 39 62
57 | 0005C1A6: 34 66
58 | 0005C1A7: 66 39
59 | 0005C1A8: 33 30
60 | 0005C1A9: 36 65
61 | 0005C1AB: 39 34
62 | 0005C1AC: 36 61
63 | 0005C1AD: 63 66
64 | 0005C1AE: 34 63
65 | 0005C1AF: 35 63
66 | 0005C1B0: 38 39
67 | 0005C1B1: 33 66
68 | 0005C1B2: 37 30
69 | 0005C1B3: 34 65
70 | 0005C1B5: 38 66
71 | 0005C1B6: 61 34
72 | 0005C1B7: 30 33
73 | 0005C1B8: 37 35
74 | 0005C1B9: 35 66
75 | 0005C1BA: 66 36
76 | 0005C1BB: 34 36
77 | 0005C1BC: 38 61
78 | 0005C1BD: 39 66
79 | 0005C1BE: 30 65
80 | 0005C1BF: 62 31
81 | 0005C1C0: 33 62
82 | 0005C1C1: 66 64
83 | 0005C1C2: 34 65
84 | 0005C1C3: 37 32
85 | 0005C1C4: 65 66
86 | 0005C1C5: 31 65
87 | 0005C1C6: 39 31
88 | 0005C1C7: 34 65
89 | 0005C1C8: 38 31
90 | 0005C1CA: 36 39
91 | 0005C1CB: 31 30
92 | 0005C1CC: 65 66
93 | 0005C1CD: 31 38
94 | 0005C1CE: 33 31
95 | 0005C1CF: 66 64
96 | 0005C1D1: 61 32
97 | 0005C1D2: 37 34
98 | 0005C1D3: 35 61
99 | 0005C1D4: 39 61
100 | 0005C1D5: 35 38
101 | 0005C1D6: 37 62
102 | 0005C1D7: 36 38
103 | 0005C1D8: 31 30
104 | 0005C1D9: 66 34
105 | 0005C1DA: 61 36
106 | 0005C1DB: 30 35
107 | 0005C1DC: 66 64
108 | 0005C1DE: 64 61
109 | 0005C1DF: 32 39
110 | 0005C1E0: 33 61
111 | 0005C1E1: 35 33
112 | 0005C1E2: 31 35
113 | 0005C1E3: 61 39
114 | 0005C1E4: 37 32
115 | 0005C1E5: 33 35
116 | 0005C1E6: 64 34
117 | 0005C1E7: 66 33
118 | 0005C1EA: 61 31
119 | 0005C1EB: 64 31
120 | 0005C1ED: 61 66
121 | 0005C1EE: 31 63
122 | 0005C1EF: 35 39
123 | 0005C1F1: 33 39
124 | 0005C1F2: 62 63
125 | 0005C1F3: 65 34
126 | 0005C1F4: 39 33
127 | 0005C1F6: 39 63
128 | 0005C1F7: 30 34
129 | 0005C1F8: 33 66
130 | 0005C1F9: 62 30
131 | 0005C1FA: 66 34
132 | 0005C1FC: 39 35
133 | 0005C1FD: 36 31
134 | 0005C1FE: 34 64
135 | 0005C1FF: 65 38
136 | 0005C200: 39 33
137 | 0005C201: 39 33
138 | 0005C202: 30 65
139 | 0005C203: 34 31
140 | 0005C204: 65 35
141 | 0005C205: 64 38
142 | 0005C206: 61 64
143 | 0005C207: 31 30
144 | 0005C208: 66 34
145 | 0005C209: 34 33
146 | 0005C20A: 65 36
147 | 0005C20B: 62 39
148 | 0005C20C: 64 61
149 | 0005C20D: 36 63
150 | 0005C20E: 31 35
151 | 0005C20F: 33 31
152 | 0005C210: 66 39
153 | 0005C211: 39 62
154 | 0005C212: 35 34
155 | 0005C213: 32 37
156 | 0005C214: 34 32
157 | 0005C215: 35 38
158 | 0005C216: 33 31
159 | 0005C217: 64 66
160 | 0005C218: 61 36
161 | 0005C219: 39 63
162 | 0005C21A: 31 61
163 | 0005C21B: 61 62
164 | 0005C21D: 31 35
165 | 0005C21E: 30 34
166 | 0005C21F: 38 39
167 | 0005C220: 64 66
168 | 0005C221: 34 31
169 | 0005C222: 65 37
170 | 0005C223: 32 38
171 | 0005C224: 38 66
172 | 0005C225: 32 64
173 | 0005C226: 64 30
174 | 0005C228: 34 61
175 | 0005C229: 38 37
176 | 0005C22A: 38 34
177 | 0005C22B: 39 66
178 | 0005C22C: 37 61
179 | 0005C22D: 36 34
180 | 0005C22F: 65 63
181 | 0005C230: 39 33
182 | 0005C231: 33 38
183 | 0005C232: 31 30
184 | 0005C233: 64 35
185 | 0005C234: 30 33
186 | 0005C235: 31 33
187 | 0005C236: 39 64
188 | 0005C237: 63 62
189 | 0005C238: 35 62
190 | 0005C239: 63 62
191 | 0005C23A: 30 39
192 | 0005C23B: 31 33
193 | 0005C23C: 66 30
194 | 0005C23D: 31 63
195 | 0005C23E: 32 35
196 | 0005C23F: 66 38
197 | 0005C240: 61 64
198 | 0005C241: 39 64
199 | 0005C242: 61 34
200 | 0005C243: 36 61
201 | 0005C244: 33 61
202 | 0005C245: 34 31
203 | 0005C246: 63 31
204 | 0005C247: 34 33
205 | 0005C248: 61 66
206 | 0005C249: 65 34
207 | 0005C24A: 64 39
208 | 0005C24B: 65 34
209 | 0005C24C: 65 34
210 | 0005C24D: 66 65
211 | 0005C24E: 64 61
212 | 0005C24F: 33 62
213 | 0005C250: 30 66
214 | 0005C251: 62 39
215 | 0005C252: 38 61
216 | 0005C253: 33 32
217 | 0005C254: 32 37
218 | 0005C255: 33 66
219 | 0005C256: 62 65
220 | 0005C257: 33 39
221 | 0005C258: 36 34
222 | 0005C259: 30 64
223 | 0005C25A: 32 65
224 | 0005C25B: 61 37
225 | 0005C25C: 61 31
226 | 0005C25D: 34 35
227 | 0005C25E: 33 62
228 | 0005C260: 36 39
229 | 0005C261: 37 32
230 | 0005C262: 61 39
231 | 0005C263: 66 30
232 | 0005C264: 37 35
233 | 0005C265: 38 63
234 | 0005C267: 37 33
235 | 0005C268: 38 61
236 | 0005C269: 36 34
237 | 0005D1D1: 32 30
238 | 0005D1D6: 33 31
239 |
--------------------------------------------------------------------------------
/src/CallbackData.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "DynCallback.h"
3 |
4 | using namespace std;
5 |
6 | CallbackData::CallbackData(int argc, bool stdCall)
7 | {
8 | m_argc = argc;
9 | char *fnBuf = (char *)&thunk_templ;
10 | //printf("fnBuf=%p\n", fnBuf);
11 | if (fnBuf[0] == '\xE9') {
12 | // debug thunk - need to follow jumps to find real fn body
13 | int offset = *(int*)&fnBuf[1];
14 | //printf("jmp %X\n", offset);
15 | fnBuf += offset + 5 /* 1 + 4 bytes for jmp OFFSET */;
16 | }
17 | char *fnBufEnd = (char *)memchr(fnBuf, '\xC2' /*RET xxx*/, 2048 /*max template size */);
18 | if (fnBufEnd == NULL) {
19 | throw InvalidCallbackTemplateException("end of function not found");
20 | }
21 | size_t fnSize = fnBufEnd - fnBuf + 3;
22 | //printf("fnSize=%i\n", fnSize);
23 |
24 | m_thunk.resize(fnSize);
25 | memcpy(&m_thunk[0], fnBuf, m_thunk.size());
26 |
27 |
28 | //dump();
29 |
30 | // correct RET xxx (last 3 bytes of fn body, C2 04 00)
31 | if (m_argc == 0 && !stdCall /* cdecl, caller must clear stack*/) {
32 | m_thunk[m_thunk.size() - 3] = (BYTE)0xC3; // RET 0
33 | }
34 | else {
35 | *((unsigned short*)&m_thunk[m_thunk.size() - 2]) = (unsigned short)m_argc * 4; // RET XXX, XXX > 0
36 | }
37 |
38 | // correct 'this' reference
39 | adjustConstant(THIS_MARKER, (DWORD)this);
40 |
41 | // correct real callback reference
42 | adjustConstant(CALLBACK_MARKER, (DWORD)&staticCallback);
43 |
44 | DWORD oldProtect;
45 | BOOL ret = VirtualProtect(&m_thunk[0], m_thunk.size(), PAGE_EXECUTE_READWRITE, &oldProtect);
46 |
47 | //dump();
48 |
49 | }
50 |
51 | CallbackData::~CallbackData()
52 | {
53 |
54 | }
55 |
56 | int CALLBACK CallbackData::thunk_templ(int dummy)
57 | {
58 | DWORD *argsPtr = (DWORD *) &dummy;
59 | int (CALLBACK *ptr)(DWORD, DWORD *) = (int (CALLBACK*)(DWORD, DWORD *)) CALLBACK_MARKER;
60 | return ptr(THIS_MARKER, argsPtr);
61 | }
62 |
63 | DWORD CallbackData::getCallbackAddr()
64 | {
65 | return (DWORD)&m_thunk[0];
66 | }
67 |
68 | int CallbackData::runCallback()
69 | {
70 | int (CALLBACK *ptr)() = (int (CALLBACK *)()) getCallbackAddr();
71 | int save1, save2;
72 | __asm {
73 | mov save1, esp;
74 | }
75 | int res = ptr();
76 | __asm {
77 | mov save2, esp;
78 | }
79 | printf("save1=%p, save2=%p\n", save1, save2);
80 | return res;
81 | }
82 | int CallbackData::runCallback(int arg1)
83 | {
84 | int (CALLBACK *ptr)(int) = (int (CALLBACK *)(int)) getCallbackAddr();
85 | int save1, save2;
86 | __asm {
87 | mov save1, esp;
88 | }
89 | int res = ptr(arg1);
90 | __asm {
91 | mov save2, esp;
92 | }
93 | printf("save1=%p, save2=%p\n", save1, save2);
94 | return res;
95 | }
96 |
97 | int CallbackData::runCallback(int arg1, int arg2)
98 | {
99 | int (CALLBACK *ptr)(int, int) = (int (CALLBACK *)(int, int)) getCallbackAddr();
100 | int save1, save2;
101 | __asm {
102 | mov save1, esp;
103 | }
104 | int res = ptr(arg1, arg2);
105 | __asm {
106 | mov save2, esp;
107 | }
108 | printf("save1=%p, save2=%p\n", save1, save2);
109 | return res;
110 | }
111 |
112 |
113 |
114 | void CallbackData::dump()
115 | {
116 | for (int i = 0; i < m_thunk.size(); i ++) {
117 | printf("%02X ", (BYTE)m_thunk[i]);
118 | }
119 | printf("\n");
120 | }
121 |
122 | std::string CallbackData::dumpThunk()
123 | {
124 | vector buf;
125 | buf.resize(m_thunk.size() * 3 );
126 | for (int i = 0; i < m_thunk.size(); i ++) {
127 | sprintf(&buf[i * 3], "%02X ", (BYTE)m_thunk[i]);
128 | }
129 | buf.push_back('\0');
130 | return &buf[0];
131 | }
132 |
133 |
134 | void CallbackData::adjustConstant(DWORD marker, DWORD newValue)
135 | {
136 | for (int i = 0; i < m_thunk.size() - 4; i ++) {
137 | if (*(DWORD*)&m_thunk[i] == marker) {
138 | *(DWORD*)&m_thunk[i] = newValue;
139 | return;
140 | }
141 | }
142 | throw InvalidCallbackTemplateException("marker not found");
143 | }
144 |
145 | int CALLBACK CallbackData::staticCallback(CallbackData * thisPtr, DWORD *argsPtr)
146 | {
147 | thisPtr->m_argsPtr = argsPtr;
148 | return thisPtr->callback();
149 | }
150 |
151 | int CALLBACK CallbackData::callback()
152 | {
153 | return 1;
154 | }
155 |
156 |
157 | typedef DWORD (*DWORDMethod)();
158 | DWORD runDynamicMethod(DWORD addr, DWORD *argv, int argc, bool isStdCall) {
159 | DWORDMethod method = (DWORDMethod)addr;
160 | for (int i = argc - 1; i >= 0; i --) {
161 | DWORD arg = argv[i];
162 | __asm push arg;
163 | }
164 | DWORD ret = method();
165 | if (!isStdCall) {
166 | int argsSize = argc * sizeof(DWORD);
167 | __asm add esp, argsSize;
168 | }
169 | return ret;
170 | }
171 |
172 | typedef double (*DoubleMethod)(DWORD, DWORD *, int, bool);
173 | double runDynamicDoubleMethod(DWORD addr, DWORD *argv, int argc, bool isStdCall) {
174 | DoubleMethod method = (DoubleMethod) &runDynamicMethod;
175 | return method(addr, argv, argc, isStdCall);
176 | }
177 |
178 |
179 | typedef float (*FloatMethod)(DWORD, DWORD *, int, bool);
180 | float runDynamicFloatMethod(DWORD addr, DWORD *argv, int argc, bool isStdCall) {
181 | FloatMethod method = (FloatMethod) &runDynamicMethod;
182 | return method(addr, argv, argc, isStdCall);
183 | }
184 |
185 | typedef __int64 (*Int64Method)(DWORD, DWORD *, int, bool);
186 | __int64 runDynamicInt64Method(DWORD addr, DWORD *argv, int argc, bool isStdCall) {
187 | Int64Method method = (Int64Method) &runDynamicMethod;
188 | return method(addr, argv, argc, isStdCall);
189 | }
--------------------------------------------------------------------------------
/src/parser/ASTNode.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include "../types/Basetype.h"
5 | #include
6 | #include "../Compiler.h"
7 | #include "../Runtime.h"
8 | #include "../Core.h"
9 | using namespace std;
10 |
11 | enum {
12 | ATTR_SIGNED = 1 << 0,
13 | ATTR_UNSIGNED = 1 << 1,
14 | ATTR_CHAR = 1 << 2,
15 | ATTR_INT8 = 1 << 3,
16 | ATTR_WCHAR_T = 1 << 4,
17 | ATTR_SHORT = 1 << 5,
18 | ATTR_INT16 = 1 << 6,
19 | ATTR_INT = 1 << 7,
20 | ATTR_INT32 = 1 << 8,
21 | ATTR_LONG = 1 << 9,
22 | ATTR_INT64 = 1 << 10,
23 | ATTR_LONGLONG = 1 << 11,
24 | ATTR_DOUBLE = 1 << 12,
25 | ATTR_FLOAT = 1 << 13,
26 | ATTR_VOID = 1 << 14,
27 | ATTR_COUNT = 15,
28 | };
29 |
30 | struct ASTPtrTypeOp;
31 | struct ASTRefTypeOp;
32 | struct ASTDeclaratorId;
33 | struct ASTNodeList;
34 | struct ASTMethodTypeOp;
35 | struct ASTDeclarator;
36 | struct ASTStructType;
37 | struct ASTArrayTypeOp;
38 |
39 | struct IASTNode {
40 | virtual ~IASTNode() {}
41 | virtual int getTypeId() { return ASTNodeId; }
42 |
43 | inline ASTNodeList* getNodeList() { return (ASTNodeList*)this; }
44 | inline ASTPtrTypeOp* getPtrTypeOp() { return (ASTPtrTypeOp*)this; }
45 | inline ASTRefTypeOp* getRefTypeOp() { return (ASTRefTypeOp*)this; }
46 | inline ASTDeclaratorId* getDeclaratorId() { return (ASTDeclaratorId*)this; }
47 | inline ASTMethodTypeOp* getMethodTypeOp() { return (ASTMethodTypeOp*)this; }
48 | inline ASTDeclarator* getDeclarator() { return (ASTDeclarator*)this; }
49 | inline ASTStructType* getStructType() { return (ASTStructType*)this; }
50 | virtual void setTypeAttr(int attr) { throw RuntimeException("Internal error: illegal use of type attributes"); }
51 | virtual Type getTypeRef() { throw RuntimeException("Internal error: illegal use of type reference"); }
52 |
53 | protected:
54 | enum {
55 | ASTNodeId,
56 | ASTPtrTypeOpId,
57 | ASTRefTypeOpId,
58 | ASTDeclaratorIdId,
59 | ASTNodeListId,
60 | ASTMethodTypeOpId,
61 | ASTArrayTypeOpId,
62 | };
63 | };
64 |
65 | typedef boost::shared_ptr ASTNode;
66 |
67 | struct ASTDeclarator: public IASTNode {
68 | virtual void convert(Type typeRef, NamedType& namedType) = 0;
69 | virtual void setStdCall(bool _isStdCall) = 0;
70 | virtual bool getStdCall() = 0;
71 | };
72 |
73 | struct ASTPtrTypeOp: public ASTDeclarator {
74 | ASTNode arg;
75 | ASTPtrTypeOp(ASTNode _arg) : arg(_arg) {}
76 | virtual int getTypeId() { return ASTPtrTypeOpId; }
77 | virtual void setStdCall(bool _isStdCall) {arg->getDeclarator()->setStdCall(_isStdCall);}
78 | virtual bool getStdCall() {return arg->getDeclarator()->getStdCall();}
79 | virtual void convert(Type typeRef, NamedType& namedType);
80 | };
81 |
82 | struct ASTRefTypeOp: public ASTDeclarator {
83 | ASTNode arg;
84 | ASTRefTypeOp(ASTNode _arg) : arg(_arg) {}
85 | virtual int getTypeId() { return ASTRefTypeOpId; }
86 | virtual void setStdCall(bool _isStdCall) {arg->getDeclarator()->setStdCall(_isStdCall);}
87 | virtual bool getStdCall() {return arg->getDeclarator()->getStdCall();}
88 | virtual void convert(Type typeRef, NamedType& namedType);
89 | };
90 |
91 | struct ASTDeclaratorId: public ASTDeclarator {
92 | bool isStdCall;
93 | string id;
94 | ASTDeclaratorId(const string& _id) : id(_id), isStdCall(CoreInstance.getDefCallingConvention()) {}
95 | virtual int getTypeId() { return ASTDeclaratorIdId; }
96 | virtual void setStdCall(bool _isStdCall) { isStdCall = _isStdCall; };
97 | virtual bool getStdCall() { return isStdCall;}
98 | virtual void convert(Type typeRef, NamedType& namedType);
99 | };
100 |
101 | struct ASTNodeList: public IASTNode {
102 | vector list;
103 | ASTNodeList(ASTNode _node) { list.push_back(_node); }
104 | ASTNodeList() { }
105 | virtual int getTypeId() { return ASTNodeListId; }
106 | void typeDef(Type typeRef, Compiler& compiler);
107 | void nameDef(Type typeRef, Compiler& compiler);
108 | void nameDef(Type typeRef, vector &names, Compiler& compiler);
109 | };
110 |
111 | struct ASTMethodTypeOp: public ASTDeclarator {
112 | bool isStdCall;
113 | vector params;
114 | ASTNode id;
115 | ASTMethodTypeOp(ASTNode _id, vector& _params): params(_params), isStdCall(CoreInstance.getDefCallingConvention()), id(_id) { }
116 | virtual void setStdCall(bool _isStdCall) { isStdCall = _isStdCall; }
117 | virtual bool getStdCall() { return isStdCall;}
118 | virtual int getTypeId() { return ASTMethodTypeOpId; }
119 | virtual void convert(Type typeRef, NamedType& namedType);
120 | };
121 |
122 | struct ASTStructType: public IASTNode {
123 | string name;
124 | Type structType;
125 | Compiler &compiler;
126 | ASTStructType(const string& _name, Compiler &_compiler);
127 | void completeStruct(int structTypeId, vector &_fields);
128 | void forwardDecl();
129 | virtual Type getTypeRef();
130 | };
131 |
132 | struct ASTInternalType: public IASTNode {
133 | int attrs;
134 | Compiler &compiler;
135 | ASTInternalType(Compiler &_compiler);
136 | virtual void setTypeAttr(int attr);
137 | virtual Type getTypeRef();
138 | static string getInternalTypeName(int attr);
139 | };
140 | struct ASTUserType: public IASTNode {
141 | string name;
142 | Compiler &compiler;
143 | ASTUserType(const string& _name, Compiler &_compiler);
144 | virtual Type getTypeRef();
145 | };
146 |
147 | struct ASTArrayTypeOp: public ASTDeclarator {
148 | ASTNode m_arg;
149 | int m_bound;
150 | bool m_isParam;
151 | ASTArrayTypeOp(ASTNode arg, int bound, bool isParam)
152 | : m_arg(arg), m_bound(bound), m_isParam(isParam) {}
153 | virtual int getTypeId() { return ASTArrayTypeOpId; }
154 | virtual void setStdCall(bool isStdCall) {m_arg->getDeclarator()->setStdCall(isStdCall);}
155 | virtual bool getStdCall() {return m_arg->getDeclarator()->getStdCall();}
156 | virtual void convert(Type typeRef, NamedType& namedType);
157 | };
158 |
159 |
--------------------------------------------------------------------------------
/doc/genhelp/working-with-structures.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Working with C/C++ structures/unions
4 |
5 |
6 |
7 |
8 |
9 | PBInvoke documentation. Version 1.X. Visit http://sqlbatch.com/pbinvoke for updates.
10 |
11 | Working with C/C++ structures/unions
12 |
13 | PBInvoke supports full access to C++ structs/unions from PowerBuilder.
14 |
15 |
Because there is no equivalents for unions and field types such
16 | as pointers to structures and function pointers in PowerBuilder,
17 | PBInvoke have a special object for storing such values: n_pi_value.
18 |
19 |
Working with nested structures and unions.
20 | Suppose you have the following structure declaration:
21 |
n_pi_core lnv_core
22 | lnv_core.of_declare("struct MYSTR { union { int ival; char* sval;} u; char ch;}")
23 |
24 | This is a structure MYSTR which has a field of type char, 'ch', and a field of type union 'u',
25 | which itself has two fields 'ival' and 'sval', which share the same memory.
26 |
27 | Some examples of working with the structure:
28 |
n_pi_core lnv_core
29 | n_pi_value lnv_str
30 |
31 | // Create an instance of the structure in memory
32 | // In C++: MYSTR str;
33 | lnv_str = lnv_core.of_create_value_of("MYSTR");
34 |
35 | // Fill the structure's memory with zero bytes.
36 | // Note, however, that of_create_value_of() does it anyway.
37 | // C++: memset(&str, sizeof(MYSTR), 0);
38 | lnv_str.of_set(0)
39 |
40 | // Assign to sval field of the union
41 | // C++: str.u.sval = "test";
42 | lnv_str.of_item("u").of_set("sval", "test")
43 |
44 | A few words regarding what does n_pi_value.of_item do.
45 | When you call of_item("fieldname"), a n_pi_value is returned which is a reference to the field.
46 | No data is copied. When you modify this reference, the original structure is modified.
47 | of_item() is used most often for accessing nested structures.
48 | If you have a field of a simple type (string, numeric) you use of_get("field")/of_set("field", value)
49 | instead of of_item("field").
50 |
Also note, that field name in of_item(), of_get(), of_set() is case sensitive.
51 |
// Read the value of ival which now holds the pointer to the string "test" because ival and sval share their memory.
52 | // C++: int i = str.u.ival;
53 | ll_i = lnv_str.of_item("u").of_get("ival")
54 |
55 | // Assign to ch field of the structure
56 | // C++: str.ch = 'A';
57 | lnv_str.of_set("ch", "A")
58 | lnv_str.of_set(2, "A") // Fields can also be accessed by a 1-based index in order of their declarations.
59 |
60 | // Pass the structure as a parameter to a function:
61 | // C++: void fn1(MYSTR s) { }
62 | // fn1(str)
63 | n_pi_method lnv_fn1
64 | lnv_fn1 = lnv_somedll.of_declare_method("void fn1(MYSTR s)")
65 | lnv_fn1.of_invoke(lnv_str) // lnv_str's value is copied.
66 |
67 | // Pass the structure as a pointer parameter to a function:
68 | // C++: void fn2(MYSTR *s) { s->u.sval = "fn2"; };
69 | // fn2(&str)
70 | lnv_fn2 = lnv_somedll.of_declare_method("void fn2(MYSTR *s)")
71 | lnv_fn2.of_invoke(lnv_str) // implicitly gets the address of the structure
72 | //or
73 | lnv_fn2.of_invoke(lnv_str.of_get_addr()) // which is the same, but explicit.
74 |
75 | // If the structure is modified in fn2 we'll see those changes
76 | String ls_mod
77 | ls_mod = lnv_str.of_item("u").of_get("sval") // returns "fn2"
78 |
79 |
80 |
81 | Working with pointers to structures as fields.
82 | Pointers to a type require dereferencing in order to allow access to the value they point to.
83 |
84 | lnv_core.of_declare("struct N { int a;}") // declare a struct
85 | lnv_core.of_declare("struct S { N* n;}") // declare a struct with nested pointer to a struct
86 | // create an instance
87 | // C++: S str;
88 | lnv_str = lnv_core.of_create_value_of("S")
89 |
90 | // init the pointer n with the address of an instance of N
91 | // C++: s.n = new N();
92 | lnv_str.of_set("n", lnv_core.of_create_value_of("N"))
93 |
94 | // access the nested field, a
95 | // C++: str.n->a = 123;
96 | lnv_str.of_item("n").of_deref().of_set("a", 123)
97 |
98 | // get the nested structure as separate reference
99 | // C++: N &n = *str.n;
100 | lnv_n = lnv_str.of_item("n").of_deref() // note this is just a reference, not a copy.
101 |
102 | //Now lnv_n.of_get("a") is the same as lnv_str.of_item("n").of_deref().of_get("a")
103 |
104 |
105 | See also
106 | Handling strings (char*, wchar_t*)
107 | Handling TCHAR and TSTR. Unicode/ANSI function name suffixes
108 | Working with callbacks
109 |
110 |
111 |
112 |
113 |
114 |
115 |
118 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/src/parser/ASTNode.cpp:
--------------------------------------------------------------------------------
1 | #include "../stdafx.h"
2 | #include "ASTNode.h"
3 |
4 | #include "../types/PointerType.h"
5 | #include "../types/RefType.h"
6 | #include "../types/MethodType.h"
7 | #include "../types/StructType.h"
8 | #include "../types/ArrayType.h"
9 | #include "../Core.h"
10 |
11 | //typedef int iii;
12 | //typedef int iii;
13 |
14 | int __cdecl fn1();
15 | int *__cdecl fn2();
16 | int ( __cdecl * fn3)();
17 | //int ( * __cdecl fn4)(); //warning C4229: anachronism used : modifiers on data are ignored
18 | //typedef __declspec(align(1)) struct S1 {}; //warning C4091: 'typedef ' : ignored on left of 'S1' when no variable is declared
19 | //__declspec(align(1)) struct S2 {};
20 |
21 |
22 | void ASTDeclaratorId::convert(Type typeRef, NamedType& namedType)
23 | {
24 | namedType.name = id;
25 | namedType.type = typeRef;
26 | }
27 |
28 | void ASTPtrTypeOp::convert(Type typeRef, NamedType& namedType)
29 | {
30 | arg->getDeclarator()->convert(Type(new PointerType(typeRef)), namedType);
31 | }
32 |
33 | void ASTRefTypeOp::convert(Type typeRef, NamedType& namedType)
34 | {
35 | arg->getDeclarator()->convert(Type(new RefType(typeRef)), namedType);
36 | }
37 |
38 | void ASTArrayTypeOp::convert(Type typeRef, NamedType& namedType)
39 | {
40 | if (/*m_bound == 0 ||*/ m_isParam) {
41 | typeRef = Type(new PointerType(typeRef));
42 | }
43 | else {
44 | typeRef = Type(new ArrayType(typeRef, m_bound));
45 | }
46 | m_arg->getDeclarator()->convert(typeRef, namedType);
47 | }
48 |
49 |
50 | void ASTMethodTypeOp::convert(Type typeRef, NamedType& namedType)
51 | {
52 | Type methodType = Type(new MethodType(typeRef, params, isStdCall));
53 | id->getDeclarator()->convert(methodType, namedType);
54 | }
55 |
56 | void ASTNodeList::typeDef(Type typeRef, Compiler& compiler)
57 | {
58 | for (size_t i = 0; i < list.size(); i ++) {
59 | NamedType namedType;
60 | list[i]->getDeclarator()->convert(typeRef, namedType);
61 | compiler.defineType(namedType.name, namedType.type);
62 | }
63 | }
64 |
65 |
66 |
67 |
68 | void ASTNodeList::nameDef(Type typeRef, Compiler& compiler)
69 | {
70 | for (size_t i = 0; i < list.size(); i ++) {
71 | NamedType namedType;
72 | list[i]->getDeclarator()->convert(typeRef, namedType);
73 | compiler.defineName(namedType.name, namedType.type);
74 | }
75 | }
76 | void ASTNodeList::nameDef(Type typeRef, vector &names, Compiler& compiler)
77 | {
78 | for (size_t i = 0; i < list.size(); i ++) {
79 | NamedType namedType;
80 | list[i]->getDeclarator()->convert(typeRef, namedType);
81 | names.push_back(namedType);
82 | }
83 | }
84 | //void ASTDeclaratorId::setStdCall(bool _isStdCall)
85 | //{
86 | // throw RuntimeException("Cannot apply " + string(_isStdCall ? "__stdcall":"__cdecl") +
87 | // " to identifier '" + id + "'");
88 | //}
89 |
90 |
91 | ASTStructType::ASTStructType(const string& _name, Compiler &_compiler)
92 | : name(_name)
93 | , compiler(_compiler)
94 | {
95 | forwardDecl();
96 | }
97 |
98 | void ASTStructType::completeStruct(int structTypeId, vector &fields)
99 | {
100 | bool isUnion;
101 | if (structTypeId == TC_STRUCT_TYPE)
102 | isUnion = false;
103 | else if (structTypeId == TC_UNION_TYPE)
104 | isUnion = true;
105 | else
106 | throw RuntimeException("Internal error: Uknown struct type ID used: " + string(CUtil::toString(structTypeId)));
107 |
108 | ((StructType*)structType.get())->complete(fields, CoreInstance.getPack(), 0, isUnion); // TODO add align (declspec)
109 |
110 | dprintf("defineStruct, type=%p, sig=%s\n", structType.get(), structType->getTypeSignature("*").c_str());
111 | structType = compiler.defineType(name, structType);
112 | }
113 |
114 | Type ASTStructType::getTypeRef()
115 | {
116 | return structType;
117 | }
118 |
119 | void ASTStructType::forwardDecl()
120 | {
121 | structType = Type(new StructType(name));
122 | compiler.defineTag(name, structType);
123 | }
124 |
125 |
126 | ASTInternalType::ASTInternalType(Compiler &_compiler)
127 | : compiler(_compiler)
128 | , attrs (0)
129 | {
130 |
131 | }
132 | void ASTInternalType::setTypeAttr(int attr)
133 | {
134 | attrs = attrs | attr;
135 | }
136 |
137 |
138 | Type ASTInternalType::getTypeRef()
139 | {
140 | return compiler.findType(getInternalTypeName(attrs));
141 | }
142 |
143 | string ASTInternalType::getInternalTypeName(int attrs)
144 | {
145 | // check check combinations of signed/unsigned
146 | if ((attrs & ATTR_SIGNED) && (attrs & ATTR_UNSIGNED))
147 | throw RuntimeException("Signed/unsigned keywords mutually exclusive");
148 | // clear signed/unsigned - it's just ignored
149 | attrs = attrs & (~ (ATTR_SIGNED | ATTR_UNSIGNED));
150 |
151 | //check combinations of internal types
152 | int currAttr = 1;
153 | int usedAttrs = 0;
154 | for (int i = 0; i < ATTR_COUNT; i ++, currAttr = currAttr << 1) {
155 | if (attrs & currAttr)
156 | usedAttrs ++;
157 | }
158 | if (usedAttrs > 1)
159 | throw RuntimeException("Illegal use of internal types: more than one type specified");
160 |
161 | // default type: int
162 | if (usedAttrs == 0)
163 | attrs = ATTR_INT;
164 |
165 | // map type implementations
166 | #define MAP_TYPE(s, t) if (attrs & s) { attrs = (attrs | t) & ~s;}
167 | MAP_TYPE(ATTR_INT8, ATTR_CHAR);
168 | MAP_TYPE(ATTR_INT16, ATTR_SHORT);
169 | MAP_TYPE(ATTR_INT32, ATTR_INT);
170 | MAP_TYPE(ATTR_LONG, ATTR_INT);
171 | MAP_TYPE(ATTR_LONGLONG, ATTR_INT64);
172 |
173 | // map attrs to type name
174 | #define MAP_TYPE_NAME(s, t) case s: typeName = t; break;
175 | string typeName;
176 | switch (attrs) {
177 | MAP_TYPE_NAME(ATTR_VOID, "void")
178 | MAP_TYPE_NAME(ATTR_CHAR, "char")
179 | MAP_TYPE_NAME(ATTR_WCHAR_T, "wchar_t")
180 | MAP_TYPE_NAME(ATTR_INT8, "__int8")
181 | MAP_TYPE_NAME(ATTR_INT16, "__int16")
182 | MAP_TYPE_NAME(ATTR_SHORT, "short")
183 | MAP_TYPE_NAME(ATTR_INT, "int")
184 | MAP_TYPE_NAME(ATTR_LONG, "long")
185 | MAP_TYPE_NAME(ATTR_INT32, "__int32")
186 | MAP_TYPE_NAME(ATTR_INT64, "__int64")
187 | MAP_TYPE_NAME(ATTR_LONGLONG, "longlong")
188 | MAP_TYPE_NAME(ATTR_FLOAT, "float")
189 | MAP_TYPE_NAME(ATTR_DOUBLE, "double")
190 | default:
191 | throw RuntimeException("Internal error: unknown type attr " + string(CUtil::toString(attrs)));
192 | }
193 | return typeName;
194 | }
195 |
196 | ASTUserType::ASTUserType(const string& _name, Compiler &_compiler)
197 | : name(_name)
198 | , compiler(_compiler)
199 | {
200 |
201 | }
202 |
203 | Type ASTUserType::getTypeRef()
204 | {
205 | return compiler.findType(name);
206 | }
207 |
208 |
--------------------------------------------------------------------------------
/doc/working-with-callbacks.html:
--------------------------------------------------------------------------------
1 | Working with callbacks
2 |
3 | PowerBuilder does not support PowerScript code to be directly called from external functions.
4 |
5 |
As of PB9 there is a possibility to write a C++ extension for that task using PBNI.
6 | However, implementing callbacks using PBNI has the following limitations:
7 |
PBNI requires knowledge of C++ from PowerBuilder developer
8 | PBNI extensions are quite hard to write and debug.
9 | PBNI requires separate DLLs for ANSI and Unicode versions.
10 | PBNI is available only as of PB9.
11 | Also, there are additional limitations not related to PBNI.
12 |
It's hard to implement (even in C++) passing of context data to the callback if the caller does not support that.
13 | A charset conversion is needed when the caller is ANSI and PB is Unicode and vice versa.
14 |
15 | PBInvoke has support for declaring and using callbacks directly in PowerScript code
16 | without these limitations.
17 |
18 |
Callback declaration
19 | In order to declare a callback you need the following steps:
20 |
Inherit a custom class from n_pi_method
21 | In the constructor event, call of_declare_callback() with a callback type declaration
22 | or a type name (in case the type was declared earlier).
23 | Extend the ue_callback event
24 |
25 | Example:
26 |
27 | // in n_cst_timerproc's constructor (inherited from n_pi_method)
28 | n_pi_core lnv_core
29 |
30 | lnv_core.of_declare("&
31 | typedef VOID CALLBACK TimerProc(&
32 | HWND hwnd, &
33 | UINT uMsg, &
34 | UINT_PTR idEvent, &
35 | DWORD dwTime &
36 | );&
37 | ")
38 |
39 | of_declare_callback("TimerProc")
40 |
41 |
42 |
43 |
Getting callback address
44 | Use n_pi_method.of_get_addr() to get the numeric value of the callback address ready to be passed to
45 | an external function which accepts function pointers of this type.
46 |
47 | Example:
48 |
49 | n_cst_timerproc lnv_timerproc
50 | lnv_timerproc = Create n_cst_timerproc
51 |
52 | // ef_SetTimer is an external function, alias for WinAPI SetTimer
53 | ll_timer = ef_SetTimer(0, 0, 1000, lnv_timerproc.of_get_addr())
54 |
55 |
56 |
57 |
Accessing callback parameters and returning result
58 |
59 | In the ue_callback event, callback parameters can be retrieved by
60 | calling of_get_param("paramname").
61 |
62 |
The return value is passed to the caller of the callback using usual RETURN operator.
63 | Note, that PBInvoke does not support the following types as return types of callbacks:
64 |
float(real), double
65 | longlong
66 | structs/unions of size of more than 4 bytes
67 | However, pointers or references to those type are supported.
68 |
69 |
Example:
70 | ulong hwnd
71 | ulong uMsg
72 | ulong idEvent
73 | ulong dwTime
74 |
75 | // retrieve parameters
76 | hwnd = of_get_param("hwnd")
77 | uMsg = of_get_param("uMsg")
78 | idEvent = of_get_param("idEvent")
79 | dwTime = of_get_param("dwTime")
80 |
81 | // process event
82 | ...
83 |
84 | Return 0
85 |
86 |
87 |
Callback context data
88 | All context data needed by a callback can be stored in the instance variables of the callback object
89 | (which is a descendant of n_pi_method).
90 |
That is possible because PBInvoke generates a unique phisical address (function pointer) for
91 | each callback object, and when an external function calls your callback via that address, PBInvoke maps that call
92 | exactly to your object.
93 |
94 |
95 |
Performance of callbacks
96 | Marshalling parameters between C++ and PB is a slow operation (compared to PB external functions calls) due to
97 | the flexibility PBInvoke provides. If a PB callback is used as a handler for intercepting GUI messages
98 | (e.g. via calling SetWindowsHookEx), then it may cause slow repaint of UI, or even a hang for a long time,
99 | because UI generates huge amount of messages, most of which are ignored by the callback but take time for marshalling.
100 |
101 |
PBInvoke provides an optimization for that case. For callbacks used with SetWindowsHookEx WinAPI
102 | function, it's possible to setup a filter for message ID's which are processed by the callback.
103 | If a message ID does not pass the filter, the PowerScript code of the callback will not be called and all the processing
104 | will be done in C++ according to the rules described in MSDN for SetWindowsHookEx hooks: call
105 | CallNextHookEx.
106 |
In order to activate the message filter you must call of_set_windows_hook_filter() immediately
107 | after calling SetWindowsHookEx().
108 |
Syntax:
109 |
110 | callback.of_set_windows_hook_filter(hook_handle, hook_type, message_id_array[])
111 |
112 | where
113 |
callback - callback object
114 | hook_handle - hook handle returned by SetWindowsHookEx()
115 | hook_type - one of supported by PBInvoke hook types (WH_CALLWNDPROCRET, WH_CALLWNDPROC, WH_GETMESSAGE)
116 | message_id_array[] - array of long integers filled with accepted message ID's
117 |
118 |
119 | Example:
120 | // This code is part of CustomSaveAs sample, which demonstrates
121 | // using callbacks for customizing Windows Shell 'Save As' dialog.
122 | Long ll_hInstance, ll_hThreadID
123 |
124 | ll_hInstance = inv_GetWindowLong.of_invoke(al_windowhandle, n_pi_winapi.GWL_HINSTANCE)
125 | ll_hThreadID = inv_GetCurrentThreadId.of_invoke()
126 |
127 | il_hHook = inv_SetWindowsHookEx.of_invoke(n_pi_winapi.WH_CALLWNDPROCRET, this.of_get_addr(), ll_hInstance, ll_hThreadID)
128 |
129 | // IMPORTANT! As number of messages sent to UI related windows hooks is really huge,
130 | // processing them all in PowerScript is inefficient, and probably will hang the UI.
131 | // PBInvoke can efficiently filter hook messages by message id.
132 | // The following call enables this feature.
133 | // of_set_windows_hook_filter must be called immediately after SetWindowsHookEx()
134 | // The args: hook handle, hook type, and array of message ids which pass via filter to the hook.
135 | of_set_windows_hook_filter(il_hHook, n_pi_winapi.WH_CALLWNDPROCRET, &
136 | {n_pi_winapi.CB_ADDSTRING, n_pi_winapi.CB_SETCURSEL} )
137 |
138 | // Currently only WH_CALLWNDPROCRET, WH_CALLWNDPROC, WH_GETMESSAGE hook types are
139 | // supported with this filtering feature
140 |
141 |
142 |
See also
143 | Calling DLL functions using PBInvoke
144 |
145 |
146 |
--------------------------------------------------------------------------------
/src/Runtime.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #pragma warning (disable:4786)
4 | #include
5 |
6 | #include
7 |
8 | //#include "DataTypes.h"
9 | #include "types/BaseType.h"
10 | #include "types/MethodType.h"
11 | #include "MethodInstance.h"
12 |
13 | using namespace std;
14 |
15 |
16 | class ParamStorage;
17 | class IRuntimeExceptionRegistry;
18 |
19 | class RuntimeException
20 | {
21 | public:
22 | string formatErrorMessage(const string &prefix, const string &suffix, DWORD error);
23 | RuntimeException(const string &msg = "", DWORD lastOsError = 0);
24 | RuntimeException(IRuntimeExceptionRegistry *registry, const string &msg = "", DWORD lastOsError = 0);
25 | inline string& getMessage() { return m_message; }
26 | private:
27 | string m_message;
28 | void init(IRuntimeExceptionRegistry *registry, const string &msg = "", DWORD lastOsError = 0);
29 | };
30 |
31 | class IRuntimeExceptionRegistry{
32 | public:
33 | /** Register exception */
34 | virtual void registerException(RuntimeException &e) = 0;
35 | virtual string getLastException() = 0;
36 | virtual void clearLastExceptionMessage() = 0;
37 | };
38 |
39 | class ExecutionContext: public IRuntimeExceptionRegistry
40 | {
41 | public:
42 | ExecutionContext() {}
43 | virtual ~ExecutionContext();
44 |
45 | /**
46 | Converts ANSI string to Unicode.
47 | Allocates memory if needed. Memory is freed auto on scope exit.
48 |
49 | @param srcString source ANSI string with trailing zero char.
50 | @param strLen length of srcString in characters.
51 | @param buf preallocated buffer
52 | */
53 | wchar_t* convertAtoW(const char *srcString, int strLen = -1, wchar_t *buf = NULL);
54 |
55 | /**
56 | Converts ANSI string length to Unicode string length.
57 | No memory is allocated.
58 |
59 | @param srcString source ANSI string with trailing zero char.
60 | @param strLen length of srcString in characters (not counting zero char).
61 |
62 | @return length of Unicode string in characters (not counting zero char)
63 | */
64 | int strlenAtoW(const char *srcString, int strLen = -1);
65 |
66 | /**
67 | Converts Unicode string to ANSI.
68 | Allocates memory if needed. Memory is freed auto on scope exit.
69 |
70 | @param srcString source Unicode string with trailing zero char.
71 | @param strLen length of srcString in characters.
72 | @param buf preallocated buffer
73 | */
74 | char* convertWtoA(const wchar_t *srcString, int strLen = -1, char *buf = NULL);
75 |
76 | /**
77 | Converts Unicode string length to ANSI string length.
78 | No memory is allocated.
79 |
80 | @param srcString source Unicode string with trailing zero char.
81 | @param strLen length of srcString in characters (not counting zero char).
82 |
83 | @return length of Unicode string in characters (not counting zero char)
84 | */
85 | int strlenWtoA(const wchar_t *srcString, int strLen = -1);
86 |
87 | /** Register exception text */
88 | void registerException(RuntimeException &e);
89 |
90 |
91 | virtual string getLastException();
92 |
93 | virtual void clearLastExceptionMessage() { m_lastExceptionMessage = ""; }
94 |
95 | /**
96 | Allocates buffer for data, pointers to which are passed as params.
97 | Callers of setParam must copy data to the buffer in order to pass the pointer to it as param.
98 | This is needed for re-entrance.
99 | These buffers are freed automatically on ParamStorage scope's exit
100 |
101 | @param size Buffer size in bytes.
102 |
103 | @return Pointer to allocated buffer
104 | */
105 | BYTE * allocateBuffer(int size, int align = 1);
106 |
107 | virtual void clear();
108 |
109 | protected:
110 | /** Allocated param buffers */
111 | vector m_buffers;
112 |
113 | /** Allocated param buffers sizes*/
114 | vector m_bufferSizes;
115 |
116 | /** The last exception occured during calls to ExecutionContext.
117 | TODO store previous exceptions */
118 | string m_lastExceptionMessage;
119 |
120 | void clearBuffers();
121 | };
122 |
123 | /**
124 | Class implementing storage of and access to params of a method .
125 | TODO merge to class Method
126 |
127 | */
128 | class ParamStorage: public ExecutionContext {
129 | public:
130 | BYTE * getParamAddr(int paramIndex);
131 | /**
132 | Ctor.
133 |
134 | @param paramTypes Array of param Types (metadata)
135 | */
136 | //ParamStorage(vector ¶mTypes, BYTE* argsPtr = NULL);
137 | ParamStorage(vector ¶ms, BYTE* argsPtr = NULL);
138 | ParamStorage() : m_storageType(Type()) {}
139 |
140 | /**
141 | Dtor.
142 | */
143 | virtual ~ParamStorage();
144 |
145 |
146 | /**
147 | Frees the allocated buffers and clears the params values.
148 | Must be called before re-using the ParamStorage instance.
149 | */
150 | //void clearParamData();
151 |
152 | virtual void clear();
153 |
154 | size_t getArgStackSize();
155 | inline void setArgsPtr(BYTE *argsPtr) { m_paramDataPtr = argsPtr; }
156 |
157 | void dumpData(const string &text = "");
158 | protected:
159 |
160 | /** Packed params binary values ready to be passed to a C function */
161 | blob m_paramDataBuf;
162 | BYTE* m_paramDataPtr;
163 |
164 | private:
165 |
166 | /** Init */
167 | void init();
168 |
169 | protected:
170 | /** Storage metadata */
171 | Type m_storageType;
172 |
173 |
174 | /** Param offsets in m_paramData */
175 | vector m_paramPointers;
176 |
177 | };
178 |
179 | class Library: public ExecutionContext {
180 | public:
181 | Library(const string &libraryName, bool delayLoad = false);
182 | virtual ~Library();
183 | DWORD getMethodAddr(const string &methodName, bool enableTCharSuffix = true);
184 | Type& getMethodType(const string &methodName);
185 | MethodInstance* createMethodInstance(const string& methodDecl, bool enableTCharSuffix);
186 | //MethodType* createMethodType(char * methodName, char *returnType,
187 | // char *paramTypes[], int paramCount, bool isStdCall = true, bool isUnicode = false);
188 |
189 | // IRuntimeExceptionRegistry
190 | /** Register exception */
191 |
192 | private:
193 | void ensureIsLoaded();
194 | string m_libraryName;
195 | HMODULE m_libraryHandle;
196 | string m_nameSpace;
197 | };
198 |
199 |
200 | class Method: public ParamStorage
201 | {
202 | public:
203 | BYTE* getReturnValueAddr();
204 | virtual void clear();
205 |
206 | void invoke(MethodInstance *methodInstance);
207 | Method(MethodType *methodType, BYTE* argsPtr = NULL);
208 | virtual ~Method();
209 | inline MethodType *getMethodType() { return m_methodType; }
210 | private:
211 | MethodType *m_methodType;
212 | vector m_returnValue;
213 | };
214 |
215 | typedef boost::shared_ptr MethodContextPtr;
--------------------------------------------------------------------------------