본문 바로가기
지속가능티끌/Python

Python. ctypes. CFUNCTYPE. WINFUNCTYPE.콜백함수

by i.got.it 2019. 5. 16.

함수 프로토타입

함수 프로토타입의 인스턴스를 만들어서 외부 함수를 만들 수도 있습니다. 함수 프로토타입은 C의 함수 프로토타입과 비슷합니다; 구현을 정의하지 않고 함수(반환형, 인자형, 호출 규칙)를 설명합니다. 팩토리 함수는 원하는 결과형과 함수의 인자형들로 호출되어야 하며, 데코레이터 팩토리로 사용되어 @wrapper 문법을 통해 함수에 적용될 수 있습니다. 예제는 콜백 함수를 참조하십시오.

 

ctypes.CFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)

 

반환된 함수 프로토타입은 표준 C 호출 규칙을 사용하는 함수를 만듭니다. 이 함수는 호출 중에 GIL을 해제합니다. use_errno를 참으로 설정하면, 시스템 errno 변수의 ctypes 내부 복사본이 호출 전후에 실제 errno 값과 교환됩니다; use_last_error는 윈도우 에러 코드에 대해 같은 일을 합니다.

 

ctypes.WINFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)

윈도우 전용: 반환된 함수 프로토타입은 stdcall 호출 규칙을 사용하는 함수를 만듭니다. 단 WINFUNCTYPE()CFUNCTYPE()과 같은 윈도우 CE는 예외입니다. 이 함수는 호출 중에 GIL을 해제합니다. use_errno 와 use_last_error는 위에서와 같은 의미가 있습니다.

 

ctypes.PYFUNCTYPE(restype, *argtypes)

반환된 함수 프로토타입은 파이썬 호출 규칙을 사용하는 함수를 만듭니다. 이 함수는 호출 도중 GIL을 해제하지 않습니다.

 

 

상세.

https://docs.python.org/ko/3/library/ctypes.html#ctypes.CFUNCTYPE

 

ctypes --- 파이썬용 외부 함수 라이브러리 — Python 3.7.3 documentation

ctypes --- 파이썬용 외부 함수 라이브러리 ctypes는 파이썬용 외부 함수(foreign function) 라이브러리입니다. C 호환 데이터형을 제공하며, DLL 또는 공유 라이브러리에 있는 함수를 호출할 수 있습니다. 이 라이브러리들을 순수 파이썬으로 감싸는 데 사용할 수 있습니다. ctypes 자습서 참고: 이 자습서의 코드 예제는 doctest를 사용하여 실제로 작동하는지 확인합니다. 일부 코드 예제는 리눅스, 윈도우 또는 맥 OS X에서

docs.python.org

위 링크의 설명에서 중요해 보이는 주의 사항 복사해옴.

참고
 C 코드에서 사용되는 동안 CFUNCTYPE() 객체에 대한 참조를 유지해야 합니다. ctypes가 참조를 유지하지는 않으며, 여러분이 하지 않는다면 가비지 수집되어, 콜백이 발생할 때 프로그램이 충돌할 수 있습니다.
또한, 콜백 함수가 파이썬 제어 바깥에서 만들어진 스레드(예를 들어, 콜백을 호출하는 외부 코드)에서 호출되면, ctypes는 모든 호출에 대해 새로운 더미 파이썬 스레드를 만듭니다. 이 동작은 대부분 적합하지만, threading.local에 저장된 값은, 같은 C 스레드에서 호출되는 여러 콜백에서 살아남을 수 없음을 뜻합니다.

 

 

 

 

DLL 에서 파이썬의 함수 호출하기. - 콜백 개념 쉬운 이해.

- DLL 의 함수 인자로 파이썬의 함수를 전달하는법. 

 

DLL 코드.

//////////// C++ DLL 

typedef void(*pf_vv)(); //type : void function(void)

extern "C" __declspec(dllexport) void __stdcall test(pf_vv pf_test) 
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	pf_test(); 

}

 

파이썬 코드.

from ctypes import *

cyfinbot = windll.LoadLibrary("CyFinBot.dll") # windll for __stdcall DLL function. 

# DLL 에서 호출하려는 파이썬측 함수. 
def my_callback():
    print("Hello CallBack");

pf_vv = WINFUNCTYPE(None) # 아래 DLL함수의 인자로 함수포인터 전달하기 위하여 함수형을 먼저 선언. 

