Function that returns pointer, when imported in separate file, return number instead of object

Question:

I have a file called, runner.py, which has a lot of functions that make calls to a market DLL.

#Imports para execução da DLL
import time
import gc
from ctypes import *
from ctypes.wintypes import UINT
import struct
from datetime import*
import sys
import functions
from threading import Thread

rotPassword = '' 
accountID   = '' 
corretora   = '' 

profit_dll = WinDLL('./ProfitDLL64.dll')
profit_dll.argtypes  = None

def printPosition():
    global profit_dll
    global corretora, accountID

    asset = 'asset'
    bolsa = 'f'
    thisCorretora = corretora
    acc_id = accountID    
    priceToReturn = 0

    result = profit_dll.GetPosition(c_wchar_p(str(acc_id)), c_wchar_p(str(thisCorretora)), c_wchar_p(asset), c_wchar_p(bolsa))

    print(f'here {result}')    
    return result
    
    n_qtd = result[0]

    if (n_qtd == 0):
        print('Nao ha posicao para esse ativo')        
        return priceToReturn
    else:
        n_tam = result[1]       

        arr = cast(result, POINTER(c_char))
        frame = bytearray()
        for i in range(n_tam):
            c = arr[i]
            frame.append(c[0])
        
        start = 8

        for i in range(n_qtd):
            corretora_id = struct.unpack('i', frame[start:start+4])[0]
            start += 4

            acc_id_length = struct.unpack('h', frame[start:start+2])[0]
            start += 2
            account_id = frame[start:start+acc_id_length]
            start += acc_id_length

            titular_length = struct.unpack('h', frame[start:start+2])[0]
            start += 2
            titular = frame[start:start+titular_length]
            start += titular_length

            ticker_length = struct.unpack('h', frame[start:start+2])[0]
            start += 2
            ticker = frame[start:start+ticker_length]
            start += ticker_length

            intraday_pos = struct.unpack('i', frame[start:start+4])[0]
            start += 4

            price = struct.unpack('d', frame[start:start + 8])[0]       
            priceToReturn = str(price)     
            start += 8

            avg_sell_price = struct.unpack('d', frame[start:start + 8])[0]
            start += 8

            sell_qtd = struct.unpack('i', frame[start:start+4])[0]
            start += 4

            avg_buy_price = struct.unpack('d', frame[start:start + 8])[0]
            start += 8

            buy_qtd = struct.unpack('i', frame[start:start+4])[0]
            start += 4

            custody_d1 = struct.unpack('i', frame[start:start+4])[0]
            start += 4

            custody_d2 = struct.unpack('i', frame[start:start+4])[0]
            start += 4

            custody_d3 = struct.unpack('i', frame[start:start+4])[0]
            start += 4

            blocked = struct.unpack('i', frame[start:start+4])[0]
            start += 4

            pending = struct.unpack('i', frame[start:start+4])[0]
            start += 4

            allocated = struct.unpack('i', frame[start:start+4])[0]
            start += 4

            provisioned = struct.unpack('i', frame[start:start+4])[0]
            start += 4

            qtd_position = struct.unpack('i', frame[start:start+4])[0]
            start += 4

            available = struct.unpack('i', frame[start:start+4])[0]
            start += 4

            print(f"Corretora: {corretora_id}, Titular: {str(titular)}, Ticker: {str(ticker)}, Price: {price}, AvgSellPrice: {avg_sell_price}, AvgBuyPrice: {avg_buy_price}, SellQtd: {sell_qtd}, BuyQtd: {buy_qtd}")

        return priceToReturn

