STLdoc
STLdocumentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
marshal.h
Go to the documentation of this file.
1 /***
2 *marshal.h
3 *
4 * Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 *Purpose: Marshalling classes
7 *
8 * [Public]
9 *
10 ****/
11 
12 #pragma once
13 
14 #ifndef _INC_MSCLR_MARSHAL
15 #define _INC_MSCLR_MARSHAL
16 
17 // #using is not used in the Windows build.
18 #if !defined _CRT_WINDOWS && !defined BUILD_WINDOWS
19  #using <system.dll>
20 #endif
21 
22 #include <sal.h>
23 #include <windows.h>
24 #include <vcclr.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <memory>
29 
30 #pragma comment(lib, "comsupp.lib")
31 #pragma comment(lib, "oleaut32.lib")
32 
33 #pragma warning(push)
34 #pragma warning(error : 4996)
35 
36 namespace msclr{
37  namespace interop{
38 
39 namespace details
40 {
41 #define _EXCEPTION_GREATER_THAN_INT_MAX "Size of string exceeds INT_MAX."
42 #define _EXCEPTION_NULLPTR "NULLPTR is not supported for this conversion."
43 #define _EXCEPTION_MB2WC "Conversion from MultiByte to WideChar failed. Please check the content of the string and/or locale settings."
44 #define _EXCEPTION_WC2MB "Conversion from WideChar to MultiByte failed. Please check the content of the string and/or locale settings."
45 
46  // helper class to allocate/deallocate a buffer with new[]/delete[]
47  template <class T>
49  {
50  public:
51  explicit char_buffer(size_t _size)
52  {
53  _ptr = new T[_size];
54  }
55 
57  {
58  delete [] _ptr;
59  }
60 
61  T *get() const
62  {
63  return _ptr;
64  }
65 
66  T* release()
67  {
68  T *_ret_value = _ptr;
69  _ptr = NULL;
70  return _ret_value;
71  }
72 
73  private:
74  // no copy constructor nor operator=
75  char_buffer(const char_buffer&);
77 
78  T *_ptr;
79  };
80 
81  inline _Check_return_ size_t GetAnsiStringSize(System::String^ _str)
82  {
83  size_t _size = 0;
84  cli::pin_ptr<const wchar_t> _pinned_ptr = PtrToStringChars(_str);
85 
86  _size = ::WideCharToMultiByte(CP_THREAD_ACP, WC_NO_BEST_FIT_CHARS, _pinned_ptr, _str->Length, NULL, 0, NULL,NULL);
87  if (_size == 0 && _str->Length != 0)
88  {
89  throw gcnew System::ArgumentException(_EXCEPTION_WC2MB);
90  }
91  // adding 1 for terminating nul
92  _size+=1;
93  return _size;
94  }
95 
96  inline void WriteAnsiString(_Out_writes_all_(_size) _Post_z_ char* _buf, size_t _size, System::String^ _str)
97  {
98  cli::pin_ptr<const wchar_t> _pinned_ptr = PtrToStringChars(_str);
99 
100  //checking for overflow
101  if (_size > INT_MAX)
102  {
103  // this should never happen if _size was returned by GetAnsiStringSize()
104  throw gcnew System::ArgumentOutOfRangeException(_EXCEPTION_GREATER_THAN_INT_MAX);
105  }
106  size_t _written = ::WideCharToMultiByte(CP_THREAD_ACP, WC_NO_BEST_FIT_CHARS, _pinned_ptr, _str->Length, _buf, static_cast<int>(_size) ,NULL,NULL);
107  if( _written >= _size ||
108  (_written == 0 && _size != 1)) // allowing empty string
109  {
110  throw gcnew System::ArgumentException(_EXCEPTION_WC2MB);
111  }
112  _buf[_written] = '\0';
113  }
114 
115  inline _Check_return_ size_t GetUnicodeStringSize(_In_reads_z_(_count+1) const char* _str, size_t _count)
116  {
117  size_t _size = 0;
118  if (_count > INT_MAX)
119  {
120  throw gcnew System::ArgumentOutOfRangeException(_EXCEPTION_GREATER_THAN_INT_MAX);
121  }
122  _size = ::MultiByteToWideChar(CP_THREAD_ACP, 0, _str, static_cast<int>(_count), NULL, 0);
123 
124  if (_size == 0 && _count != 0)
125  {
126  throw gcnew System::ArgumentException(_EXCEPTION_MB2WC);
127  }
128  //adding 1 for terminating nul
129  _size+=1;
130  return _size;
131  }
132 
133  inline void WriteUnicodeString(_Out_writes_all_(_size) _Post_z_ wchar_t* _dest, size_t _size, _In_reads_bytes_(_count)const char* _src, size_t _count)
134  {
135  //checking for overflow
136  if (_size > INT_MAX || _count > INT_MAX)
137  {
138  throw gcnew System::ArgumentOutOfRangeException(_EXCEPTION_GREATER_THAN_INT_MAX);
139  }
140 
141  size_t _written = ::MultiByteToWideChar(CP_THREAD_ACP, 0, _src, static_cast<int>(_count), _dest, static_cast<int>(_size));
142  if( _written >= _size ||
143  (_written == 0 && _size != 1)) // allowing empty string
144  {
145  throw gcnew System::ArgumentException(_EXCEPTION_MB2WC);
146  }
147  _dest[_written] = L'\0';
148  }
149 
150  inline System::String^ InternalAnsiToStringHelper(_In_reads_z_(_count+1)const char* _src, size_t _count)
151  {
152  size_t _size = details::GetUnicodeStringSize(_src, _count);
153  if (_size > INT_MAX || _size <=0 )
154  {
155  throw gcnew System::ArgumentOutOfRangeException(_EXCEPTION_GREATER_THAN_INT_MAX);
156  }
157  details::char_buffer<wchar_t> _wchar_buf(_size);
158  if (_wchar_buf.get() == NULL)
159  {
160  throw gcnew System::InsufficientMemoryException();
161  }
162 
163  details::WriteUnicodeString(_wchar_buf.get(), _size, _src, _count);
164 
165  return gcnew System::String(_wchar_buf.get(), 0, static_cast<int>(_size)-1);
166  }
167 
168  inline System::String^ InternalUnicodeToStringHelper(_In_reads_z_(_count+1)const wchar_t* _src, size_t _count)
169  {
170  if (_count > INT_MAX)
171  {
172  throw gcnew System::ArgumentOutOfRangeException(_EXCEPTION_GREATER_THAN_INT_MAX);
173  }
174 
175  return gcnew System::String(_src, 0 ,static_cast<int>(_count));
176  }
177 } // namespace details
178 
179 //--------------------------------------------------------------------------------
180 // Forward declarations
181 //--------------------------------------------------------------------------------
182 
183 ref class context_node_base;
184 
185 template<class _To_Type, class _From_Type>
186 ref class context_node;
187 
188 template <class _To_Type, class _From_Type,
191 
192 template<class _To_Type>
193 inline _To_Type marshal_as(_In_z_ const char _from_object[])
194 {
195  const char* _ptr = _from_object;
196  return marshal_as<_To_Type, const char *>(_ptr);
197 }
198 
199 template<class _To_Type>
200 inline _To_Type marshal_as(_In_z_ const wchar_t _from_object[])
201 {
202  const wchar_t* _ptr = _from_object;
203  return marshal_as<_To_Type, const wchar_t*>(_ptr);
204 }
205 
206 ref class marshal_context;
207 
208 template <class _To_Type, class _From_Type>
209 inline _To_Type marshal_as(const _From_Type&);
210 
211 //--------------------------------------------------------------------------------
212 // Context-free conversion generic templates
213 //--------------------------------------------------------------------------------
214 
215 template <class _To_Type, class _From_Type>
216 class error_reporting_helper<_To_Type, _From_Type, /* _Needs_Context */ false>
217 {
218  public:
219  __declspec(deprecated("This conversion is not supported by the library or the header file needed for this conversion is not included. Please refer to the documentation on 'How to: Extend the Marshaling Library' for adding your own marshaling method."))
220  static _To_Type marshal_as(const _From_Type& _from_object)
221  {
222  return _This_conversion_is_not_supported;
223  }
224 };
225 
226 template <class _To_Type, class _From_Type>
227 class error_reporting_helper<_To_Type, _From_Type, /* _Needs_Context */ true>
228 {
229  public:
230  __declspec(deprecated("This conversion requires a marshal_context. Please use a marshal_context for this conversion."))
231  static _To_Type marshal_as(const _From_Type& _from_object)
232  {
233  return _This_conversion_requires_a_context;
234  }
235 };
236 
237 template <class _To_Type, class _From_Type>
238 inline _To_Type marshal_as(const _From_Type& _from_object)
239 {
241 }
242 
243 //--------------------------------------------------------------------------------
244 // Context conversion generic templates
245 //--------------------------------------------------------------------------------
246 
248 {
249  public:
250  static const bool _Needs_Context= true;
251 };
252 
253 template<class _To_Type, class _From_Type>
254 ref class context_node : public context_node_base
255 {
256  public:
257  static const bool _Needs_Context= false;
258 };
259 
261 {
262  internal:
263  //The list of objects that need to be cleaned up. Basically all those that have a destructor
264  System::Collections::Generic::LinkedList <Object^> _clean_up_list;
265 
266  template<class _To_Type, class _From_Type, bool _Needs_Context>
268 
269  template<class _To_Type, class _From_Type>
270  ref class internal_marshaler<_To_Type, _From_Type, true>
271  {
272  public:
273  // This is a supported context conversation.
274  // Convert and added it to the list of cleanup
275  static inline _To_Type marshal_as(const _From_Type& _from, System::Collections::Generic::LinkedList<Object^>% _clean_up_list)
276  {
278 
279  _To_Type _to_object;
280  //Create a context node and assign marshalling result to the 'to' variable
281  _cn^ _obj = gcnew _cn(_to_object, _from);
282  _clean_up_list.AddLast(_obj);
283  return _to_object;
284  };
285  };
286 
287  template<class _To_Type, class _From_Type>
288  ref class internal_marshaler<_To_Type, _From_Type, false>
289  {
290  public:
291  // This is not a supported context conversation.
292  // This maybe a context-free conversation or a unsupported converstaion.
293  // Both cases will be handed by the Marshal_as object.
294  static inline _To_Type marshal_as(const _From_Type& _from, System::Collections::Generic::LinkedList<Object^>% _clean_up_list)
295  {
296  (_clean_up_list); // not using this variable intentionally
297  return ::msclr::interop::marshal_as<_To_Type, _From_Type>(_from);
298  };
299  };
300 
301  public:
302  template<class _To_Type, class _From_Type>
303  inline _To_Type marshal_as(const _From_Type& _from)
304  {
307  }
308 
309  template<class _To_Type, class _From_Type>
310  inline _To_Type marshal_as(_From_Type^ _from)
311  {
314  }
315 
316  // special case marshal_as() that doesn't fit the usual marshal_as<To,From>() templates
317  template<class _To_Type>
318  inline _To_Type marshal_as(_In_z_ const char _from[])
319  {
322  }
323 
324  template<class _To_Type>
325  inline _To_Type marshal_as(_In_z_ const wchar_t _from[])
326  {
329  }
330 
331  template<class _To_Type>
332  inline _To_Type marshal_as(System::IntPtr _from)
333  {
334  return ::msclr::interop::marshal_as<_To_Type>(_from);
335  }
336 
338  {};
339 
341  {
342  for each(Object^ _obj in _clean_up_list)
343  delete _obj;
344  }
345 };
346 
347 //--------------------------------------------------------------------------------
348 // Context-free conversions templates specialization for basic types
349 //--------------------------------------------------------------------------------
350 
351 template <>
352 inline System::String^ marshal_as(_In_z_ const char * const & _from_object)
353 {
354  if (!_from_object)
355  {
356  return nullptr;
357  }
358  return details::InternalAnsiToStringHelper(_from_object, strlen(_from_object));
359 }
360 
361 template<>
362 inline System::String^ marshal_as(_In_z_ char * const & _from_object)
363 {
364  return marshal_as<System::String^, const char *>(_from_object);
365 }
366 
367 template <>
368 inline System::String^ marshal_as(_In_z_ const wchar_t* const & _from_object)
369 {
370  if (_from_object == NULL)
371  {
372  return nullptr;
373  }
374  return gcnew System::String(_from_object);
375 }
376 
377 // Note: BSTR and wchar_t* are actually typedef alias. Therefore, we can not define the
378 // conversion BSTR -> System::String^. BSTR actually will use this function.
379 template <>
380 inline System::String^ marshal_as(_In_z_ wchar_t* const& _from_object)
381 {
382  return marshal_as<System::String^, const wchar_t *>(_from_object);
383 }
384 
385 //--------------------------------------------------------------------------------
386 // Context conversion templates specialization for basic types
387 //--------------------------------------------------------------------------------
388 
389 template<>
390 ref class context_node<const char*, System::String^> :
391  public context_node_base
392 {
393  private:
394  char* _ptr;
395  public:
396  context_node(_Outref_result_maybenull_ _Post_z_ const char*& _to_object, System::String^ _from_object)
397  {
398  _ptr = NULL;
399  if (_from_object == nullptr)
400  {
401  _to_object =nullptr;
402  return;
403  }
404 
405  size_t _size = details::GetAnsiStringSize(_from_object);
406 
407  details::char_buffer<char> _char_buf(_size);
408  if (_char_buf.get() == NULL)
409  {
410  throw gcnew System::InsufficientMemoryException();
411  }
412 
413  details::WriteAnsiString(_char_buf.get(), _size, _from_object);
414 
415  _ptr = _char_buf.release();
416  _to_object = _ptr;
417  }
418 
420  {
421  this->!context_node();
422  }
423 
424  protected:
426  {
427  delete [] _ptr;
428  }
429 };
430 
431 
432 template<>
433 ref class context_node<const wchar_t*, System::String^> :
434  public context_node_base
435 {
436  private:
437  System::IntPtr _ip;
438  public:
439  context_node(_Outref_ _Post_z_ const wchar_t*& _to_object, System::String^ _from_object)
440  {
441  _ip = System::Runtime::InteropServices::Marshal::StringToHGlobalUni (_from_object);
442  _to_object = static_cast<wchar_t*>(_ip.ToPointer());
443  }
444 
446  {
447  this->!context_node();
448  }
449 
450  protected:
452  {
453  if(_ip != System::IntPtr::Zero)
454  System::Runtime::InteropServices::Marshal::FreeHGlobal(_ip);
455  }
456 };
457 
458  } //namespace interop
459 } //namespace msclr
460 
461 #pragma warning(pop) // error:4996
462 #endif /* _INC_MSCLR_MARSHAL */
char_buffer & operator=(const char_buffer &)
System::String marshal_as(_In_z_ wchar_t *const &_from_object)
Definition: marshal.h:380
T * release()
Definition: marshal.h:66
#define _EXCEPTION_GREATER_THAN_INT_MAX
Definition: marshal.h:41
context_node(_Outref_ _Post_z_ const wchar_t *&_to_object, System::String^_from_object)
Definition: marshal.h:439
#define _Out_writes_all_(size)
Definition: sal.h:354
_Check_return_ size_t GetUnicodeStringSize(_In_reads_z_(_count+1) const char *_str, size_t _count)
Definition: marshal.h:115
Definition: gcroot.h:43
_Check_return_ size_t GetAnsiStringSize(System::String^_str)
Definition: marshal.h:81
#define _In_reads_bytes_(size)
Definition: sal.h:318
_To_Type marshal_as(_In_z_ const char _from[])
Definition: marshal.h:318
#define _EXCEPTION_WC2MB
Definition: marshal.h:44
static _To_Type marshal_as(const _From_Type &_from, System::Collections::Generic::LinkedList< Object^>%_clean_up_list)
Definition: marshal.h:294
System::String InternalAnsiToStringHelper(_In_reads_z_(_count+1) const char *_src, size_t _count)
Definition: marshal.h:150
_Check_return_ size_t __cdecl strlen(_In_z_ char const *_Str)
__const_Char_ptr PtrToStringChars(__const_String_handle s)
Definition: vcclr.h:40
Definition: marshal.h:48
marshal_context()
Definition: marshal.h:337
#define _Post_z_
Definition: sal.h:688
Definition: marshal.h:247
#define _In_reads_z_(size)
Definition: sal.h:320
#define _Check_return_
Definition: sal.h:554
#define _In_z_
Definition: sal.h:310
static _To_Type marshal_as(const _From_Type &_from, System::Collections::Generic::LinkedList< Object^>%_clean_up_list)
Definition: marshal.h:275
T * _ptr
Definition: marshal.h:78
_To_Type marshal_as(_From_Type^_from)
Definition: marshal.h:310
T * get() const
Definition: marshal.h:61
unsigned char
Definition: mbstring.h:107
_To_Type marshal_as(_In_z_ const char _from_object[])
Definition: marshal.h:193
#define false
Definition: stdbool.h:16
void WriteUnicodeString(_Out_writes_all_(_size) _Post_z_ wchar_t *_dest, size_t _size, _In_reads_bytes_(_count) const char *_src, size_t _count)
Definition: marshal.h:133
void WriteAnsiString(_Out_writes_all_(_size) _Post_z_ char *_buf, size_t _size, System::String^_str)
Definition: marshal.h:96
_To_Type marshal_as(_In_z_ const wchar_t _from[])
Definition: marshal.h:325
Definition: marshal.h:260
#define _EXCEPTION_MB2WC
Definition: marshal.h:43
__declspec(deprecated("This conversion is not supported by the library or the header file needed for this conversion is not included. Please refer to the documentation on 'How to: Extend the Marshaling Library' for adding your own marshaling method.")) static _To_Type marshal_as(const _From_Type &_from_object)
Definition: marshal.h:219
#define _Outref_
Definition: sal.h:487
_To_Type marshal_as(System::IntPtr _from)
Definition: marshal.h:332
Definition: marshal.h:186
unsigned short wchar_t
Definition: sourceannotations.h:25
~marshal_context()
Definition: marshal.h:340
__declspec(deprecated("This conversion requires a marshal_context. Please use a marshal_context for this conversion.")) static _To_Type marshal_as(const _From_Type &_from_object)
Definition: marshal.h:230
char_buffer(size_t _size)
Definition: marshal.h:51
~char_buffer()
Definition: marshal.h:56
_To_Type marshal_as(const _From_Type &_from)
Definition: marshal.h:303
#define INT_MAX
Definition: limits.h:35
#define _Outref_result_maybenull_
Definition: sal.h:488
#define true
Definition: stdbool.h:17
context_node(_Outref_result_maybenull_ _Post_z_ const char *&_to_object, System::String^_from_object)
Definition: marshal.h:396
#define NULL
Definition: corecrt.h:158
System::String InternalUnicodeToStringHelper(_In_reads_z_(_count+1) const wchar_t *_src, size_t _count)
Definition: marshal.h:168