cyfinbot.test(pf_vv(my_callback)) # 전달할 함수를 앞에서 선언한 callback_type 으로 변환하여 전달.


 

설명 : 파이썬코드를 실행하면 DLL 로딩하고 DLL 함수 test 호출하면서 파이썬측의 함수 my_callback 을 인자로 전달하고 있다. 실행시키면 dll 함수 test() 호출되면 파이썬측의 my_callback 호출되므로 콘솔에 Hello Callback 글자 출력된다.

 

 

 

DLL 에서 파이썬의 함수 호출하기. - 구조체, 포인터

- 함수 인자에 구조체 및 포인터 w_char_t * 타입 있는 상황. 

- 앞의 간단한 상황과는 다르다. 결론적으로 아래 코드로 해결됨. 

- 요점 : DLL (C++) 에서 구조체 변수의 주소를 전달하면 파이썬에서 구조체 멤버 변수들에 값설정 해준다. 이때 일반 자료형들 int , float 등은 특별한 처리없이 쉽게 값할당이 되는데, wchart_t * 에 값을 할당 받는 처리부분이 파이썬에서 추가로 더 해줘야 한다는점.

 

DLL 코드

typedef struct {
	wchar_t* pstr_result; 
	int i_test; 

}CyST_RESULT_ORDER_NEW;

// 함수 인자로 상기 구조체 포인터 
typedef void(*pf_v_pcyst)(CyST_RESULT_ORDER_NEW *); // 


extern "C" __declspec(dllexport) void __stdcall regi_pfunction_order_CyFinBot(
                                                   pf_v_pcyst pf_order_new
                                                   )
{
	CyST_RESULT_ORDER_NEW cyst;
	pf_order_new(&cyst); // 파이썬의 함수 호출하면서 구조체 주소 전달하면 cyst 의 멤버값을 파이썬에서 대입해줌. 
}

 

파이썬 코드. 

# 구조체 타입선언.
class CyST_RESULT_ORDER_NEW(Structure):
    _pack_ = 4
    _fields_ = [("pstr_result",c_wchar_p),
                ("i_test", c_int)
               ]

# DLL 에서 호출하는 함수. 
def test_order_new(pst_result_order_new):  
    print(pst_result_order_new.contents.i_test)
    str_retv = str(client.Order.Order_new(side="Buy",symbol="BTCUSD",order_type="Limit",qty=1,price=8300,time_in_force="GoodTillCancel").result());
    p = create_unicode_buffer(str_retv); # 파이썬 스트링을 문자열 배열로 변환함. 

	# 중요. cast 함수로 p 를 c_wchar_p 타입으로 형변환함. 
    pst_result_order_new.contents.pstr_result = cast(p,c_wchar_p) # 중요: 구조체 포인터의 멤버 접근시 .contents.로 접근함. 
    pst_result_order_new.contents.i_test = 1237



cyfinbot = windll.LoadLibrary("CyFinBot.dll") #DLL 로딩. windll for __stdcall DLL function.  

cbTypeOrderNew = WINFUNCTYPE(None, POINTER(CyST_RESULT_ORDER_NEW)) # 함수포인터 타입정의하는것. 

cyfinbot.regi_pfunction_order_CyFinBot(cbTypeOrderNew(test_order_new)) # 콜백함수test_order_new 를 DLL로 전달했음. 

 

 

 

 

 

 

 

연관 

 

 

함수포인터, 콜백(Callback)

함수포인터 1. int Function(int a) {... } ; 로 정의된 함수가 있다치자. 2. 위 1의 함수의 포인터(함수이름이 포인터임)를 받을 수 있는 함수포인터 변수 선언하고 1의 함수포인터를 대입하는 방법 int (*pFunc)..

igotit.tistory.com

 

 


첫등록 : 2019년 5월 16일 

최종수정 : 2020.03.19

 

본 글 단축주소 : https://igotit.tistory.com/2171

 


 

 

'지속가능티끌 > Python' 카테고리의 다른 글

Python. if . 비교연산자, and, or not, in, not in ,  (0) 2019.05.16
Python. enum  (0) 2019.05.16
Python. function, 함수  (0) 2019.05.16
Python. tuple  (0) 2019.04.21
Python. matplotlib  (0) 2019.04.21

댓글



 

비트코인




암호화폐       외환/나스닥/골드         암호화폐/외환/나스닥/골드
     
현물 |선물 인버스 |선물 USDT       전략매니저(카피트레이딩)         프랍 트레이더 온라인 지원가능. MT4,MT5