共用方式為


如何:擴充封送處理程式庫

本主題說明如何擴充封送處理程式庫,以提供資料類型之間的更多轉換。 使用者可以針對程式庫目前不支援的任何資料轉換,擴充封送處理程式庫。

您可以使用下列兩種方式之一來擴充封送處理程式庫:使用或不使用 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. 將轉換邏輯的相關批註取代為程式碼,以將 參數轉換成 from TO 類型的物件,並傳回轉換的物件。

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. 將轉換邏輯的相關批註取代為程式碼,以將參數轉換成 from TO 類型的物件 。 這個轉換的物件將會儲存在 中 toPtr

  6. 將有關設定 toObject 的批註取代為要設定 toObject 為已轉換物件的程式碼。

  7. 以程式碼取代清除原生資源的批註,以釋放 所 toPtr 配置的任何記憶體。 如果使用 toPtr 配置記憶體 new ,請使用 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.
         }
      };
   }
}

範例:擴充封送處理程式庫

下列範例會使用不需要內容的轉換來擴充封送處理程式庫。 在此範例中,程式碼會將員工資訊從原生資料類型轉換成 Managed 資料類型。

// 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

範例:轉換員工資訊

下列範例會將員工資訊從 Managed 資料類型轉換成原生資料類型。 此轉換需要封送處理內容。

// 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++ 中封送處理的概觀