Python과 DLL 사이에서의 interface방법에 대해 알아보자. DLL interface는 확장 DLL이 아닌 Generic DLL만 다룬다. 
simple interface
C part
아래 코드를 이용하여 dll을 만든다.
#include <stdio.h>

extern "C" _declspec(dllexport) int testDLL(void);

int testDLL(void)
{
    printf("Hello world\n");
    return 1;
};

python에서는 ctype을 사용하여 DLL을 load한 후 call하면 된다. 
from ctypes import *
dll = cdll.LoadLibrary('debug/ssdll.dll')
dll.testDLL()

hello world가 출력됨을 확인할 수 있다. 위의 내용이 visual C++ 파일로 첨부되어 있다.

Argument 전달
처음의 예는 argument 없이 함수 call만 하였는데 인자를 전달해 보자. 인자는 python에서 c_double(), c_int(), c_char_p(), c_long()을 사용하여 전달하면 된다. 
int testDLL2(int a, float b)
{
    return int(a + b);
}   
int testDLL3(char *p)
{
    printf(p);
    return 1;
};

# python
print dll.testDLL2(c_int(3),c_float(5.7))
dll.testDLL3(c_char_p('Hello from python'))

참고로 integer나 char pointer인 경우 c_int(), c_char_p()를 생략해도 된다. 


callback 함수 
python에서 DLL에 있는 함수를 call 할 수 있고, 또한 C에서 python 쪽의 함수를 call하거나 변수의 값을 읽어들일 수 있다. 
이것에 대해서는 첨부된 파일을 참조하면 별다는 어려움없이 이해할 수 있으리라 생각된다. 

첨부된 파일은 Visual C++ 2008 express version으로 작성되었다.



Implicit linking

 

순수 C언어로만 구성해보자.  참고로 개발 도구는 다음과 같다.

 

(1) 컴파일러 : Intel Compiler 10.1.020

(2) 툴 : Visual Studio 2008 Team System 2008

 

 

1. DLL 파일

 

Visual Studio -> Console Program -> empty project

 

참고로 프로젝트명은 testDll 이다.

파일명은 testDll.c 로 하고 다음과 같이 적는다.

 

__declspec(dllexport) char *str = "THE TRUTH IS OUT THERE";
__declspec(dllexport) int adds(int a, int b);

 

int adds(int a, int b)
{
 return a+b+10;
}

이렇게 소스 코드를 작성 후,  컴파일을 하자!

(순수 C언어로 컴파일 하기 위해 컴파일방법을 "C" 언어로만 하도록 바꾼다.  이는 Project->Properties->C/C++->Advanced

 Compile as 메뉴에서 "Compile as C COde" 로 하자.)

 

그러면 testDll.dll  및 testDll.lib 파일이 나온다.

(참고로 컴파일시 Project->Properties->General->Configuration type  에서 Dynamic Library 로 바꿔 주어야 한다.)

 

 

2. Dll 을 사용하는 코드

 

testadd.c

#include  <stdio.h>


__declspec(dllimport!) int adds(int,int);

(만약, 위의 줄을 사용하고 싶지 않으면 adds 를 헤더파일이 declaration 하면 된다.)


int main(void)
{

 printf("sum %d \n",adds(4,6));

  return EXIT_SUCCESS;
}

위와 같은 코드로 코딩한다.

 

Project->Properties->Linker -> Input ->Additional Dependencies 칸에 testDll.lib 를 적어넣는다.

 

(물론, 이 testadd.c 코드가 있는 디렉토리에 앞서 1번에서 만든 testDll.lib 파일을 복사해 넣어야 오류없이 컴파일이 될 것이다.)



