Re: Simple Attempt Wrapping CPP Library
- Posted by ghaberek (admin) Mar 01, 2023
- 753 views
Bad news is, you're not going to be able to wrap C++ calls without basically recreating the vtable and name mangling used by various C++ compilers, which is unique to each major compiler. Good news is, you don't have to.
Looking at the Core Temp Plug-in SDK1 page we can see we just need those exported functions called fnGetCoreTempInfo (which uses CDECL) and fnGetCoreTempInfoAlt (which uses STDCALL) and that's all we really need to get at the data. The C++ class is just there to get access to the structure members so we can ignore it completely. Although on my first attempt to call either function they returned 0. The SDK page indicates that GetLastError should return 0x20000000 if there was an exception. When I call GetLastError I got back a value of "2" which is ERROR_FILE_NOT_FOUND. Turns out you need to have Core Temp installed and running and have the Enable global shared memory option turned on.
1Side note: it's helpful to link directly to these things when asking for help so I can get more information from the source without having to hunt it down.
Note: this code uses my recent changes to libffi-euphoria (I've been sitting on them lately so I pushed them all just now.) I renamed define_c_type() to define_c_struct() and added define_c_union() (and I think it works?). There's a new define_c_type() function thats it's strictly for creating or copying C types. Its parameter types are different so your existing code will need to be renamed to use define_c_struct(). I also added peek_member() and poke_member() to more easily access struct/union members, including nested members! I'd still like to add functionality for naming things so you can allocate structs and peek/poke members by name. Might even incorporate basic C parser so you can define structs by (more or less) copying the code from C headers. IIRC this is sort of how Pete does it for Phix.
include std/ffi.e include std/machine.e constant coretemp = open_dll( "GetCoreTempInfo.dll" ) constant fnGetCoreTempInfo = define_c_func( coretemp, "+fnGetCoreTempInfo", {C_POINTER}, C_BOOL ) constant CORE_TEMP_SHARED_DATA = define_c_struct({ {C_UINT,256}, -- unsigned int uiLoad[256] {C_UINT,128}, -- unsigned int uiTjMax[128] C_UINT, -- unsigned int uiCoreCnt C_UINT, -- unsigned int uiCPUCnt {C_FLOAT,256}, -- float fTemp[256] C_FLOAT, -- float fVID C_FLOAT, -- float fCPUSpeed C_FLOAT, -- float fFSBSpeed C_FLOAT, -- float fMultiplier {C_CHAR,100}, -- char sCPUName[100] C_UCHAR, -- unsigned char ucFarenheit C_UCHAR -- unsigned char ucDeltaToTjMax }) public function GetCoreTempInfo() -- N.B. it's not clear from the SDK docs but fnGetCoreTempInfo -- expects a pointer to the pointer of our structure. So we -- first allocate the structure (which gives us a pointer) and -- then allocate some memory and store our pointer there, then -- pass this "indirect" pointer when calling the function. atom data = allocate_struct( CORE_TEMP_SHARED_DATA ) atom pdata = allocate_data( sizeof(C_POINTER), 1 ) poke_pointer( pdata, data ) if not c_func( fnGetCoreTempInfo, {pdata} ) then free( data ) return NULL end if return delete_routine( data, routine_id("free") ) end function public function GetCoreLoad( atom data, integer nIndex ) return peek_member( data, CORE_TEMP_SHARED_DATA, {1,nIndex} ) end function public function GetTjMax( atom data, integer nIndex ) return peek_member( data, CORE_TEMP_SHARED_DATA, {2,nIndex} ) end function public function GetCoreCount( atom data ) return peek_member( data, CORE_TEMP_SHARED_DATA, 3 ) end function public function GetCPUCount( atom data ) return peek_member( data, CORE_TEMP_SHARED_DATA, 4 ) end function public function GetTemp( atom data, integer nIndex ) return peek_member( data, CORE_TEMP_SHARED_DATA, {5,nIndex} ) end function public function GetVID( atom data ) return peek_member( data, CORE_TEMP_SHARED_DATA, 6 ) end function public function GetCPUSpeed( atom data ) return peek_member( data, CORE_TEMP_SHARED_DATA, 7 ) end function public function GetFSBSpeed( atom data ) return peek_member( data, CORE_TEMP_SHARED_DATA, 8 ) end function public function GetMultiplier( atom data ) return peek_member( data, CORE_TEMP_SHARED_DATA, 9 ) end function public function GetCPUName( atom data ) sequence name = peek_member( data, CORE_TEMP_SHARED_DATA, 10 ) -- N.B. sCPUName is a character array, not a string pointer. Calling -- peek_member() will always return a sequence of 100 characters (the -- size of the array) so we need to trim any trailing null characters. -- Sometimes we get a trailing space so we'll just check for the last -- non-space printable character and trim off everything after that. for i = length( name ) to 1 by -1 do if name[i] > ' ' then name = name[1..i] exit end if end for return name end function public function IsFahrenheit( atom data ) return peek_member( data, CORE_TEMP_SHARED_DATA, 11 ) end function public function IsDistanceToTjMax( atom data ) return peek_member( data, CORE_TEMP_SHARED_DATA, 12 ) end function
-Greg