다음을 통해 공유


방법: 마샬링 라이브러리 확장명

이 항목에서는 마샬링 라이브러리를 확장하여 데이터 형식 간에 더 많은 변환을 제공하는 방법을 설명합니다. 사용자는 라이브러리에서 현재 지원되지 않는 데이터 변환에 대해 마샬링 라이브러리를 확장할 수 있습니다.

marshal_context 클래스를 사용하거나 사용하지 않고 두 가지 방법 중 하나로 마샬링 라이브러리를 확장할 수 있습니다. C++ 항목의 마샬링 개요를 검토하여 새 변환에 컨텍스트가 필요한지 여부를 확인합니다.

두 경우 모두 먼저 새 마샬링 변환을 위한 파일을 만듭니다. 이렇게 하면 표준 마샬링 라이브러리 파일의 무결성을 유지할 수 있습니다. 프로젝트를 다른 컴퓨터 또는 다른 프로그래머로 포팅하려면 프로젝트의 나머지 부분과 함께 새 마샬링 파일을 복사해야 합니다. 이러한 방식으로 프로젝트를 수신하는 사용자는 새 변환을 받도록 보장되며 라이브러리 파일을 수정할 필요가 없습니다.

컨텍스트가 필요하지 않은 변환을 사용하여 마샬링 라이브러리를 확장하려면

  1. 새 마샬링 함수(예: MyMarshal.h)를 저장할 파일을 만듭니다.

  2. 하나 이상의 마샬링 라이브러리 파일을 포함합니다.

    • 기본 형식의 경우 marshal.h입니다.

    • windows 데이터 형식의 경우 marshal_windows.h입니다.

    • C++ 표준 라이브러리 데이터 형식에 대한 marshal_cppstd.h입니다.

    • ATL 데이터 형식의 경우 marshal_atl.h입니다.

  3. 이러한 단계의 끝에 있는 코드를 사용하여 변환 함수를 작성합니다. 이 코드에서 TO는 변환할 형식이고 FROM은 변환할 형식이며 from 변환할 매개 변수입니다.

  4. 변환 논리에 대한 주석을 코드로 바꿔 매개 변수를 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.
      }
   }
}

컨텍스트가 필요한 변환을 사용하여 마샬링 라이브러리를 확장하려면

  1. 새 마샬링 함수(예: MyMarshal.h)를 저장할 파일을 만듭니다.

  2. 하나 이상의 마샬링 라이브러리 파일을 포함합니다.

    • 기본 형식의 경우 marshal.h입니다.

    • windows 데이터 형식의 경우 marshal_windows.h입니다.

    • C++ 표준 라이브러리 데이터 형식에 대한 marshal_cppstd.h입니다.

    • ATL 데이터 형식의 경우 marshal_atl.h입니다.

  3. 이러한 단계의 끝에 있는 코드를 사용하여 변환 함수를 작성합니다. 이 코드에서 TO는 변환할 형식이고 FROM은 변환할 형식이며 결과를 toObject 저장할 포인터이며 fromObject 변환할 매개 변수입니다.

  4. 초기화에 대한 주석을 코드로 바꿔 적절한 빈 값으로 초기화 toPtr 합니다. 예를 들어 포인터인 경우 으로 설정합니다 NULL.

  5. 변환 논리에 대한 주석을 매개 변수를 TO 형식의 개체로 변환 from 하는 코드로 바꿉다. 이 변환된 개체는 에 toPtr저장됩니다.

  6. 설정 toObject 에 대한 설명을 변환된 개체로 설정할 toObject 코드로 바꿉다.

  7. 네이티브 리소스 정리에 대한 설명을 코드로 바꿔 할당된 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

참고 항목

C++ 마샬링 개요