[출처 : http://blog.daum.net/artofprogramming/4526762]

 - Explicit linking -

 

순수 C언어로만 구성해보자.  참고로 개발 도구는 다음과 같다.

 

(1) 컴파일러 : Intel Compiler 10.1.020

(2) 툴 : Visual Studio 2008 Team System 2008

 

 

1. DLL 파일

 

Visual Studio -> Console Program -> empty project

 

참고로 프로젝트명은 testDll 이다.

파일명은 testDll.c 로 하고 다음과 같이 적는다.

 

__declspec(dllexport) char *str = "THE TRUTH IS OUT THERE";
__declspec(dllexport) int adds(int a, int b);

 

int adds(int a, int b)
{
 return a+b+10;
}

이렇게 소스 코드를 작성 후,  컴파일을 하자!

(순수 C언어로 컴파일 하기 위해 컴파일방법을 "C" 언어로만 하도록 바꾼다.  이는 Project->Properties->C/C++->Advanced

 Compile as 메뉴에서 "Compile as C COde" 로 하자.)

 

그러면 testDll.dll  파일이 나온다.

(참고로 컴파일시 Project->Properties->General->Configuration type  에서 Dynamic Library 로 바꿔 주어야 한다.)

 

 

2. Dll 를 사용하는 소스

 

Visual Studio -> Console Program -> empty project

 

프로젝트명은 "test" 로 한다.

 

(여기서 주의점은 LoadLibrary 시 UNICODE 로 된 dll 파일명을 넘겨야 컴파일시 에러가 발생하지 않는데, 이를 위해서

 _T() 매크로를 사용해서 넘겨야 한다.  문젠 이 _T 매크로를 사용하기 위해선 MFC 를 사용해야 한다. 

 따라서 이 예제에서는 어쩔 수 없이 순수 C가 아닌 C++ 로 컴파일을 대체해야 한다.

 

 만약, 본인이 순수 C 를 이용해 _T() 매크로를  대체 할 수  있는 코드를 만들어서 테스트 해본 후 성공한다면 업데이트 할 것이다.)

 

 

test.cpp 파일을 등록하고 아래와 같이 코딩한다.

 

(주의 사항 : !! MFC 를 위해 <afx.h> 및 <afxwin.h> 를 사용할 텐데, 이는 반드시 <windows.h> 보다 위에 와야 한다.)

 

#include <afx.h>
#include <afxwin.h>
#include <stdio.h>

#include <windows.h>

int main(void)
{

//function pointer

int (*adds)(int, int);


 // DLL Load
 HMODULE  hInst;
 hInst = LoadLibrary(_T("testDll.dll"));
 if(hInst==NULL) {

  printf("failuressss \n");
  return EXIT_FAILURE;

 }

 adds = (int (*)(int, int))GetProcAddress(hInst, "adds");
 printf("sum %d \n",adds(4,6));
 FreeLibrary(hInst);

 

 

  return EXIT_SUCCESS;
}

컴파일을 한 후 생성되는 실행파일과 같은 디렉토리에 1번에서 만든 testDll.dll 파일을 함께 놓고 실행하면 결과가 나올 것이다.



[출처 : http://blog.daum.net/artofprogramming/4526612]

1. Dll 파일을 만들때는 가급적 __cdecl  형식으로 컴파일 해야 된다.

 

   __cdecl 은 컴파일시 함수의 이름이 바뀌는 naming 규칙 중 하나로써, __stdcall 및 __fastcall 도 있다.

 

 

  만약,  LoadLibrary 계열의 함수를 사용할 경우 __cdecl 이라는 형식으로 컴파일이 되어 있지 않은 경우

  GetProcAddress() 함수에서 찾아낼 함수의 이름을 다르게 해줘야 한다.

 

  예를들어 작성한 함수의 이름이 test() 이라고 한다면

 

  __cdecl 은 test

  __stdcall 은 _test@숫자

  __fastcall 은 @test@숫자

 

  이렇게 저장되어 있을 것이다. 

 

  따라서 GetProcAddress 에서 __cdecl 사용시에는 "test" 라고 호출하면 되지만

  __stdcall 에서는 "_test@숫자" 이렇게 바뀐 함수명을 호출해야 제대로 검색 할 것이다.

 

 

  반면에 LoadLibrary 함수를 사용하지 않고 "foo.lib" 파일을 사용해서 컴파일시 linking 을 한다면

  반드시 __cdecl 형식으로 해야 한다.  그래야 linking 시 함수명을 제대로 찾아서 올바르게 linking 할 수 있기 때문이다.

 

  p.s. : exe 파일이나 dll 및 lib 파일에서 만들어진 외부에 연결되도록 한 함수명을 보고 싶으면 "dumpbin /exports" 를 사용하고

          자기가 사용하는 함수명을 보고 싶으면 "dumpbin /import!s" 를 하면 된다.

 

  p.s. : 일반 cmd 창을 띄우면 dumpbin 명령이 안 먹힐 것이다.  이는 Visual Studio Command Prompt 로 만들어진 cmd 창에서

          실행시켜야 한다.



[출처 : http://blog.daum.net/artofprogramming/4526245]

DLL

간략하게 말해서 windows 플랫폼 환경에서 "Dynamic Library" 기술을 사용하도록 하는 방법

 

UNIX / LINUX 플랫폼에서는 "foo.so" 라는 파일을 만듬으로써 "Dynamic Library" 기술을 활용할 수 있다.

 

본론에 앞서서  UNIX/LINUX 플랫폼과의 비교를 간단하게 해보면 다음과 같다.

 

 

UNIX/LINUX  에서는 컴파일 이후  linking 작업시 "foo.so" 파일이 필요

Win32 에서는 컴파일 이후 linking 작업시 Dll 파일 생성시 함께 만들어지는  "foo.lib" 파일이 필요하다

그리고  양쪽 플랫폼 모두 마치 foo.h 라는 헤더 파일을 이용해서 함수를 호출하는 방법으로 프로그래밍 하면 된다.

 

예를 들어, foo.dll 안에 test() 라는 함수를 호출하고 싶다면, foo.h 에 함수의 prototype 을 declaration 한 후, 이를 사용할

파일에 인클루드 한 후 printf() 를 호출하듯이 test() 함수를 호출하면 된다.

 

이 방법에서는 굳이 library 안에 있는 함수의 주소를 가져오는 일을 하지 않아도 된다.

 

 

실제 프로그램 구동시,

UNIX/LINUX 에서는 "foo.so" 라는 linking 시 사용한 파일이 동일하게 사용

Win32  에서는 "foo.dll" 이라는 파일이 필요

 

 

만약, 프로그램 실행시 linking이 되도록 사용을 하려면

UNIX/LINUX 에서는 dlopen 계열의 함수를 사용하고

Win32 에서는 LoadLibrary 계열의 함수를 사용하면 된다.

이 방법은 UNIX/LINUX 나 Win32 플랫폼 모두 실제로 메모리에 load 되는 library 안에 있는 사용할 함수의 주소를 가져와야 하는 작업을 해야 한다.


[출처 : http://blog.daum.net/artofprogramming/4525745]

+ Recent posts