PageRenderTime 5ms CodeModel.GetById 2ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 0ms

/doc/notes_on_COM_gu.cpp

http://r2clr.codeplex.com
C++ | 775 lines | 537 code | 165 blank | 73 comment | 62 complexity | cf17dc545a22f73c1b3f554ca28ecad4 MD5 | raw file
  1#define _WIN32_DCOM
  2#include <stdio.h>
  3#include <wtypes.h>
  4
  5#import "path\\mscorlib.tlb" no_namespace named_guids raw_interfaces_only
  6
  7HRESULT InvokeStaticMember(BSTR typeName, BSTR memberName,
  8  BindingFlags memberType, SAFEARRAY* parameters, VARIANT* retVal)
  9{
 10  HRESULT hresult;
 11  IUnknown* pUnk = NULL;
 12  _Object* pObj = NULL;
 13  _Type* pType = NULL;
 14  _Type* pTypeOfType = NULL;
 15  _Type* pDesiredType = NULL;
 16  VARIANT typeNameParam;
 17  VARIANT getTypeRetVal;
 18  VARIANT nullObject;
 19  SAFEARRAY* psa;
 20  LONG index;
 21  BSTR getTypeName = SysAllocString(L"GetType");
 22
 23  VariantInit(&typeNameParam);
 24  VariantInit(&getTypeRetVal);
 25  VariantInit(&nullObject);
 26
 27  // Instantiate a dummy class just so we can get a System.Type instance
 28  hresult = CoCreateInstance(CLSID_Object, NULL,
 29    CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&pUnk);
 30  if (FAILED(hresult)) goto cleanup;
 31
 32  // Get the _Object interface so we can call GetType
 33  hresult = pUnk->QueryInterface(IID__Object, (void**)&pObj);
 34  if (FAILED(hresult)) goto cleanup;
 35
 36  // Call _Object.GetType
 37  hresult = pObj->GetType(&pType);
 38  if (FAILED(hresult)) goto cleanup;
 39
 40  // Call the instance Type.GetType method (inherited from Object)
 41  // in order to get the type for System.Type rather than the type for
 42  // System.Object
 43  hresult = pType->GetType(&pTypeOfType);
 44  if (FAILED(hresult)) goto cleanup;
 45
 46  // Prepare a 1-element array containing the passed-in type name
 47  // to pass to the static Type.GetType method
 48  psa = SafeArrayCreateVector(VT_VARIANT, 0, 1);
 49  typeNameParam.vt = VT_BSTR;
 50  typeNameParam.bstrVal = typeName;
 51  index = 0;
 52  hresult = SafeArrayPutElement(psa, &index, &typeNameParam);
 53  if (FAILED(hresult)) goto cleanup;
 54
 55  // Invoke the static Type.GetType method using reflection on the
 56  // type for System.Type in order to get the desired type
 57  nullObject.vt = VT_EMPTY;
 58  hresult = pTypeOfType->InvokeMember_3(getTypeName,
 59    (BindingFlags)(BindingFlags_InvokeMethod | BindingFlags_Public |
 60    BindingFlags_Static | BindingFlags_FlattenHierarchy), NULL,
 61    nullObject, psa, &getTypeRetVal);
 62  if (FAILED(hresult)) goto cleanup;
 63
 64  // Get the _Type interface so we can call the static InvokeMember
 65  // method on the desired type to invoke the desired static member
 66  hresult = getTypeRetVal.punkVal->QueryInterface(IID__Type,
 67    (void**)&pDesiredType);
 68  if (FAILED(hresult)) goto cleanup;
 69
 70  // Invoke the desired static member
 71  pDesiredType->InvokeMember_3(memberName, (BindingFlags)(memberType |
 72    BindingFlags_Public | BindingFlags_Static |
 73    BindingFlags_FlattenHierarchy), NULL, nullObject, parameters,
 74    retVal);
 75  if (FAILED(hresult)) goto cleanup;
 76
 77cleanup:
 78  if (pUnk) pUnk->Release();
 79  if (pObj) pObj->Release();
 80  if (pType) pType->Release();
 81  if (pTypeOfType) pTypeOfType->Release();
 82  if (pDesiredType) pDesiredType->Release();
 83  if (getTypeName) SysFreeString(getTypeName);
 84  SafeArrayDestroy(psa);
 85  VariantClear(&typeNameParam);
 86  VariantClear(&getTypeRetVal);
 87  VariantClear(&nullObject);
 88
 89  return hresult;
 90};
 91
 92int main(int argc, char* argv[])
 93{
 94  HRESULT hresult;
 95  VARIANT retVal;
 96  _AppDomain* pDomain = NULL;
 97  BSTR typeName1, typeName2, memberName1, memberName2, directory;
 98
 99  // Initialize COM
100  hresult = CoInitializeEx(NULL, COINIT_MULTITHREADED);
101  if (FAILED(hresult))
102  {
103    printf("ERROR: Cannot initialize COM: 0x%x\n", hresult);
104    return -1;
105  }
106
107  VariantInit(&retVal);
108
109  // ------------------------------------------
110  // Example 1: Calling System.Console.ReadLine
111  // ------------------------------------------
112
113  typeName1 = SysAllocString(L"System.Console");
114  memberName1 = SysAllocString(L"ReadLine");
115
116  printf("Type in something followed by Enter: ");
117
118  hresult = InvokeStaticMember(typeName1, memberName1,
119    BindingFlags_InvokeMethod, NULL, &retVal);
120  if (FAILED(hresult))
121  {
122    printf("ERROR: Invocation failed: 0x%x\n", hresult);
123    return -1;
124  }
125
126  wprintf(L"You typed: '%s'\n", retVal.bstrVal);
127
128  // --------------------------------------------------
129  // Example 2: Calling System.AppDomain.CurrentDomain
130  // --------------------------------------------------
131
132  typeName2 = SysAllocString(L"System.AppDomain");
133  memberName2 = SysAllocString(L"CurrentDomain");
134
135  hresult = InvokeStaticMember(typeName2, memberName2,
136    BindingFlags_GetProperty, NULL, &retVal);
137  if (FAILED(hresult))
138  {
139    printf("ERROR: Invocation failed: 0x%x\n", hresult);
140    return -1;
141  }
142
143  // Get the _AppDomain interface from the returned IUnknown pointer
144  hresult = retVal.punkVal->QueryInterface(IID__AppDomain,
145    (void**)&pDomain);
146  if (FAILED(hresult))
147  {
148    printf("ERROR: Could not get _AppDomain interface pointer: 0x%x\n",
149      hresult);
150    return -1;
151  }
152
153  // Call the BaseDirectory property on the _AppDomain instance
154  pDomain->get_BaseDirectory(&directory);
155  wprintf(L"Base directory of the current domain: '%s'\n", directory);
156
157  CoUninitialize();
158  return 0;
159};
160
161
162
163#define _WIN32_DCOM
164#include <stdio.h>
165#include <wtypes.h>
166
167// Reference the two necessary type libraries
168#import "path\\mscoree.tlb" no_namespace named_guids raw_interfaces_only
169#import "path\\mscorlib.tlb" no_namespace named_guids raw_interfaces_only
170
171IUnknown* pUnk = NULL;
172IUnknown* pUnk2 = NULL;
173ICorRuntimeHost* pHost = NULL;
174_AppDomain* pDomain = NULL;
175_ObjectHandle* pHandle = NULL;
176IDispatch* pDisp = NULL;
177
178BSTR asmName;
179BSTR typeName;
180VARIANT arrayList;
181VARIANT param;
182
183void Cleanup()
184{
185  pHost->Stop();
186  if (pUnk) pUnk->Release();
187  if (pUnk2) pUnk2->Release();
188  if (pDisp) pDisp->Release();
189  if (pHandle) pHandle->Release();
190  if (pDomain) pDomain->Release();
191  if (pHost) pHost->Release();
192  if (asmName) SysFreeString(asmName);
193  if (typeName) SysFreeString(typeName);
194  VariantClear(&param);
195  VariantClear(&arrayList);
196  CoUninitialize();
197};
198
199int main(int argc, char* argv[])
200{
201  HRESULT hresult;
202
203  // Initialize COM
204  hresult = CoInitializeEx(NULL, COINIT_MULTITHREADED);
205  if (FAILED(hresult))
206  {
207    printf("ERROR: Cannot initialize COM: 0x%x\n", hresult);
208    Cleanup();
209    return -1;
210  }
211
212  // Initialize the CLR
213  hresult = CoCreateInstance(CLSID_CorRuntimeHost, NULL,
214    CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&pUnk);
215  if (FAILED(hresult))
216  {
217    printf("ERROR: Cannot create host object: 0x%x\n", hresult);
218    Cleanup();
219    return -1;
220  }
221
222  // Get the ICorRuntimeHost interface
223  hresult = pUnk->QueryInterface(IID_ICorRuntimeHost, (void**)&pHost);
224  if (FAILED(hresult))
225  {
226    printf("ERROR: Cannot get ICorRuntimeHost interface pointer: 0x%x\n",
227      hresult);
228    Cleanup();
229    return -1;
230  }
231
232  // Start the host
233  hresult = pHost->Start();
234  if (FAILED(hresult))
235  {
236    printf("ERROR: Cannot start host: 0x%x\n", hresult);
237    Cleanup();
238    return -1;
239  }
240
241  // Get the default domain
242  hresult = pHost->GetDefaultDomain(&pUnk2);
243  if (FAILED(hresult))
244  {
245    printf("ERROR: Cannot get default domain: 0x%x\n", hresult);
246    Cleanup();
247    return -1;
248  }
249
250  // Get the _AppDomain interface
251  hresult = pUnk2->QueryInterface(IID__AppDomain, (void**)&pDomain);
252  if (FAILED(hresult))
253  {
254    printf("ERROR: Cannot get _AppDomain interface pointer: 0x%x\n",
255      hresult);
256    Cleanup();
257    return -1;
258  }
259
260  // Strings for CreateInstance_3
261  asmName = SysAllocString(L"mscorlib");
262  typeName = SysAllocString(L"System.Collections.ArrayList");
263
264  // Create a 1D array with one integer element
265  SAFEARRAY* psa = SafeArrayCreateVector(VT_VARIANT, 0, 1);
266  VariantInit(&param);
267  param.vt = VT_I4;
268  param.lVal = 128;
269  LONG index = 0;
270
271  hresult = SafeArrayPutElement(psa, &index, &param);
272  if (FAILED(hresult))
273  {
274    printf("ERROR: Cannot set SAFEARRAY element: 0x%x\n", hresult);
275    Cleanup();
276    return -1;
277  }
278
279  // Create an instance of ArrayList using a parameterized constructor
280  hresult = pDomain->CreateInstance_3(asmName, typeName, VARIANT_TRUE,
281    BindingFlags_Default, NULL, psa, NULL, NULL, NULL, &pHandle);
282  if (FAILED(hresult))
283  {
284    printf("ERROR: Cannot create instance: 0x%x\n", hresult);
285    Cleanup();
286    return -1;
287  }
288
289  // Unwrap the ArrayList instance inside the ObjectHandle
290  VariantInit(&arrayList);
291  hresult = pHandle->Unwrap(&arrayList);
292  if (FAILED(hresult))
293  {
294    printf("ERROR: Could not unwrap object handle: 0x%x\n", hresult);
295    Cleanup();
296    return -1;
297  }
298
299  // Get the IDispatch interface so we can call the Capacity property
300  hresult = arrayList.punkVal->QueryInterface(IID_IDispatch,
301    (void**)&pDisp);
302  if (FAILED(hresult))
303  {
304    printf("ERROR: Could not get IDispatch interface pointer: 0x%x\n",
305      hresult);
306    Cleanup();
307    return -1;
308  }
309
310  // Get the DISPID for the Capacity property
311  OLECHAR* name = L"Capacity";
312  DISPID dispid;
313  hresult = pDisp->GetIDsOfNames(IID_NULL, &name, 1, GetUserDefaultLCID(),
314    &dispid);
315  if (FAILED(hresult))
316  {
317    printf("ERROR: GetIDsOfNames failed: 0x%x\n", hresult);
318    Cleanup();
319    return -1;
320  }
321
322  // Invoke the Capacity property
323  VARIANT result;
324  VariantInit(&result);
325  DISPPARAMS params = { NULL, NULL, 0, 0 };
326
327  hresult = pDisp->Invoke(dispid, IID_NULL, GetUserDefaultLCID(),
328    DISPATCH_PROPERTYGET, &params, &result, NULL, NULL);
329  if (FAILED(hresult))
330  {
331    printf("ERROR: Invoke failed: 0x%x\n", hresult);
332    Cleanup();
333    return -1;
334  }
335
336  printf("ArrayList Capacity: %d\n", result.lVal);
337
338  Cleanup();
339  return 0;
340};
341
342					  
343
344					
345
346// http://social.msdn.microsoft.com/Forums/vstudio/en-US/ce105a9b-837d-4384-ac03-287b45c1ecc9/marshalling-safearray-of-user-defined-struct					
347					  
348					  
349					  
350					  __declspec(dllexport) SAFEARRAY * music_library_get_songs()
351
352	{
353
354		USES_CONVERSION;
355
356		HRESULT hr = S_OK;
357
358
359
360		// safe array dim
361
362		SAFEARRAYBOUND safeArrayDim[1];
363
364		safeArrayDim[0].lLbound = 0;
365
366		safeArrayDim[0].cElements = 5;
367
368
369
370		// create safe array
371
372		SAFEARRAY * pSafeArray = SafeArrayCreate(VT_VARIANT,1,safeArrayDim);
373
374
375
376		// fill safe array with data
377
378		if(pSafeArray != NULL) {
379
380			unsigned int i;
381
382			long index;
383
384			pSafeArray->pvData = malloc(5*sizeof(t_song));
385
386			for(i = safeArrayDim[0].lLbound; i < safeArrayDim[0].cElements + safeArrayDim[0].lLbound; i++) {
387
388				VARIANT vOut;
389
390				VariantInit(&vOut);
391
392				t_song * song = (t_song*)malloc(sizeof(t_song));
393
394				song->album = "album";
395
396				song->artist = "artist";
397
398				song->name = "name";
399
400				/* i don't know how to connect the song structure with the VARIANT 
401
402				*/
403
404				hr = SafeArrayPutElement(pSafeArray, &index, &vOut);
405
406				VariantClear(&vOut);
407
408			}
409
410		}
411
412		return pSafeArray;
413
414	}
415managed c# code
416// structure marshaling
417
418[StructLayout(LayoutKind.Sequential)]
419
420        public class Song
421
422        {
423
424           [MarshalAs(UnmanagedType.LPTStr)]
425
426           public string name;
427
428           [MarshalAs(UnmanagedType.LPStr)]
429
430           public string album;
431
432           [MarshalAs(UnmanagedType.LPStr)]
433
434           public string artist;        
435
436
437
438        }
439
440
441
442
443
444[DllImport(MyLibrary.dll)]
445
446[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_VARIANT)]
447
448
449
450
451USES_CONVERSION;  // enables use of ATL conversion macro A2W
452char buffer[20];  // used to store ANSI string
453HRESULT hr= S_OK;
454
455// Create SafeArray of VARIANT BSTRs
456SAFEARRAY *pSA;
457SAFEARRAYBOUND aDim[1];    // a one dimensional array
458aDim[0].lLbound= 0;  // Visual Basic arrays start with index 0
459aDim[0].cElements= 10;
460pSA= SafeArrayCreate(VT_VARIANT,1,aDim);  // create a 1D SafeArray of VARIANTS
461if (pSA != NULL) {
462    long aLong[1];
463    // iterate over array adding VARIANTs of type VT_BSTR
464    for (long l= aDim[0].lLbound; l< (aDim[0].cElements + aDim[0].lLbound); l++) { 
465        VARIANT vOut;
466        VariantInit(&vOut);
467        vOut.vt= VT_BSTR;  // set type
468        ltoa(l,buffer,10);  // convert long to ANSI string value
469        vOut.bstrVal= ::SysAllocString(A2W(buffer)); // system wide "new"
470        aLong[0]= l;  // set index value
471        if (hr= SafeArrayPutElement(pSA, aLong, &vOut)) { // "correctly" copies VARIANT
472            VariantClear(&vOut);  // release BSTR from memory on error
473            SafeArrayDestroy(pSA); // does a deep destroy on error
474            return hr;
475        }
476        VariantClear(&vOut);  // does a deep destroy of source VARIANT
477    } // end iteration
478}
479// clean up here only if you do not return SafeArray as an [out, retval]
480SafeArrayDestroy(pSA); // again does a deep destroy
481
482
483
484
485// Learning DCOM book on Safary
486void CallOcrImage(IOcr *pIOcr, BYTE *pImage, ULONG len)
487{
488   // Create a one-dimensional SAFEARRAY of BYTEs (VT_UI)
489   // The size of this array is len, which represents our image length.
490   SAFEARRAY *psa = SafeArrayCreateVector(VT_UI1, 0, len);
491   // Access the data pointer
492   unsigned char *pc = NULL;
493   SafeArrayAccessData(psa, reinterpret_cast<void HUGEP**>(&pc));
494   // Copy our binary image data into array
495   memcpy(pc, pImage, len);
496   // Done accessing, so unaccess now.
497   SafeArrayUnaccessData(psa);
498   // Now we've got the array, we need to store it in
499   // a VARIANT (the value holder).
500   VARIANT vImage;           // So, let's create a variant
501   VariantInit(&vImage); // Initialize the variant
502   // Tell the value holder it's holding a SAFEARRAY of bytes
503   binaryImageArray.vt = (VT_ARRAY|VT_UI1) ;
504   binaryImageArray.parray = psa;   // Let the variant hold the array
505   // Yes!  That much set up work before we can invoke a method!
506   // Now for the method invocation...
507    BSTR pOcrText ;  // Where the OCR text will be stored
508    HRESULT hr = pIOcr->OcrImage(vImage, &pOcrText);
509   if (SUCCEEDED(hr)) {
510      m_strOCRResults = pOcrText ;
511      SysFreeString(pOcrText) ;
512   }
513   SafeArrayDestroyData(psa);  // Destroy the data within the SAFEARRAY
514   SafeArrayDestroy(psa);      // Destroy the SAFEARRAY
515   // Clear the data
516   VariantClear(&binaryImageArray);
517}
518
519
520
521void CVcpphostclrDlg::OnTestmanagedclassButton()
522
523   HRESULT hRes;
524   ICorRuntimeHost *pRuntimeHost;
525   IUnknown *pUnkAppDomain;
526   _AppDomain *pAppDomain;
527   _ObjectHandle *pHandle;
528   OLECHAR *methodName=L"GetSalary";
529   VARIANT vntResult;
530   float fltVal;
531   DISPID dispid;
532   EXCEPINFO errorInfo;
533   UINT intArg;
534   DISPPARAMS param;
535   BSTR bstrTypeName, bstrAssemblyName;
536   SAFEARRAY *paramArray;
537   VARIANT paramID, paramName;
538   VARIANT paramSalary, paramBonus;
539   LONG index;
540   hRes=CoInitializeEx(NULL,COINIT_MULTITHREADED);
541   if (FAILED(hRes))
542       AfxMessageBox("Could not initialize COM");
543   hRes=CoCreateInstance(CLSID_CorRuntimeHost,
544       NULL,CLSCTX_INPROC_SERVER,
545       IID_ICorRuntimeHost,
546       (void **)&pRuntimeHost);
547   if (FAILED(hRes))
548       AfxMessageBox("Could not create host");
549   hRes=pRuntimeHost->Start();
550   hRes=pRuntimeHost->GetDefaultDomain(
551       &pUnkAppDomain);
552   if (FAILED(hRes))
553       AfxMessageBox("Could not get Appdomain");
554   hRes=pUnkAppDomain->QueryInterface(
555       IID__AppDomain,(void **)&pAppDomain);
556   if (FAILED(hRes))
557       AfxMessageBox("Failed to get domain");
558   if (pUnkAppDomain!=NULL)
559       pUnkAppDomain->Release();
560   bstrTypeName=SysAllocString(
561       L"AssemblyDemo.Manager");
562   bstrAssemblyName=SysAllocString(
563       L"multifile3,Version=2.0.0.0,Culture=neutral,
564         PublicKeyToken=8a707be49fd7d8f4");
565   paramArray=SafeArrayCreateVector(VT_VARIANT,0,4);
566
567   VariantInit(&paramID);
568   paramID.vt=VT_I4;
569   paramID.lVal=45;
570   index=0;
571   hRes=SafeArrayPutElement(paramArray,
572       &index,&paramID);
573   VariantInit(&paramName);
574   paramName.vt=VT_BSTR;
575   paramName.bstrVal=SysAllocString(L"Alan Gordon");
576   index=1;
577   hRes=SafeArrayPutElement(paramArray,
578       &index,&paramName);
579   VariantInit(&paramSalary);
580   paramSalary.vt=VT_R4;
581   paramSalary.fltVal=1000.0;
582   VariantChangeType(&paramSalary,&paramSalary,
583       0,VT_DECIMAL);
584   index=2;
585   hRes=SafeArrayPutElement(paramArray,
586       &index,&paramSalary);
587   VariantInit(&paramBonus);
588   paramBonus.vt=VT_R4;
589   paramBonus.fltVal=100.0;
590   VariantChangeType(&paramBonus,&paramBonus,
591       0,VT_DECIMAL);
592   index=3;
593   hRes=SafeArrayPutElement(paramArray,
594       &index,&paramBonus);
595   hRes=pAppDomain->CreateInstance_3(
596       bstrAssemblyName,bstrTypeName,VARIANT_TRUE,
597       BindingFlags_Default,NULL,paramArray,
598       NULL,NULL,NULL,&pHandle);
599   if (FAILED(hRes))
600       AfxMessageBox("Could not create object");
601   VARIANT vntObject;
602   IDispatch *pObject;
603   VariantInit(&vntObject);
604   pHandle->Unwrap(&vntObject);
605   vntObject.punkVal->QueryInterface(IID_IDispatch,
606       (void **)&pObject);
607   if (vntObject.punkVal!=NULL)
608       vntObject.punkVal->Release();
609
610   param.cArgs=0;
611   param.rgvarg=NULL;
612   param.cNamedArgs=0;
613   param.rgdispidNamedArgs=NULL;
614   VariantInit(&vntResult);
615   hRes=pObject->GetIDsOfNames(IID_NULL,
616       &methodName,1,GetUserDefaultLCID(),&dispid);
617   hRes=pObject->Invoke(dispid,IID_NULL,
618       GetUserDefaultLCID(),
619       DISPATCH_METHOD,&param,&vntResult,
620       &errorInfo,&intArg);
621   if (SUCCEEDED(hRes))
622   {
623       vntResult.decVal;
624       VarR4FromDec(&vntResult.decVal,&fltVal);
625   }
626   else
627   {
628   // Handle the error, code omitted...
629   }
630   if (pObject!=NULL)
631       pObject->Release();
632   if (pAppDomain!=NULL)
633       pAppDomain->Release();
634
635   SysFreeString(bstrTypeName);
636   SysFreeString(bstrAssemblyName);
637   SafeArrayDestroy(paramArray);
638}
639
640
641					  
642
643
644					  
645					  
646					  // _bstr_t_Assign.cpp
647
648#include <comdef.h>
649#include <stdio.h>
650
651int main()
652{
653    // creates a _bstr_t wrapper
654    _bstr_t bstrWrapper; 
655
656    // creates BSTR and attaches to it
657    bstrWrapper = "some text";
658    wprintf_s(L"bstrWrapper = %s\n",
659              static_cast<wchar_t*>(bstrWrapper));
660
661    // bstrWrapper releases its BSTR
662    BSTR bstr = bstrWrapper.Detach();
663    wprintf_s(L"bstrWrapper = %s\n", 
664              static_cast<wchar_t*>(bstrWrapper));
665    // "some text" 
666    wprintf_s(L"bstr = %s\n", bstr);
667
668    bstrWrapper.Attach(SysAllocString(OLESTR("SysAllocedString")));
669    wprintf_s(L"bstrWrapper = %s\n", 
670              static_cast<wchar_t*>(bstrWrapper));
671
672    // assign a BSTR to our _bstr_t
673    bstrWrapper.Assign(bstr);
674    wprintf_s(L"bstrWrapper = %s\n", 
675              static_cast<wchar_t*>(bstrWrapper));
676
677    // done with BSTR, do manual cleanup
678    SysFreeString(bstr);
679
680    // resuse bstr
681    bstr= SysAllocString(OLESTR("Yet another string"));
682    // two wrappers, one BSTR 
683    _bstr_t bstrWrapper2 = bstrWrapper;   
684
685    *bstrWrapper.GetAddress() = bstr;
686
687    // bstrWrapper and bstrWrapper2 do still point to BSTR
688    bstr = 0;   
689    wprintf_s(L"bstrWrapper = %s\n", 
690              static_cast<wchar_t*>(bstrWrapper));
691    wprintf_s(L"bstrWrapper2 = %s\n", 
692              static_cast<wchar_t*>(bstrWrapper2));
693
694    // new value into BSTR
695    _snwprintf_s(bstrWrapper.GetBSTR(), 100, bstrWrapper.length(),
696                 L"changing BSTR");   
697    wprintf_s(L"bstrWrapper = %s\n", 
698              static_cast<wchar_t*>(bstrWrapper));
699    wprintf_s(L"bstrWrapper2 = %s\n", 
700              static_cast<wchar_t*>(bstrWrapper2));
701}
702
703
704
705HRESULT PASCAL __export CPoly::EnumPoints(IEnumVARIANT FAR* FAR* ppenum)
706{
707  unsigned int i;
708  HRESULT hresult;
709  VARIANT var;
710  SAFEARRAY FAR* psa;
711  CEnumPoint FAR* penum;
712  POINTLINK FAR* ppointlink;
713  SAFEARRAYBOUND rgsabound[1];
714  rgsabound[0].lLbound = 0;
715  rgsabound[0].cElements = m_cPoints;
716
717  psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
718  if(psa == NULL){
719    HRESULT = ResultFromScode(E_OUTOFMEMORY);
720    goto LError0;
721  }
722
723  // Code omitted here for brevity.
724
725    V_VT(&var) = VT_DISPATCH;
726    HRESULT = ppointlink->ppoint->QueryInterface(
727    IID_IDispatch, (void FAR* FAR*)&V_DISPATCH(&var));
728    if(HRESULT != NOERROR)
729      goto LError1;
730
731    ix[0] = i;
732    SafeArrayPutElement(psa, ix, &var);
733
734    ppointlink = ppointlink->next;
735  }
736
737  HRESULT = CEnumPoint::Create(psa, &penum);
738  if(HRESULT != NOERROR)
739    goto LError1;
740  *ppenum = penum;
741  return NOERROR;
742
743LError1:;
744  SafeArrayDestroy(psa);
745
746LError0:;
747  return hresult;
748}
749
750// http://social.msdn.microsoft.com/Forums/vstudio/en-US/cdc68fd4-08d5-4bfd-8dd7-6c095bd619a6/any-easy-way-to-create-a-safearray
751void AlternativeSetSafeArrayData(/*[in]*/ SAFEARRAY* psaStrings)
752{
753  BSTR  bstr = ::SysAllocString(OLESTR("Another BSTR."));
754  VARIANT var;
755  long  lIndexVector[1];
756
757  lIndexVector[0] = 0;
758  
759  VariantInit(&var);
760  VariantClear(&var);
761  V_VT(&var) = VT_BSTR;
762  V_BSTR(&var) = bstr;
763
764  SafeArrayPutElement
765  (
766    psaStrings, 
767    (long*)lIndexVector,
768    (void*)&var
769  );
770  
771  VariantClear(&var);
772}
773
774
775