1 /***
2 *ptr.h
3 *
4 *           Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 *Purpose:     COM Wrapper for the Managed World
7 *
8 *           [Public]
9 *
10 ****/
11
12 #pragma once
13
14 #if !defined(_INC_MSCLR_COM_PTR)
15
16 #ifndef __cplusplus_cli
17 #error ERROR: msclr libraries are not compatible with /clr:oldSyntax
18 #endif
19
20 #include <vcclr.h>
21
22 #include <msclr\safebool.h>
23
24 namespace msclr
25 {
26
27 namespace _detail
28 {
29       // COM::ptr::operator->() returns a smart_com_ptr instead of
30       // a regular interface pointer so that a Release is done automatically
31       // when the temporary is destroyed
32
33       template<class _interface_type>
34       ref class smart_com_ptr
35       {
36              public:
37              smart_com_ptr(_interface_type * p)
38              {
39                     ptr= p;
40              }
41
42              smart_com_ptr(smart_com_ptr % ip)
43              {
44                     ptr = ip.ptr;
45                     ptr->AddRef();
46              }
47
48              _interface_type * operator ->()
49              {
50                     return ptr;
51              }
52
53              ~smart_com_ptr()
54              {
55                     ptr->Release();
56              }
57
58              private:
59              _interface_type * ptr;
60       };
61 } //namespace _detail
62
63
64 namespace com
65 {
66       template<class _interface_type>
67       ref class ptr
68       {
69              public:
70
71              ptr():obj_rcw(nullptr)
72              {
73              }
74
75              // Construct from interface pointer
76              ptr(_interface_type * p)
77              {
78                     obj_rcw = nullptr;
79                     assign(p);
80              }
81
82              // Attach to an interface pointer
83              void Attach(_interface_type * _right)
84              {
85                     if (valid()) 
86                     {
87                           throw gcnew System::InvalidOperationException("COM::ptr.Attach");
88                     }
89
90                     assign(_right);
91              }
92
93              // Assign an interface pointer
94              ptr<_interface_type> % operator=(_interface_type * _right)
95              {
96                     Attach(_right);
97                     return *this;
98              }
99
100              // All CreateInstance methods create an instance of a COM Object 
101              // by calling CoCreateInstance
102              void CreateInstance(System::String ^ prog_id, LPUNKNOWN pouter, DWORD cls_context)
103              {
104                     wchar_t * pwszprog_id = NULL;
105                     
106                     if(prog_id != nullptr)
107                     {
108                           pin_ptr<const __wchar_t> _pinned_ptr = PtrToStringChars( prog_id );
109                           pwszprog_id = _wcsdup(_pinned_ptr);
110                     }
111
112                     try 
113                     {
114                           CreateInstance(pwszprog_id, pouter, cls_context);
115                     }
116                     finally 
117                     {
118                           free(pwszprog_id);
119                     }
120              }
121
122              void CreateInstance(System::String ^ prog_id, LPUNKNOWN pouter)
123              {
124                     CreateInstance(prog_id, pouter, CLSCTX_ALL);
125              }
126
127              void CreateInstance(System::String ^ prog_id)
128              {
129                     CreateInstance(prog_id, NULL, CLSCTX_ALL);
130              }
131
132              void CreateInstance(const wchar_t* progid, LPUNKNOWN pouter, DWORD cls_context)
133              {
134                     CLSID clsid;
135                     System::Runtime::InteropServices::Marshal::ThrowExceptionForHR(
136                           CLSIDFromProgID(progid, &clsid));
137                     CreateInstance(clsid, pouter, cls_context);
138              }
139
140              void CreateInstance(const wchar_t * progid, LPUNKNOWN pouter)
141              {
142                     CreateInstance(progid, pouter, CLSCTX_ALL);
143              }
144
145              void CreateInstance(const wchar_t * progid)
146              {
147                     CreateInstance(progid, NULL, CLSCTX_ALL);
148              }
149
150              void CreateInstance(REFCLSID rclsid,LPUNKNOWN pouter,DWORD cls_context)
151              {
152                     if (valid()) 
153                     {
Lines 154 ... 163 are skipped.
164                     {
165                           assign(interface_ptr);
166                           interface_ptr->Release();
167                     }
168              }
169
170              void CreateInstance(REFCLSID rclsid,LPUNKNOWN pouter)
171              {
172                     CreateInstance(rclsid, pouter, CLSCTX_ALL);
173              }
174
175              void CreateInstance(REFCLSID rclsid)
176              {
177                     CreateInstance(rclsid, NULL, CLSCTX_ALL);
178              }
179
180              // Give up ownership of the interface pointer & return the
181              // interface pointer
182              _interface_type * Detach()
183              {
184                     if(valid())
185                     {
186                           _interface_type * interface_ptr = GetInterface();
187                           destroy();
188                           return interface_ptr;
189                     }
190
191                     return NULL;
192              }
193
194              // Give up ownership of the interface pointer
195              void Release()
196              {
197                     if(valid())
198                     {
199                           destroy();
200                     }
201              }
202              
203              // Operator ->() - to be used to call methods on the owned COM Object
204              // We return a smart_com_ptr instead of an interface pointer so that
205              // the reference is released automatically
206              _detail::smart_com_ptr<_interface_type> operator->()
207              {
208                     _detail::smart_com_ptr<_interface_type> interface_ptr(GetInterface());
209                     return interface_ptr;
210              }
211
212              // Return an interface pointer
213              _interface_type * GetInterface()
214              {
215                     if(!valid())
216                     {
217                           return NULL;
218                     }
219
220                     System::IntPtr iface_intptr = System::Runtime::InteropServices::Marshal::GetIUnknownForObject(obj_rcw);
221
222                     IUnknown * iunk = static_cast<IUnknown *>(static_cast<void*>(iface_intptr));
223
224                     _interface_type * interface_ptr;
225                     System::Runtime::InteropServices::Marshal::ThrowExceptionForHR(iunk->QueryInterface(__uuidof(_interface_type), (void **)&interface_ptr));
226
227                     iunk->Release();
228
229                     interface_ptr->AddRef();
230                     System::Runtime::InteropServices::Marshal::Release(iface_intptr);
231
232                     return interface_ptr;
233              }
234
235              // QueryInteface & fillup up the passed it COM::ptr with the result
236              template<class _other_type>
237              void QueryInterface(ptr<_other_type> % other)
238              {
239                     QueryInterface<_other_type>(__uuidof(_other_type), other);
240              }
241
242              // for use when com::ptr appears in a conditional
243              operator _detail_class::_safe_bool()
244              {
245                     return valid() ? _detail_class::_safe_true : _detail_class::_safe_false;
246              }
247
248              // for use when com::ptr appears in a conditional
249              bool operator!()
250              {
251                     return ! valid();
252              }
253
254              ~ptr()
255              {
256                     if(valid())
257                     {
258                           destroy();
259                     }
260              }
261
262              private:
263
264              void destroy()
265              {
266                     System::Runtime::InteropServices::Marshal::ReleaseComObject(obj_rcw);
267                     obj_rcw = nullptr;
268              }
269
270              bool valid()
271              {
272                     return (obj_rcw != nullptr);
273              }
274
275
276              void assign(_interface_type *p)
277              {
278                     if(p)
279                     {
280                           obj_rcw = System::Runtime::InteropServices::Marshal::GetUniqueObjectForIUnknown(System::IntPtr(p));
281                     }
282              }
283
284              template<class _other_type>
285              void QueryInterface(REFIID riid, ptr<_other_type> % other)
286              {
287                     _detail::smart_com_ptr<_interface_type> interface_ptr(GetInterface());
288                     _other_type * other_ptr;
289
290                     System::Runtime::InteropServices::Marshal::ThrowExceptionForHR(interface_ptr->QueryInterface(riid,(void **)&other_ptr));
291                     other.Attach(other_ptr);
292
293                     other_ptr->Release();
294              }
295
296              Object ^obj_rcw;
297       };
298 } // namespace com
299
300 } // namespace msclr
301
302 #define _INC_MSCLR_COM_PTR
303 #endif // _INC_MSCLR_COM_PTR
304