2012-01-11 2 views
0

현재 Visual Studio 2010을 사용 중입니다. C++ 클래스의 래퍼를 작성한 것은 이번이 처음입니다. C++의 클래스는 다음과 같습니다 : I 보이는 헤더 파일을 생성 C#의 String []을 C++의 Char * []로 변환

bool exampleCode(char* arrayOfStrings[], int number, char* regularString) 

같은 :

bool exampleCode(array<String^>^ arrayOfStrings, int number, String^ regularString) 

과 같은 .cpp 파일 클래스는 같습니다 내가 알아 낸

bool exampleCode(array<String^>^ arrayOfStrings, int number, System::String^ regularString) 

regularString 데이터를 마샬링하는 방법은 있지만 String 배열을 char*[]으로 변환하는 방법을 잘 모르겠습니다. 어떤 도움을 주시면 감사하겠습니다.

#include <algorithm> 
#include <memory> 
#include <vector> 

using System::IntPtr; 
using System::String; 
using System::Runtime::InteropServices::Marshal; 

bool exampleCodeManaged(array<String^>^ arrayOfStrings, String^ regularString) 
{ 
    auto deleter = [](char* p) { Marshal::FreeHGlobal(IntPtr(p)); }; 
    typedef std::unique_ptr<char[], decltype(deleter)> cstr_t; 
    auto make_cstr = [&deleter](String^ s) 
    { 
     return cstr_t(
      static_cast<char*>(Marshal::StringToHGlobalAnsi(s).ToPointer()), 
      deleter 
     ); 
    }; 

    std::vector<cstr_t> cstrs; 
    cstrs.reserve(arrayOfStrings->Length); 
    for each (String^ s in arrayOfStrings) 
     cstrs.push_back(make_cstr(s)); 

    std::vector<char*> ptrs; 
    ptrs.reserve(cstrs.size()); 
    std::for_each(
     cstrs.begin(), 
     cstrs.end(), 
     [&ptrs](cstr_t& cstr) { ptrs.push_back(cstr.get()); } 
    ); 

    auto reg_cstr = make_cstr(regularString); 

    return exampleCode(ptrs.data(), arrayOfStrings->Length, reg_cstr.get()); 
} 

(이 배열의에서 추론 할 수 number가 관리 기능에 전달 될 필요가 없다는 것을 참고 : 다음

+0

네이티브 함수는 전달 된 메모리를 정리합니까? 아니면 호출자에게 남겨 둡니까? – ildjarn

+0

나는 네이티브 함수가 통과 한 메모리를 정리한다고 믿지만, C++/CLI 프로그래밍이 처음 인 이래로 나는 100 %가 아니다. – avtoader

+0

좋아, 그럼 다음 질문은 _how_ 네이티브 함수는 메모리를 정리합니까? '자유'? 'delete []'? 'CoTaskMemFree'? 'LocalFree'? 'GlobalFree'? – ildjarn

답변

0

할당량을 줄이고 지역을 개선하여 @ ildjarn의 대답을 향상시키는 데 사용할 수있는 재사용 가능한 버전입니다 (데모 포함). 또한 UTF-8과 같은 인코딩 선택을 사용합니다.

#include <iostream> 
#include <vector> 

#include <windows.h> 
#include <vcclr.h> 

using namespace System; 

template <typename T> 
struct advanced_marshal; 

template <> 
struct advanced_marshal<char*[]> 
{ 
    char** get() { return &m_strings[0]; } 

    advanced_marshal(array<System::String^>^ strings, UINT code_page = CP_ACP) : m_strings(strings->Length) 
    { 
     if (int count = strings->Length) { 
      int i; 
      size_t total_length_estimate = count; // one NUL byte per string 
      for(i = 0; i < count; ++i) { 
       total_length_estimate += strings[i]->Length * 4; 
      } 

      m_buffer.resize(total_length_estimate); 
      auto tail = m_buffer.begin(), end = m_buffer.end(); 
      i = 0; 
      do { 
       m_strings[i] = &*tail; 
       pin_ptr<const WCHAR> pwsz = PtrToStringChars(strings[i]); 
       tail += 1 + WideCharToMultiByte(code_page, 0, pwsz, strings[i]->Length, &*tail , end - tail, nullptr, nullptr); 

       ++i; 
      } while (i < count); 
     } 
    } 

    advanced_marshal(advanced_marshal<char*[]>&& other) { m_buffer.swap(other.m_buffer); m_strings.swap(other.m_strings); } 

private: 
    advanced_marshal(const advanced_marshal<char*[]>&); // = delete 
    void operator=(const advanced_marshal<char*[]>&); // = delete 

    std::vector<char> m_buffer; 
    std::vector<char*> m_strings; 
}; 

void print_some_strings(char* strings[], int num) 
{ 
    for(int i = 0; i < num; ++i) 
     std::cout << strings[i] << "\n"; 

    std::cin.get(); 
} 

int main(array<System::String ^> ^args) 
{ 
    print_some_strings(advanced_marshal<char*[]>(args).get(), args->Length); 
    return 0; 
} 
1

이상적으로 효율적인 (최소 복사) 및 예외 안전 길이) 대신 Marshal 클래스의 std::string를 사용하는 벤 보이트의 제안을 통합 또는

:.

,529,
+0

'StringToHGlobalAnsi'가 "이상적으로 효율적"이라고 확신하지 못합니다. 그것은 작동하지만, 원칙적으로 사용하기를 거절합니다. 그 이유는 그 이름이 오도 된 것이기 때문입니다. 실제로'HGLOBAL '을 생성하지 않으며 결과를'GlobalFree'로 전달할 수 없습니다 (이것은' HGLOBAL's). –

+0

@Ben : 확실하지는 않지만 쉬운 대안은'marshal_as '또는'marshal_as '를 사용하는 것입니다.이 경우'const_cast <> '가 사용되지 않는 한 여분의 데이터 사본이 필요합니다. 나는'const_cast <>'를 피하려고한다. – ildjarn

+0

'std :: string'은 완벽하게 사용할 수 있습니다. 그냥'& s [0]'을 사용하십시오. 하지만 나는''Encoding :: GetBytes' (http://msdn.microsoft.com/en-us/library/6s1x2atd)를 호출하여 하나의 벡터 을 선호한다고 생각합니다.aspx) (모든 문자열을 엔드 투 엔드로 패킹). 하나의 할당, 자동 무료, 사용자 정의 deleter가 없습니다. –