1. Basis
Visual C++은 Windows SDK, MFC와 .Net Framework를 동시에 사용하여 개발이 가능하다. C++/CLI(이전 Managed Extensions for C++)라 불리우는 .Net Framework를 위한 언어규격을 사용하여 .NET Framework를 위한 코드를 개발할 수 있다.
이를 이용하여 .Net과 C API의 중간자로서, .Net에서 직접적으로 사용하기 힘든 각종 C Library를 .Net에서 직접사용할 수 있도록 하는 DLL을 만들 수 있다. 즉, 내부적으로는 C/API/MFC를 사용하고 외부로의 기능노출을 .Net으로 개발하여 중간자 역할을 하는 DLL 개발이 가능하다.
1.1. Features
- 내부적으로 C,API, MFC 등 Visual C++의 모든 기능을 사용할 수 있다.
- C++/CLI를 사용하여 .Net의 모든 Class를 사용할 수 있다.
- C++/CLI를 사용하여 .Net에서 참조만으로 사용가능한 Class를 만들 수 있다.
1.2. API Proxy Class
.Net에서 MFC 기능을 사용하고 싶다거나, 복잡한 Pointer 구조 등을 사용하는 C API를 .Net에서 사용하고 싶은 경우, 기존의 Visual C#이나 Visual Basic에서는 사용이 불가하거나, 그 사용법의 복잡함으로 인하여 개발이 용이하지 않은 경우가 많다.
이러한 경우, Visual C++을 이용하여 C Library를 .Net과 호환시켜주는 Proxy Class를 만들어, .Net에서 사용할 수 있도록 할 수 있다.
이렇게 하는 경우 .Net에서 사용할 수 없는 C++ Class를 사용할 수 있게 하여 C++ 개발자와 C# 개발자의 협력이 가능하다.
1.3. C++/CLI 구문
- Class 선언
C++/CLI에서 관리되는 형식의 선언방법은 아래와 같다.
ref class Block {}; // reference class value class Vector {}; // value class interface class I {}; // interface class ref class Shape abstract {}; // abstract class ref class Shape2D sealed: Shape{}; // derived class
- 개체 선언
C++/CLI에서 관리되는 형식의 개체선언은 아래와 같이 “^”를 이용하여 선언한다. “^”는 관리되는 개체형식의 Pointer를 의미한다.
public ref class Form1 : System::Windows::Forms::Form { System::ComponentModel::Container^ components; System::Windows::Forms::Button^ button1; System::Windows::Forms::DataGrid^ myDataGrid; System::Data::DataSet^ myDataSet; };
- 관리되는 Object 생성
C++/CLI에서 Object의 생성은 “gcnew”를 사용한다.
Button^ button1 = gcnew Button; // managed heap int * pi1 = new int; // native heap Int32^ pi2 = gcnew Int32; // managed heap
- CLR 배열
“array” keyword 사용
array<Object^>^ myArr
array<int,3>^ myArr
- Property (속성)
“property” keyword 사용
public ref class Vector sealed { double _x; public: property double x { double get() { return _x; } void set( double newx ){ _x = newx; } } };
2. Making C++/CLI DLL
2.1. Object
간단한 DLL을 만들기 위하여 아래와 같은 기능을 가지는 Class를 DLL로 만들기로 한다.
- MFC의 CFtpConnection Class를 .NET에서 사용할 수 있는 CLR Class를 제작
- 동작의 시험을 위하여 Connect/Disconnect 기능만을 구현한다.
2.2. Implementation
- 아래와 같이 새 프로젝트를 선택하고 “Visual C++” 카테고리의 “클래스 라이브러리”를 선택하여 프로젝트를 생성한다.
- 프로젝트 속성 페이지에서 “구성속성 ? 일반” 카테고리를 선택하여 “MFC사용” 항목에서 “공유 DLL에서 MFC사용”을 선택한다.
[Stdafx.h]
#include <afxwin.h> #include <afxinet.h>
- .Net에서 사용할 CLR Class를 작성한다. 실제 내부적으로 사용할 MFC의 CFTPConnection Class를 위한 변수를 멤버로 추가한다. Class는 Resource 반환을 위하여 IDisposable Interface를 구현한다. 또한 서버의 접속/접속해제를 위한 함수를 추가한다. 함수의 파라미터는 .NET에서 사용할 것이므로 CLR Type을 사용한다.
[FTPProxySample.h]
namespace FTPProxySample { public ref class FtpConnection : public IDisposable { public: FtpConnection(); ~FtpConnection(); void Open(String^ serverURL, int Port, String^ ClientName, String^ UserID, String^ Pwd); void Close(); private: CInternetSession* m_pSession; CFtpConnection* m_pFtpConn; }; }
- 실제 Connect와 Close의 구현을 추가한다. 각 함수는 실제 MFC Class의 오브젝트를 이용하여 처리를 하면된다. 이렇게 하는 경우, .NET에서 함수를 호출하면, 함수에서 MFC를 접근하여 각 처리를 수행하게 된다.
[FTPProxySample.cpp]
namespace FTPProxySample { FtpConnection::FtpConnection() { m_pSession = NULL; m_pFtpConn = NULL; } FtpConnection::~FtpConnection() { Close(); System::GC::SuppressFinalize(this); } void FtpConnection::Open(String^ ServerURL, int Port, String^ ClientName, String^ UserID, String^ Pwd) { CString serverURL(ServerURL); CString userID(UserID); CString password(Pwd); CString clientName(ClientName); m_pSession = new CInternetSession(clientName); // FTP 접속 try { m_pFtpConn = m_pSession->GetFtpConnection(serverURL, userID, password, Port); } catch(CInternetException* pe) { // Exception 처리 } } void FtpConnection::Close() { if(m_pSession != NULL) { m_pSession->Close(); delete m_pSession; m_pSession = NULL; m_pFtpConn = NULL; } } }
- 컴파일을 하면, .NET에서 참조가능한 FTPProxySample.dll이 만들어진다.
3. Using C++/CLI DLL
- 만들어진 DLL은 .NET용 DLL이므로, .NET 프로젝트에서 “참조추가”를 하면, 바로 DLL내의 Class를 사용할 수 있다.
- 아래와 같이 참조한 DLL의 Class의 객체를 생성하여 사용한다.
private void button1_Click(object sender, EventArgs e) { using (var ftp = new FTPProxySample.FtpConnection()) { try { ftp.Open("server-url", 21, "Test", "id", "password"); MessageBox.Show("Success"); } catch (Exception ex) { MessageBox.Show(ex.Message); } } }
댓글 없음:
댓글 쓰기