방법: 마샬링 라이브러리 확장명
이 항목에서는 마샬링 라이브러리를 확장하여 데이터 형식 간에 더 많은 변환을 제공하는 방법을 설명합니다. 사용자는 라이브러리에서 현재 지원되지 않는 데이터 변환에 대해 마샬링 라이브러리를 확장할 수 있습니다.
marshal_context 클래스를 사용하거나 사용하지 않고 두 가지 방법 중 하나로 마샬링 라이브러리를 확장할 수 있습니다. C++ 항목의 마샬링 개요를 검토하여 새 변환에 컨텍스트가 필요한지 여부를 확인합니다.
두 경우 모두 먼저 새 마샬링 변환을 위한 파일을 만듭니다. 이렇게 하면 표준 마샬링 라이브러리 파일의 무결성을 유지할 수 있습니다. 프로젝트를 다른 컴퓨터 또는 다른 프로그래머로 포팅하려면 프로젝트의 나머지 부분과 함께 새 마샬링 파일을 복사해야 합니다. 이러한 방식으로 프로젝트를 수신하는 사용자는 새 변환을 받도록 보장되며 라이브러리 파일을 수정할 필요가 없습니다.
컨텍스트가 필요하지 않은 변환을 사용하여 마샬링 라이브러리를 확장하려면
새 마샬링 함수(예: MyMarshal.h)를 저장할 파일을 만듭니다.
하나 이상의 마샬링 라이브러리 파일을 포함합니다.
기본 형식의 경우 marshal.h입니다.
windows 데이터 형식의 경우 marshal_windows.h입니다.
C++ 표준 라이브러리 데이터 형식에 대한 marshal_cppstd.h입니다.
ATL 데이터 형식의 경우 marshal_atl.h입니다.
이러한 단계의 끝에 있는 코드를 사용하여 변환 함수를 작성합니다. 이 코드에서 TO는 변환할 형식이고 FROM은 변환할 형식이며
from
변환할 매개 변수입니다.변환 논리에 대한 주석을 코드로 바꿔 매개 변수를 TO 형식의 개체로 변환
from
하고 변환된 개체를 반환합니다.
namespace msclr {
namespace interop {
template<>
inline TO marshal_as<TO, FROM> (const FROM& from) {
// Insert conversion logic here, and return a TO parameter.
}
}
}
컨텍스트가 필요한 변환을 사용하여 마샬링 라이브러리를 확장하려면
새 마샬링 함수(예: MyMarshal.h)를 저장할 파일을 만듭니다.
하나 이상의 마샬링 라이브러리 파일을 포함합니다.
기본 형식의 경우 marshal.h입니다.
windows 데이터 형식의 경우 marshal_windows.h입니다.
C++ 표준 라이브러리 데이터 형식에 대한 marshal_cppstd.h입니다.
ATL 데이터 형식의 경우 marshal_atl.h입니다.
이러한 단계의 끝에 있는 코드를 사용하여 변환 함수를 작성합니다. 이 코드에서 TO는 변환할 형식이고 FROM은 변환할 형식이며 결과를
toObject
저장할 포인터이며fromObject
변환할 매개 변수입니다.초기화에 대한 주석을 코드로 바꿔 적절한 빈 값으로 초기화
toPtr
합니다. 예를 들어 포인터인 경우 으로 설정합니다NULL
.변환 논리에 대한 주석을 매개 변수를 TO 형식의 개체로 변환
from
하는 코드로 바꿉다. 이 변환된 개체는 에toPtr
저장됩니다.설정
toObject
에 대한 설명을 변환된 개체로 설정할toObject
코드로 바꿉다.네이티브 리소스 정리에 대한 설명을 코드로 바꿔 할당된
toPtr
메모리를 해제합니다. 메모리를 사용하여new
할당된 경우toPtr
메모리를 해제하는 데 사용합니다delete
.
namespace msclr {
namespace interop {
template<>
ref class context_node<TO, FROM> : public context_node_base
{
private:
TO toPtr;
public:
context_node(TO& toObject, FROM fromObject)
{
// (Step 4) Initialize toPtr to the appropriate empty value.
// (Step 5) Insert conversion logic here.
// (Step 6) Set toObject to the converted parameter.
}
~context_node()
{
this->!context_node();
}
protected:
!context_node()
{
// (Step 7) Clean up native resources.
}
};
}
}
예: 마샬링 라이브러리 확장
다음 예제에서는 컨텍스트가 필요하지 않은 변환을 사용하여 마샬링 라이브러리를 확장합니다. 이 예제에서 코드는 직원 정보를 네이티브 데이터 형식에서 관리되는 데이터 형식으로 변환합니다.
// MyMarshalNoContext.cpp
// compile with: /clr
#include <msclr/marshal.h>
value struct ManagedEmp {
System::String^ name;
System::String^ address;
int zipCode;
};
struct NativeEmp {
char* name;
char* address;
int zipCode;
};
namespace msclr {
namespace interop {
template<>
inline ManagedEmp^ marshal_as<ManagedEmp^, NativeEmp> (const NativeEmp& from) {
ManagedEmp^ toValue = gcnew ManagedEmp;
toValue->name = marshal_as<System::String^>(from.name);
toValue->address = marshal_as<System::String^>(from.address);
toValue->zipCode = from.zipCode;
return toValue;
}
}
}
using namespace System;
using namespace msclr::interop;
int main() {
NativeEmp employee;
employee.name = "Jeff Smith";
employee.address = "123 Main Street";
employee.zipCode = 98111;
ManagedEmp^ result = marshal_as<ManagedEmp^>(employee);
Console::WriteLine("Managed name: {0}", result->name);
Console::WriteLine("Managed address: {0}", result->address);
Console::WriteLine("Managed zip code: {0}", result->zipCode);
return 0;
}
이전 예제에서 함수는 marshal_as
변환된 데이터에 대한 핸들을 반환합니다. 이 작업은 데이터의 추가 복사본을 만들지 못하도록 하기 위해 수행되었습니다. 변수를 직접 반환하면 불필요한 성능 비용이 발생합니다.
Managed name: Jeff Smith
Managed address: 123 Main Street
Managed zip code: 98111
예: 직원 정보 변환
다음 예제에서는 직원 정보를 관리되는 데이터 형식에서 네이티브 데이터 형식으로 변환합니다. 이 변환에는 마샬링 컨텍스트가 필요합니다.
// MyMarshalContext.cpp
// compile with: /clr
#include <stdlib.h>
#include <string.h>
#include <msclr/marshal.h>
value struct ManagedEmp {
System::String^ name;
System::String^ address;
int zipCode;
};
struct NativeEmp {
const char* name;
const char* address;
int zipCode;
};
namespace msclr {
namespace interop {
template<>
ref class context_node<NativeEmp*, ManagedEmp^> : public context_node_base
{
private:
NativeEmp* toPtr;
marshal_context context;
public:
context_node(NativeEmp*& toObject, ManagedEmp^ fromObject)
{
// Conversion logic starts here
toPtr = NULL;
const char* nativeName;
const char* nativeAddress;
// Convert the name from String^ to const char*.
System::String^ tempValue = fromObject->name;
nativeName = context.marshal_as<const char*>(tempValue);
// Convert the address from String^ to const char*.
tempValue = fromObject->address;
nativeAddress = context.marshal_as<const char*>(tempValue);
toPtr = new NativeEmp();
toPtr->name = nativeName;
toPtr->address = nativeAddress;
toPtr->zipCode = fromObject->zipCode;
toObject = toPtr;
}
~context_node()
{
this->!context_node();
}
protected:
!context_node()
{
// When the context is deleted, it will free the memory
// allocated for toPtr->name and toPtr->address, so toPtr
// is the only memory that needs to be freed.
if (toPtr != NULL) {
delete toPtr;
toPtr = NULL;
}
}
};
}
}
using namespace System;
using namespace msclr::interop;
int main() {
ManagedEmp^ employee = gcnew ManagedEmp();
employee->name = gcnew String("Jeff Smith");
employee->address = gcnew String("123 Main Street");
employee->zipCode = 98111;
marshal_context context;
NativeEmp* result = context.marshal_as<NativeEmp*>(employee);
if (result != NULL) {
printf_s("Native name: %s\nNative address: %s\nNative zip code: %d\n",
result->name, result->address, result->zipCode);
}
return 0;
}
Native name: Jeff Smith
Native address: 123 Main Street
Native zip code: 98111