@@ -72,17 +72,7 @@ int GetDynCallConvention(Convention_t eConv)
7272 }
7373
7474 BOOST_RAISE_EXCEPTION (PyExc_ValueError, " Unsupported calling convention." )
75- return 0 ;
76- }
77-
78- std::vector<DataType_t> ObjectToDataTypeVector (object oArgTypes)
79- {
80- std::vector<DataType_t> vecArgTypes;
81- for (int i=0 ; i < len (oArgTypes); i++)
82- {
83- vecArgTypes.push_back (extract<DataType_t>(oArgTypes[i]));
84- }
85- return vecArgTypes;
75+ return -1 ;
8676}
8777
8878ICallingConvention* MakeDynamicHooksConvention (Convention_t eConv, std::vector<DataType_t> vecArgTypes, DataType_t returnType, int iAlignment=4 )
@@ -103,7 +93,7 @@ ICallingConvention* MakeDynamicHooksConvention(Convention_t eConv, std::vector<D
10393#endif
10494
10595 BOOST_RAISE_EXCEPTION (PyExc_ValueError, " Unsupported calling convention." )
106- return 0 ;
96+ return NULL ;
10797}
10898
10999// -----------------------------------------------------------------------------
@@ -241,17 +231,52 @@ CPointer* CPointer::Realloc(int iSize)
241231 return new CPointer ((unsigned long ) UTIL_Realloc ((void *) m_ulAddr, iSize));
242232}
243233
244- CFunction* CPointer::MakeFunction (Convention_t eConv , object args, object return_type )
234+ CFunction* CPointer::MakeFunction (object oCallingConvention , object args, object oReturnType )
245235{
246236 if (!IsValid ())
247237 BOOST_RAISE_EXCEPTION (PyExc_ValueError, " Pointer is NULL." )
248238
249- return new CFunction (m_ulAddr, eConv, args, return_type);
239+ Convention_t _eCallingConvention = CONV_NONE;
240+ int _iCallingConvention = -1 ;
241+ object _oCallingConvention = object ();
242+ ICallingConvention* _pCallingConvention = NULL ;
243+ tuple _tArgs = tuple (args);
244+ object _oReturnType = oReturnType;
245+ DataType_t _eReturnType;
246+
247+ // Get the enum return type
248+ try
249+ {
250+ _eReturnType = extract<DataType_t>(oReturnType);
251+ }
252+ catch ( ... )
253+ {
254+ PyErr_Clear ();
255+ _eReturnType = DATA_TYPE_POINTER;
256+ }
257+
258+ try
259+ {
260+ // If this line succeeds the user wants to create a function with the built-in calling conventions
261+ _eCallingConvention = extract<Convention_t>(oCallingConvention);
262+ _iCallingConvention = GetDynCallConvention (_eCallingConvention);
263+ _pCallingConvention = MakeDynamicHooksConvention (_eCallingConvention, ObjectToDataTypeVector (args), _eReturnType);
264+ }
265+ catch ( ... )
266+ {
267+ // If this happens, we won't be able to call the function, because we are using a custom calling convention
268+ PyErr_Clear ();
269+
270+ _oCallingConvention = oCallingConvention (args, _eReturnType);
271+ _pCallingConvention = extract<ICallingConvention*>(_oCallingConvention);
272+ }
273+
274+ return new CFunction (m_ulAddr, _eCallingConvention, _iCallingConvention, _oCallingConvention, _pCallingConvention, _tArgs, _eReturnType, _oReturnType);
250275}
251276
252- CFunction* CPointer::MakeVirtualFunction (int iIndex, Convention_t eConv , object args, object return_type)
277+ CFunction* CPointer::MakeVirtualFunction (int iIndex, object oCallingConvention , object args, object return_type)
253278{
254- return GetVirtualFunc (iIndex)->MakeFunction (eConv , args, return_type);
279+ return GetVirtualFunc (iIndex)->MakeFunction (oCallingConvention , args, return_type);
255280}
256281
257282void CPointer::CallCallback (PyObject* self, char * szCallback)
@@ -301,48 +326,51 @@ void CPointer::__del__(PyObject* self)
301326// -----------------------------------------------------------------------------
302327// CFunction class
303328// -----------------------------------------------------------------------------
304- CFunction::CFunction (unsigned long ulAddr, Convention_t eConv, object args, object return_type)
305- : CPointer(ulAddr)
329+ CFunction::CFunction (unsigned long ulAddr, Convention_t eCallingConvention,
330+ int iCallingConvention, object oCallingConvention,
331+ ICallingConvention* pCallingConvention, tuple tArgs,
332+ DataType_t eReturnType, object oReturnType)
333+ :CPointer(ulAddr)
306334{
307- m_eConv = eConv;
308- m_Args = tuple (args);
309- m_oReturnType = return_type;
310-
311- DataType_t eReturnType;
312-
313- // Try to get the return type
314- try
315- {
316- eReturnType = extract<DataType_t>(m_oReturnType);
317- }
318- catch ( ... )
319- {
320- PyErr_Clear ();
335+ m_eCallingConvention = eCallingConvention;
336+ m_iCallingConvention = iCallingConvention;
337+ m_oCallingConvention = oCallingConvention;
338+ m_pCallingConvention = pCallingConvention;
339+ m_tArgs = tArgs;
340+ m_eReturnType = eReturnType;
341+ m_oReturnType = oReturnType;
342+ }
321343
322- // It failed, so let's handle it as a pointer
323- eReturnType = DATA_TYPE_POINTER;
324- }
344+ bool CFunction::IsCallable ()
345+ {
346+ return (m_eCallingConvention != CONV_NONE) && (m_iCallingConvention != -1 );
347+ }
325348
326- m_pCallingConvention = MakeDynamicHooksConvention (eConv, ObjectToDataTypeVector (args), eReturnType);
349+ bool CFunction::IsHookable ()
350+ {
351+ return m_pCallingConvention != NULL ;
327352}
328353
329354object CFunction::Call (tuple args, dict kw)
330355{
356+ if (!IsCallable ())
357+ BOOST_RAISE_EXCEPTION (PyExc_ValueError, " Function is not callable." )
358+
331359 if (!IsValid ())
332360 BOOST_RAISE_EXCEPTION (PyExc_ValueError, " Function pointer is NULL." )
333361
334- if (len (args) != len (m_Args ))
362+ if (len (args) != len (m_tArgs ))
335363 BOOST_RAISE_EXCEPTION (PyExc_ValueError, " Number of passed arguments is not equal to the required number." )
336364
337365 // Reset VM and set the calling convention
338366 dcReset (g_pCallVM);
339- dcMode (g_pCallVM, GetDynCallConvention (m_eConv) );
367+ dcMode (g_pCallVM, m_iCallingConvention );
340368
341369 // Loop through all passed arguments and add them to the VM
342370 for (int i=0 ; i < len (args); i++)
343371 {
344372 object arg = args[i];
345- switch (extract<DataType_t>(m_Args [i]))
373+ switch (extract<DataType_t>(m_tArgs [i]))
346374 {
347375 case DATA_TYPE_BOOL: dcArgBool (g_pCallVM, extract<bool >(arg)); break ;
348376 case DATA_TYPE_CHAR: dcArgChar (g_pCallVM, extract<char >(arg)); break ;
@@ -369,23 +397,8 @@ object CFunction::Call(tuple args, dict kw)
369397 }
370398 }
371399
372- DataType_t return_type;
373-
374- // Try to get the return type
375- try
376- {
377- return_type = extract<DataType_t>(m_oReturnType);
378- }
379- catch ( ... )
380- {
381- PyErr_Clear ();
382-
383- // It failed, so let's handle it as a pointer
384- return m_oReturnType (ptr (new CPointer (dcCallPointer (g_pCallVM, m_ulAddr))));
385- }
386-
387400 // Call the function
388- switch (return_type )
401+ switch (m_eReturnType )
389402 {
390403 case DATA_TYPE_VOID: dcCallVoid (g_pCallVM, m_ulAddr); break ;
391404 case DATA_TYPE_BOOL: return object (dcCallBool (g_pCallVM, m_ulAddr));
@@ -401,7 +414,13 @@ object CFunction::Call(tuple args, dict kw)
401414 case DATA_TYPE_ULONG_LONG: return object ((unsigned long long ) dcCallLongLong (g_pCallVM, m_ulAddr));
402415 case DATA_TYPE_FLOAT: return object (dcCallFloat (g_pCallVM, m_ulAddr));
403416 case DATA_TYPE_DOUBLE: return object (dcCallDouble (g_pCallVM, m_ulAddr));
404- case DATA_TYPE_POINTER: return object (ptr (new CPointer (dcCallPointer (g_pCallVM, m_ulAddr))));
417+ case DATA_TYPE_POINTER:
418+ {
419+ CPointer* pPtr = new CPointer (dcCallPointer (g_pCallVM, m_ulAddr));
420+ if (!m_oReturnType.is_none ())
421+ return m_oReturnType (ptr (pPtr));
422+ return object (ptr (pPtr));
423+ }
405424 case DATA_TYPE_STRING: return object ((const char *) dcCallPointer (g_pCallVM, m_ulAddr));
406425 default : BOOST_RAISE_EXCEPTION (PyExc_TypeError, " Unknown return type." )
407426 }
@@ -410,42 +429,38 @@ object CFunction::Call(tuple args, dict kw)
410429
411430object CFunction::CallTrampoline (tuple args, dict kw)
412431{
432+ if (!IsCallable ())
433+ BOOST_RAISE_EXCEPTION (PyExc_ValueError, " Function is not callable." )
434+
413435 if (!IsValid ())
414436 BOOST_RAISE_EXCEPTION (PyExc_ValueError, " Function pointer is NULL." )
415437
416438 CHook* pHook = GetHookManager ()->FindHook ((void *) m_ulAddr);
417439 if (!pHook)
418440 BOOST_RAISE_EXCEPTION (PyExc_ValueError, " Function was not hooked." )
419441
420- return CFunction ((unsigned long ) pHook->m_pTrampoline , m_eConv, m_Args, m_oReturnType).Call (args, kw);
442+ return CFunction ((unsigned long ) pHook->m_pTrampoline , m_eCallingConvention,
443+ m_iCallingConvention, m_oCallingConvention, m_pCallingConvention, m_tArgs,
444+ m_eReturnType, m_oReturnType).Call (args, kw);
421445}
422446
423447handle<> CFunction::AddHook (HookType_t eType, PyObject* pCallable)
424448{
449+ if (!IsHookable ())
450+ BOOST_RAISE_EXCEPTION (PyExc_ValueError, " Function is not hookable." )
451+
425452 if (!IsValid ())
426453 BOOST_RAISE_EXCEPTION (PyExc_ValueError, " Function pointer is NULL." )
427454
428- // Generate the argument string
429- DataType_t return_type;
430- try
431- {
432- return_type = extract<DataType_t>(m_oReturnType);
433- }
434- catch ( ... )
435- {
436- PyErr_Clear ();
437- return_type = DATA_TYPE_POINTER;
438- }
439-
440455 // Hook the function
441456 CHook* pHook = GetHookManager ()->HookFunction ((void *) m_ulAddr, m_pCallingConvention);
442-
457+
443458 // Add the hook handler. If it's already added, it won't be added twice
444- pHook->AddCallback (eType, (HookHandlerFn *) &SP_HookHandler);
445-
459+ pHook->AddCallback (eType, (HookHandlerFn *) ( void *) &SP_HookHandler);
460+
446461 // Add the callback to our map
447462 g_mapCallbacks[pHook][eType].push_back (pCallable);
448-
463+
449464 // Return the callback, so we can use this method as a decorator
450465 return handle<>(borrowed (pCallable));
451466}
0 commit comments