[pygccxml-commit] SF.net SVN: pygccxml:[1475] pyplusplus_dev/pyplusplus
Brought to you by:
mbaas,
roman_yakovenko
From: <rom...@us...> - 2008-12-17 22:22:09
|
Revision: 1475 http://pygccxml.svn.sourceforge.net/pygccxml/?rev=1475&view=rev Author: roman_yakovenko Date: 2008-12-17 21:43:57 +0000 (Wed, 17 Dec 2008) Log Message: ----------- adding ctypes-cpp tester Added Paths: ----------- pyplusplus_dev/pyplusplus/cpptypes/ pyplusplus_dev/pyplusplus/cpptypes/decorators.py pyplusplus_dev/pyplusplus/cpptypes/decorators.pyc pyplusplus_dev/pyplusplus/cpptypes/get_exports.py pyplusplus_dev/pyplusplus/cpptypes/mydll/ pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.cpp pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.h pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.sln pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.suo pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.vcproj pyplusplus_dev/pyplusplus/cpptypes/mydll/release/ pyplusplus_dev/pyplusplus/cpptypes/mydll/release/mydll.dll pyplusplus_dev/pyplusplus/cpptypes/tester.py Added: pyplusplus_dev/pyplusplus/cpptypes/decorators.py =================================================================== --- pyplusplus_dev/pyplusplus/cpptypes/decorators.py (rev 0) +++ pyplusplus_dev/pyplusplus/cpptypes/decorators.py 2008-12-17 21:43:57 UTC (rev 1475) @@ -0,0 +1,9 @@ +class public( object ): + def __init__(self , dll, decorated_name, return_type, argumen_types): + self.decorated_name = decorated_name + self.func = getattr( dll, decorated_name ) + self.func.restype = return_type + self.func.argtypes = argumen_types + + def __call__(self, *args, **keywd ): + return self.func( *args, **keywd ) Added: pyplusplus_dev/pyplusplus/cpptypes/decorators.pyc =================================================================== (Binary files differ) Property changes on: pyplusplus_dev/pyplusplus/cpptypes/decorators.pyc ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: pyplusplus_dev/pyplusplus/cpptypes/get_exports.py =================================================================== --- pyplusplus_dev/pyplusplus/cpptypes/get_exports.py (rev 0) +++ pyplusplus_dev/pyplusplus/cpptypes/get_exports.py 2008-12-17 21:43:57 UTC (rev 1475) @@ -0,0 +1,289 @@ +# This code was contributed by 'leppton', see +# https://sourceforge.net/tracker/?func=detail&atid=305470&aid=1559219&group_id=5470 +# +# This example shows how to use ctypes module to read all +# function names from dll export directory + +import os +if os.name != "nt": + raise Exception("Wrong OS") + +import ctypes as ctypes +import ctypes.wintypes as wintypes + +def convert_cdef_to_pydef(line): + """\ +convert_cdef_to_pydef(line_from_c_header_file) -> python_tuple_string +'DWORD var_name[LENGTH];' -> '("var_name", DWORD*LENGTH)' + +doesn't work for all valid c/c++ declarations""" + l = line[:line.find(';')].split() + if len(l) != 2: + return None + type_ = l[0] + name = l[1] + i = name.find('[') + if i != -1: + name, brac = name[:i], name[i:][1:-1] + return '("%s", %s*%s)'%(name,type_,brac) + else: + return '("%s", %s)'%(name,type_) + +def convert_cdef_to_structure(cdef, name, data_dict=ctypes.__dict__): + """\ +convert_cdef_to_structure(struct_definition_from_c_header_file) + -> python class derived from ctypes.Structure + +limited support for c/c++ syntax""" + py_str = '[\n' + for line in cdef.split('\n'): + field = convert_cdef_to_pydef(line) + if field != None: + py_str += ' '*4 + field + ',\n' + py_str += ']\n' + + pyarr = eval(py_str, data_dict) + class ret_val(ctypes.Structure): + _fields_ = pyarr + ret_val.__name__ = name + ret_val.__module__ = None + return ret_val + +#struct definitions we need to read dll file export table +winnt = ( + ('IMAGE_DOS_HEADER', """\ + WORD e_magic; + WORD e_cblp; + WORD e_cp; + WORD e_crlc; + WORD e_cparhdr; + WORD e_minalloc; + WORD e_maxalloc; + WORD e_ss; + WORD e_sp; + WORD e_csum; + WORD e_ip; + WORD e_cs; + WORD e_lfarlc; + WORD e_ovno; + WORD e_res[4]; + WORD e_oemid; + WORD e_oeminfo; + WORD e_res2[10]; + LONG e_lfanew; +"""), + + ('IMAGE_FILE_HEADER', """\ + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +"""), + + ('IMAGE_DATA_DIRECTORY', """\ + DWORD VirtualAddress; + DWORD Size; +"""), + + ('IMAGE_OPTIONAL_HEADER32', """\ + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +""", + {'IMAGE_NUMBEROF_DIRECTORY_ENTRIES':16}), + + ('IMAGE_NT_HEADERS', """\ + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; +"""), + + ('IMAGE_EXPORT_DIRECTORY', """\ + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; + DWORD AddressOfNames; + DWORD AddressOfNameOrdinals; +"""), + ) + +#Construct python ctypes.Structures from above definitions +data_dict = dict(wintypes.__dict__) +for definition in winnt: + name = definition[0] + def_str = definition[1] + if len(definition) == 3: + data_dict.update(definition[2]) + type_ = convert_cdef_to_structure(def_str, name, data_dict) + data_dict[name] = type_ + globals()[name] = type_ + + ptype = ctypes.POINTER(type_) + pname = 'P'+name + data_dict[pname] = ptype + globals()[pname] = ptype + +del data_dict +del winnt + +class DllException(Exception): + pass + +def read_export_table(dll_name, mmap=False, use_kernel=False): + """\ +read_export_table(dll_name [,mmap=False [,use_kernel=False]]]) + -> list of exported names + +default is to load dll into memory: dll sections are aligned to +page boundaries, dll entry points is called, etc... + +with mmap=True dll file image is mapped to memory, Relative Virtual +Addresses (RVAs) must be mapped to real addresses manually + +with use_kernel=True direct kernel32.dll calls are used, +instead of python mmap module + +see http://www.windowsitlibrary.com/Content/356/11/1.html +for details on Portable Executable (PE) file format +""" + if not mmap: + dll = ctypes.cdll.LoadLibrary(dll_name) + if dll == None: + raise DllException("Cant load dll") + base_addr = dll._handle + + else: + if not use_kernel: + fileH = open(dll_name) + if fileH == None: + raise DllException("Cant load dll") + import mmap + m = mmap.mmap(fileH.fileno(), 0, None, mmap.ACCESS_READ) + # id(m)+8 sucks, is there better way? + base_addr = ctypes.cast(id(m)+8, ctypes.POINTER(ctypes.c_int))[0] + else: + kernel32 = ctypes.windll.kernel32 + if kernel32 == None: + raise DllException("cant load kernel") + fileH = kernel32.CreateFileA(dll_name, 0x00120089, 1,0,3,0,0) + if fileH == 0: + raise DllException("Cant open, errcode = %d"%kernel32.GetLastError()) + mapH = kernel32.CreateFileMappingW(fileH,0,0x8000002,0,0,0) + if mapH == 0: + raise DllException("Cant mmap, errocode = %d"%kernel32.GetLastError()) + base_addr = ctypes.windll.kernel32.MapViewOfFile(mapH, 0x4, 0, 0, 0) + if base_addr == 0: + raise DllException("Cant mmap(2), errocode = %d"%kernel32.GetLastError()) + + dbghelp = ctypes.windll.dbghelp + if dbghelp == None: + raise DllException("dbghelp.dll not installed") + pimage_nt_header = dbghelp.ImageNtHeader(base_addr) + if pimage_nt_header == 0: + raise DllException("Cant find IMAGE_NT_HEADER") + + #Functions like dbghelp.ImageNtHeader above have no type information + #let's make one prototype for extra buzz + #PVOID ImageRvaToVa(PIMAGE_NT_HEADERS NtHeaders, PVOID Base, + # ULONG Rva, PIMAGE_SECTION_HEADER* LastRvaSection) + # we use integers instead of pointers, coz integers are better + # for pointer arithmetic + prototype = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_int, + ctypes.c_int, ctypes.c_int, ctypes.c_int) + paramflags = ((1,"NtHeaders",pimage_nt_header),(1,"Base",base_addr),(1,"Rva"),(1,"LastRvaSection",0)) + ImageRvaToVa = prototype(('ImageRvaToVa', dbghelp), paramflags) + + def cast_rva(rva, type_): + va = base_addr + rva + if mmap and va > pimage_nt_header: + va = ImageRvaToVa(Rva=rva) + if va == 0: + raise DllException("ImageRvaToVa failed") + return ctypes.cast(va, type_) + + if not mmap: + dos_header = cast_rva(0, PIMAGE_DOS_HEADER)[0] + if dos_header.e_magic != 0x5A4D: + raise DllException("IMAGE_DOS_HEADER.e_magic error") + nt_header = cast_rva(dos_header.e_lfanew, PIMAGE_NT_HEADERS)[0] + else: + nt_header = ctypes.cast(pimage_nt_header, PIMAGE_NT_HEADERS)[0] + if nt_header.Signature != 0x00004550: + raise DllException("IMAGE_NT_HEADERS.Signature error") + + opt_header = nt_header.OptionalHeader + if opt_header.Magic != 0x010b: + raise DllException("IMAGE_OPTIONAL_HEADERS32.Magic error") + + ret_val = [] + exports_dd = opt_header.DataDirectory[0] + if opt_header.NumberOfRvaAndSizes > 0 or exports_dd != 0: + export_dir = cast_rva(exports_dd.VirtualAddress, PIMAGE_EXPORT_DIRECTORY)[0] + + nNames = export_dir.NumberOfNames + if nNames > 0: + PNamesType = ctypes.POINTER(ctypes.c_int * nNames) + names = cast_rva(export_dir.AddressOfNames, PNamesType)[0] + for rva in names: + name = cast_rva(rva, ctypes.c_char_p).value + ret_val.append(name) + + if mmap: + if use_kernel: + kernel32.UnmapViewOfFile(base_addr) + kernel32.CloseHandle(mapH) + kernel32.CloseHandle(fileH) + else: + m.close() + fileH.close() + return ret_val + + +if __name__ == '__main__': + import sys + if len(sys.argv) != 2: + print 'usage: %s dll_file_name'%sys.argv[0] + sys.exit() +## names = read_export_table(sys.argv[1], mmap=False, use_kernel=False) + names = read_export_table(sys.argv[1], mmap=False, use_kernel=False) + for name in names: + print name + + Added: pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.cpp =================================================================== --- pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.cpp (rev 0) +++ pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.cpp 2008-12-17 21:43:57 UTC (rev 1475) @@ -0,0 +1,52 @@ +#include "mydll.h" +#include "windows.h" +#include <iostream> + +number_t::number_t() +: m_value(0) +{ +// std::cout << "{C++} number_t( 0 )" << std::endl; +} + + +number_t::number_t(int value) +: m_value(value) +{ +// std::cout << "{C++} number_t( " << value << " )" << std::endl; +} + +number_t::~number_t() { +// std::cout << "{C++} ~number_t()" << std::endl; +} +void number_t::print_it() const { + std::cout << "{C++} value: " << m_value << std::endl; +} + +int number_t::get_value() const{ + return m_value; +} + +void number_t::set_value(int x){ + m_value = x; +} + +number_t number_t::clone() const{ + return number_t(*this); +} + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + Added: pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.h =================================================================== --- pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.h (rev 0) +++ pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.h 2008-12-17 21:43:57 UTC (rev 1475) @@ -0,0 +1,17 @@ +#pragma once + +class __declspec(dllexport) number_t{ +public: + number_t(); + explicit number_t(int value); + virtual ~number_t(); + void print_it() const; + int get_value() const; + void set_value(int x); + + number_t clone() const; + +private: + int m_value; +}; + Added: pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.sln =================================================================== --- pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.sln (rev 0) +++ pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.sln 2008-12-17 21:43:57 UTC (rev 1475) @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mydll", "mydll.vcproj", "{E7A34C45-534F-43A6-AF95-3CA2428619E2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E7A34C45-534F-43A6-AF95-3CA2428619E2}.Debug|Win32.ActiveCfg = Debug|Win32 + {E7A34C45-534F-43A6-AF95-3CA2428619E2}.Debug|Win32.Build.0 = Debug|Win32 + {E7A34C45-534F-43A6-AF95-3CA2428619E2}.Release|Win32.ActiveCfg = Release|Win32 + {E7A34C45-534F-43A6-AF95-3CA2428619E2}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal Added: pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.suo =================================================================== (Binary files differ) Property changes on: pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.suo ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.vcproj =================================================================== --- pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.vcproj (rev 0) +++ pyplusplus_dev/pyplusplus/cpptypes/mydll/mydll.vcproj 2008-12-17 21:43:57 UTC (rev 1475) @@ -0,0 +1,179 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="mydll" + ProjectGUID="{E7A34C45-534F-43A6-AF95-3CA2428619E2}" + RootNamespace="mydll" + Keyword="Win32Proj" + TargetFrameworkVersion="196613" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="2" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MYDLL_EXPORTS" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="2" + WarningLevel="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkIncremental="2" + GenerateDebugInformation="true" + SubSystem="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="2" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + EnableIntrinsicFunctions="true" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MYDLL_EXPORTS" + RuntimeLibrary="2" + EnableFunctionLevelLinking="true" + UsePrecompiledHeader="0" + WarningLevel="3" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkIncremental="1" + GenerateDebugInformation="true" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <File + RelativePath=".\mydll.cpp" + > + </File> + <File + RelativePath=".\mydll.h" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> Added: pyplusplus_dev/pyplusplus/cpptypes/mydll/release/mydll.dll =================================================================== (Binary files differ) Property changes on: pyplusplus_dev/pyplusplus/cpptypes/mydll/release/mydll.dll ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: pyplusplus_dev/pyplusplus/cpptypes/tester.py =================================================================== --- pyplusplus_dev/pyplusplus/cpptypes/tester.py (rev 0) +++ pyplusplus_dev/pyplusplus/cpptypes/tester.py 2008-12-17 21:43:57 UTC (rev 1475) @@ -0,0 +1,133 @@ +import ctypes +import unittest +import decorators + +mydll = ctypes.CPPDLL( './mydll/release/mydll.dll' ) + +#we should keep somewhere decorated-undecorated name mappings +#I don't feel like parsing source code is a good strategy +# - there is no way to create mangled name for a function. In this example, other way is used - binary file is parsed +# and the functions are mapped to dll entry using "human readable" format. +# GCCXML reports mangled and demangled names of the function, but it is not a cross platform( compile ) solution. +# It looks like I will have to cause mspdb package to work ( from where ctypes loads dlls? ctypes.windll.msvcr90 ??? + + +tmp = [ ( "number_t::number_t(class number_t const &)", "??0number_t@@QAE@ABV0@@Z" ) + , ( "number_t::number_t(int)", "??0number_t@@QAE@H@Z" ) + , ( "number_t::number_t(void)", "??0number_t@@QAE@XZ" ) + , ( "number_t::~number_t(void)", "??1number_t@@UAE@XZ" ) + , ( "class number_t & number_t::operator=(class number_t const &)", "??4number_t@@QAEAAV0@ABV0@@Z" ) + , ( "const number_t::'vftable'", "??_7number_t@@6B@" ) + , ( "int number_t::get_value(void)", "?get_value@number_t@@QBEHXZ" ) + , ( "void number_t::print_it(void)", "?print_it@number_t@@QBEXXZ" ) + , ( "void number_t::set_value(int)", "?set_value@number_t@@QAEXH@Z" ) ] + +mydll.name_mapping = {} +for n1, n2 in tmp: + mydll.name_mapping[n1] = n2 + mydll.name_mapping[n2] = n1 + +# what is the best way to treat overloaded constructors +class public( object ): + def __init__(self, dll, this, name, restype=None, argtypes=None ): + self.this = this #reference to class instance + self.name = name + self.func = getattr( dll, dll.name_mapping[name] ) + self.func.restype = restype + this_call_arg_types = [ ctypes.POINTER( this._obj.__class__ ) ] + if argtypes: + this_call_arg_types.extend( argtypes ) + self.func.argtypes = this_call_arg_types + + def __call__(self, *args, **keywd ): + return self.func( self.this, *args, **keywd ) + +class mem_fun_factory( object ): + def __init__( self, dll, this ): + self.dll = dll + self.this = this + + def __call__( self, *args, **keywd ): + return public( self.dll, self.this, *args, **keywd ) + +class Number(ctypes.Structure): + #http://www.phpcompiler.org/articles/virtualinheritance.html, + _fields_ = [("vptr", ctypes.POINTER(ctypes.c_void_p)), + ("m_value", ctypes.c_int)] + + def __init__(self, x=None): + mem_fun = mem_fun_factory( mydll, ctypes.byref( self ) ) + self.get_value = mem_fun( 'int number_t::get_value(void)', restype=ctypes.c_int ) + self.set_value = mem_fun( 'void number_t::set_value(int)', argtypes=[ctypes.c_int]) + self.print_it = mem_fun( 'void number_t::print_it(void)' ) + self.assign = mem_fun( "class number_t & number_t::operator=(class number_t const &)" + , restype=ctypes.POINTER(Number) + , argtypes=[ctypes.POINTER(Number)] ) + #overloading example + if None is x: + mem_fun( 'number_t::number_t(void)' )() + elif isinstance( x, int ): + mem_fun( 'number_t::number_t(int)', argtypes=[ctypes.c_int] )( x ) + elif isinstance( x, Number ): + mem_fun( 'number_t::number_t(class number_t const &)', argtypes=[ctypes.POINTER(Number)] )( ctypes.byref( x ) ) + else: + raise RuntimeError( "Wrong argument" ) + + def __del__(self): + public( mydll, ctypes.byref(self), "number_t::~number_t(void)" )() + +class tester_t( unittest.TestCase ): + def test_constructors(self): + obj1 = Number(32) + self.failUnless( obj1.m_value == 32 ) + obj2 = Number() + self.failUnless( obj2.m_value == 0 ) + obj3 = Number(obj1) + self.failUnless( obj3.m_value == obj1.m_value == 32 ) + + def test_get_value( self ): + obj = Number(99) + self.failUnless( 99 == obj.get_value() ) + + def test_set_value( self ): + obj = Number() + obj.set_value( 13 ) + self.failUnless( 13 == obj.get_value() == obj.m_value ) + + def test_assign( self ): + obj1 = Number(1) + obj2 = Number(2) + x = obj1.assign( obj2 ) + #there are special cases, where ctypes could introduce "optimized" behaviour and not create new python object + self.failUnless( x is obj1 ) + self.failUnless( obj1.m_value == obj2.m_value ) + +def main(): + obj = Number(42) + print obj.m_value + print hex(obj.vptr[0]) + obj.print_it() + print '42 == ', obj.get_value() + +if __name__ == "__main__": + unittest.main() + +#problems: +#consider generic algorithm for resolving overloaded functions call +# * function name should be unique +# * write something very smart and bugy and let the smart people to improve it + + +""" +TODO: + +* I think more testers and "demos", before I write code generator: + * a class instance passed\returned by value\reference\pointer\smart pointer + * function overloading + * how much code, we can put in the helper files. I mean class like "public". Or std::vector - there is no reason, to define\generate this class every time + * how we are going to manage relationship between objects: + class X{...}; + class Y{ X x; public: const X& get_x() const { return x;} }; + I think our solution should be very similar to Boost.Python call policies. It is definitely possible to go without it. + +""" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |