함수 프로토타입
함수 프로토타입의 인스턴스를 만들어서 외부 함수를 만들 수도 있습니다. 함수 프로토타입은 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
위 링크의 설명에서 중요해 보이는 주의 사항 복사해옴.
참고 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로 전달했음.
연관
첫등록 : 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 |
댓글