C#의 .dll Library를 C++에서 활용하기


(C# 프로그램을 .dll Library로 만드는 방법은 여기를 클릭)


C#에서 생성한 .dll파일과 .tlb 파일을 C++의 해당 프로젝트 폴더안과 .exe 실행파일이 있는 곳에 복사해 넣는다.

이제 남은 것은 C++ 소스코드 작성법만 알면 C#에서 만든 .dll Library를 C++에서 사용할수 있게 된다.

샘플 예제 코드는 다음과 같다. 각 부분에 대한 설명은 아래 코드상에 있다.

아래 코드는 MFC에서 정보 확인 버튼 클릭시 C# .dll Library의 특정 메소드(함수)를 실행하고 C# .dll이 던져주는 정보(결과)를 보여주는 기능을 구현한 코드 조각이다.


이때 다음과 같이 .tlb 파일을 #include 아랫쪽에 import해 주어야 정상적으로 C# .dll 라이브러리에 있는 메소드들을 MFC에서 사용할수 있다.


#import "ExMakeClassLibSerialRead.tlb" no_namespace named_guids


//MFC에서 C#의 라이브러리 .dll을 이용한다.

void CMFC_UseCsharpDllDlg::OnBnClickedButton1()

{

// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.


//ICallClass는 C#의 interface이름이다.

//public interface ICallClass { .... }과 같이 C#에서 선언되어 있는 부분이다.

ICallClass *csharp = NULL;


//CoInitialize()

//==> Initializes the COM library on the current thread and identifies the concurrency model 

//==> as single-thread apartment (STA).

//COM이란, 컴포넌트 오브젝트 모델(Component Object Model, COM)은 마이크로소프트가 개발한 

//소프트웨어 구성 요소들의 응용 프로그램 이진 인터페이스이다. 

//COM을 이용해 개발된 프로그램들은 프로세스간 통신과 동적 오브젝트 생성이 가능하다. 

CoInitialize(NULL);


//typedef long HRESULT

//CoCreateInstance(CLSID_C#의클래스이름, NULL, CLSCTX_INPROC_SERVER, IID_C#의interface이름, 

//                 reinterpret_cast<void**>(&C#의interface이름type으로선언된참조변수명));

//아래의 CLSID_Class1에서 Class1은 C#에서 사용자가 필요로하는 기능을 담고 있는 클래스인데 

        //C#에서 다음과 같이 정의되어 있다.

//public class Class1 : ICallClass { ... } 자세한 것은 C#의 ExMakeClassLibSerialRead라는 이름의 프로젝트를 참조할 것

//아래에서 IID_ICallClass에서 ICallClass는 C#에서 public interface ICallClass { ... }와 같이 선언된 부분의 interface 이름이다.

HRESULT hr = CoCreateInstance(CLSID_Class1, NULL, CLSCTX_INPROC_SERVER, IID_ICallClass, reinterpret_cast<void**>(&csharp));

//SUCCEEDED macro

//Provides a generic test for success on any status value.

//BOOL SUCCEEDED(HRESULT hr);

//==> hr : The status code.This value can be an HRESULT or an SCODE.A non - negative number indicates success.

//==> Return value : TRUE if hr represents a success status value; otherwise, FALSE.

if (SUCCEEDED(hr))

{

//showInfo() 함수는 C#에서 public void showInfo() { ... }과 같이 정의되어 있는 C#용 메소드이다.

csharp->showInfo();


CString msg = csharp->getInfo();

MessageBox(msg);


}

else {

MessageBox(_T("실패~\n\nC++의 exe 실행파일이 있는 위치에 \nC#에서 생성한 .dll과 .tlb가 있어야 합니다."));

}

}



본 프로그램은 n명의 학생 각각이 m개의 과목을 수강할 경우에 대한 

2차원 배열을 선언하는 형태인데 학생 수가 고정되어 있지 않고 가변이고

각 학생의 수강 과목도 고정되어 있지 않고 각각 상이하다고 할 때의 

상황이다. 이때 가장 적합한 2차원 배열의 형태가 "2차원 포인터(포인터의 포인터)"

형태로 선언하는 것에 대한 예제 코드이다.


#include <iostream>

#include <malloc.h>


using namespace std;


void main()

{

//2차원 포인터는 2차원 배열의 형태를 갖는데 

//세로(행, row)도 가변적인 배열, 가로(열, column)도 가변의 크기를 갖는 배열이라는 뜻이다.

int** score;

int studentNum = 0;

int lessonNum = 0;

int allTotalSize = 0;


cout << "학생 수 입력 : ";

cin >> studentNum;


//studentNum 갯수 만큼의 크기를 가진 배열이 선언되는데 이 배열의 각 원소가

//int형 포인터 변수이므로 각 원소가 또 동적 할당으로 임의 크기의 배열의 시작 주소를

//가리키게 되므로 결국 2차원 배열이 되는 것이다.

//즉 studentNum 갯수 만큼의 크기를 가진 int형 포인터 변수가 배열 형태로

//선언되고 그 시작 주소 값을 score에 저장한다.

//통상적으로 이렇게 생성되는 배열을 2차원 배열의 행(row, 가로)의 크기로 본다.

score = new int*[studentNum];

cout << "sizeof(score) : " << sizeof(score) << " byte" << endl;

cout << "_msize(score) : " << _msize(score) << " byte" << endl << endl;


//_msize()함수에 대해: new로 생성된 메모리는 heap 메모리 영역에 생성되고

//heap 메모리 영역은 운영체자가 관리해 주기 때문에 동적 할당된 메모리의 크기를

//알기 위해서는 운영체제의 도움이 필요하다.

//윈도우의 경우 _msize()함수를 통해 알수 있다.

//반면에 sizeof()함수는 포인터 변수 자체의 크기를 반환하는데 포인터 변수는 항상 4byte로 동일하다

//아래의 코드는 score가 가리키는 동적 할당된 메모리 전체의 크기를 반환한다.

//score = new int*[studentNum]으로 할당되었기에 

//studentNum * 4(int형의 크기가 4byte이므로)의 크기를 가진다.

allTotalSize = _msize(score);


//studentNum 갯수 만큼의 배열 각 요소인 int형 포인터 변수 각각에 대해

//동적 메모리 할당을 통해 또 다시 배열을 만든다. 따라서 2차원 배열이 되는 것이다.

//통상적으로 이렇게 생성되는 배열을 2차원 배열의 열(column, 세로)의 크기로 본다.

for (int i = 0; i < studentNum; i++)

{

cout << (i+1) << "번 학생의 수강 과목 수 : ";

cin >> lessonNum;


score[i] = new int[lessonNum];

allTotalSize += _msize(score[i]);

cout << (i + 1) << "번째 배열의 크기 : " << _msize(score[i]) << " byte" << endl << endl;

}


cout << endl << "2차원 포인터 배열 전체의 크기 : " << allTotalSize << " byte" << endl;


//여기서 성적 입력 및 평균, 총점 처리...


//메모리 해제(동적 할당된 메모리는 사용후 반드 해재해 줘야함!)

for (int i = 0; i < studentNum; i++)

{

delete[] score[i];

//delete score[i]; //이 경우는 i번째 배열 전체가 아닌 그 배열의 시작 주소만 해제 함

}


delete[] score;


cout << endl << "동적 할당 메모리 해제 완료~" << endl;

}


실행 결과는 다음과 같다.








'C++' 카테고리의 다른 글

C#의 .dll Library를 C++에서 활용하기  (0) 2017.12.08
memcpy()함수를 이용한 문자열 복사 하기  (0) 2017.07.25

memcpy()함수를 이용한 문자열 복사 하기


char *name = "홍 길동";


//strlen() : 현재 문자열의 크기 값을 반환

//size_t strlen(const char *_Str)

//따라서 매개인자의 데이터 타입은 char* 형

char *kkk = new char[strlen(name) + 1];


//만일 char *kkk = new char[strlen(name) + 1]의 작업 없이 

//char *kkk;로만 선언후 memcpy(kkk, name, strlen(name))과 같이 하면

//이 경우는 "초기화되지 않은 'kkk' 지역 변수를 사용했습니다."라는 에러 발생.

//이유는 메모리 할당되지 않은 상태에서 memcpy()로 복사하고자 했기 때문이다.


//memcpy() : void *memcpy(void *dest, const void *src, size_t count)

//아래는 name에 있는 문자열을 kkk에 복사를 하되 strlen(name)+1만큼 복사

memcpy(kkk, name, strlen(name));


//printf("kkk : %s\n", kkk);

//cout << "kkk : " << *kkk << endl; //not work

cout << "kkk : " << kkk << endl; //work





+ Recent posts