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