def dllStart():    
    try:
        global profit_dll
        key = input("Chave de acesso: ")
        user = input("Usuário: ") # preencher com usuário da conta (email ou documento)
        password = input("Senha: ") # preencher com senha da conta
        
        bRoteamento = True
        
        if bRoteamento :            
            result = profit_dll.DLLInitializeLogin(c_wchar_p(key), c_wchar_p(user), c_wchar_p(password), stateCallback, historyCallBack, orderChangeCallBack, accountCallback,
                                              newTradeCallback, newDailyCallback, priceBookCallback,
                                              offerBookCallback, newHistoryCallback, progressCallBack, newTinyBookCallBack)
        else :
            result = profit_dll.DLLInitializeMarketLogin(c_wchar_p(key), c_wchar_p(user), c_wchar_p(password), stateCallback, newTradeCallback, newDailyCallback, priceBookCallback,
                                                 offerBookCallback, newHistoryCallback, progressCallBack, newTinyBookCallBack)

        profit_dll.SendSellOrder.restype = c_longlong
        profit_dll.SendBuyOrder.restype = c_longlong
        profit_dll.SendStopBuyOrder.restype = c_longlong
        profit_dll.SendStopSellOrder.restype = c_longlong
        profit_dll.SendZeroPosition.restype = c_longlong
        profit_dll.GetAgentNameByID.restype = c_wchar_p
        profit_dll.GetAgentShortNameByID.restype = c_wchar_p
        profit_dll.GetPosition.restype = POINTER(c_int)
        profit_dll.SendMarketSellOrder.restype = c_longlong
        profit_dll.SendMarketBuyOrder.restype = c_longlong

        print('DLLInitialize: ' + str(result))
        wait_login()
      
    except Exception as e:
        print(str(e))

if __name__ == '__main__':    
    try:
        dllStart()

        strInput = ''        

        while strInput != "exit":
            strInput = input('Insira o comando: ')
            if strInput == 'subscribe':
                subscribeTicker()
            elif strInput == 'unsubscribe':
                unsubscribeTicker()
            elif strInput == 'offerbook':
                subscribeOffer()
            elif strInput == 'position':
                printPosition()
            elif strInput == 'lastAdjusted':
                printLastAdjusted()
            elif strInput == 'buystop' :
                buyStopOrder()
            elif strInput == 'sellstop':
                sellStopOrder()
            elif strInput == 'cancel':
                cancelOrder()
            elif strInput == 'changeOrder':
                changeOrder()
            elif strInput == 'cancelAllOrders':
                cancelAllOrders()
            elif strInput == 'getOrders':
                getOrders()
            elif strInput == 'getOrder':
                getOrder()
            elif strInput == 'selectOrder':
                selectOrder()
            elif strInput == 'cancelOrder':
                cancelOrder()
            elif strInput == 'getOrderProfitID':
                getOrderProfitID()
            elif strInput == 'getAllTickersByStock':
                getAllTickersByStock()           
            elif strInput == 'getOld':
                getSerieHistory()        
            elif strInput == 'account':
                getAccount()         
            elif strInput == 'myBuy':
                sendBuyOrder()               
    except KeyboardInterrupt:                
        pass            

The correct log that I get when calling:

<ctypes.wintypes.LP_c_long object at 0x000001714E9CABC0>

When running directly the runner.py and calling printPosition(), everything works fine and it returns what I need (the object above).
Although, I need to import this printPosition in a separate file to make a call for it. When performing so, I received a number only and not the object I needed.

import socket, base64
import re
import sys
from operator import neg
from datetime import datetime
import profitrunner
import time
import gc
from ctypes import *
from ctypes.wintypes import UINT
import struct

def calculate_pos():
    memory_address = profitrunner.printPosition()       

    print(heapPosition)

    # I though on doing but did not work:  
  
    arr = cast(memory_address, POINTER(c_char))


The logs from this:

2015042512
2015042656
2015042800
2015042944
2015043088
2015043232

The documentation from GetPosition gives is the follwing:

Function that returns the position for a given ticker. Returns a data structure specified below. With full size (90 + N + T + K) bytes:

function GetPosition(
    pwcIDAccount   : PWideChar;
    pwcIDCorretora : PWideChar;
    pwcTicker      : PWideChar;
    pwcBolsa       : PWideChar) : Pointer; stdcall;

enter image description here

Answers:

You need something like this:

import ctypes as ct

profit_dll = ct.WinDLL('./ProfitDLL64.dll')
profit_dll.GetPosition.argtypes = ct.c_wchar_p, ct.c_wchar_p, ct.c_wchar_p, ct.c_wchar_p
profit_dll.GetPosition.restype = ct.POINTER(ct.c_int)

result = profit_dll.GetPosition(acc_id, thisCorretora, asset, bolsa)

The return type is only Pointer which isn’t descriptive, but in the .zip provided in comments the return type is POINTER(c_int) so I used that. No need to wrap every parameter in a C type if .argtypes is set properly for the function, but profitDLL.py isn’t doing that. Make sure to call dllStart() to set the return types, but it’s better to set .argtypes and .restype correctly for every function for better error checking by ctypes.

Answered By: Mark Tolonen
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.