Build the GHC package in stage 3 too
[ghc-hetmet.git] / rts / dotnet / Invoke.c
1 /*
2  * C callable bridge to the .NET object model
3  *
4  * Managed C++ is used to access the .NET object model via
5  * System.Reflection. Here we provide C callable functions
6  * to that functionality, which we then export via a COM
7  * component.
8  *
9  * Note: the _only_ reason why we're going via COM and not simply
10  * exposing the required via some DLL entry points, is that COM
11  * gives us location independence (i.e., the RTS doesn't need
12  * be told where this interop layer resides in order to hoik
13  * it in, the CLSID suffices (provided the component has been
14  * registered, of course.)) It is a bit tiresome to have play
15  * by the .NET COM Interop's rules as regards argument arrays,
16  * so we may want to revisit this issue at some point.
17  * 
18  * [ But why not simply use MC++ and provide C-callable entry
19  *   points to the relevant functionality, and avoid COM interop
20  *   alltogether? Because we have to be able to (statically)
21  *   link with gcc-compiled code, and linking MC++ and gcc-compiled
22  *   object files doesn't work.]
23  *
24  * Note: you need something never than gcc-2.95 to compile this
25  *       code (I'm using gcc-3.2, which comes with mingw-2).
26  */
27 #define _WIN32_DCOM
28 #define COBJMACROS
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <wtypes.h>
32 #ifndef _MSC_VER
33 #include <oaidl.h>
34 #include <objbase.h>
35 #include <oleauto.h>
36 # if defined(COBJMACROS) && !defined(_MSC_VER)
37 #define IErrorInfo_QueryInterface(T,r,O) (T)->lpVtbl->QueryInterface(T,r,O)
38 #define IErrorInfo_AddRef(T) (T)->lpVtbl->AddRef(T)
39 #define IErrorInfo_Release(T) (T)->lpVtbl->Release(T)
40 #define IErrorInfo_GetSource(T,pbstr) (T)->lpVtbl->GetSource(T,pbstr)
41 #define IErrorInfo_GetDescription(T,pbstr) (T)->lpVtbl->GetDescription(T,pbstr)
42
43 #define ISupportErrorInfo_QueryInterface(T,r,O) (T)->lpVtbl->QueryInterface(T,r,O)
44 #define ISupportErrorInfo_AddRef(T) (T)->lpVtbl->AddRef(T)
45 #define ISupportErrorInfo_Release(T) (T)->lpVtbl->Release(T)
46 #define ISupportErrorInfo_InterfaceSupportsErrorInfo(T,iid) (T)->lpVtbl->InterfaceSupportsErrorInfo(T,iid)
47 # endif
48 #endif
49 #include "DNInvoke.h"
50 #define WANT_UUID_DECLS
51 #include "InvokerClient.h"
52 #include "Dotnet.h"
53
54 /* Local prototypes */
55 static void genError( IUnknown* pUnk,
56                       HRESULT hr,
57                       char* loc,
58                       char** pErrMsg);
59 static int  startBridge(char**);
60 static int  fromVariant
61                     ( DotnetType resTy, 
62                       VARIANT* pVar, 
63                       void* res,
64                       char** pErrMsg);
65 static VARIANT* toVariant ( DotnetArg* p );
66
67 /* Pointer to .NET COM component instance; instantiated on demand. */
68 static InvokeBridge* pBridge = NULL;
69
70 /* convert a char* to a BSTR, copied from the HDirect comlib/ sources */
71 static
72 HRESULT
73 stringToBSTR( /*[in,ptr]*/const char* pstrz
74             , /*[out]*/ BSTR* pbstr
75             )
76 {
77   int i;
78
79   if (!pbstr) {
80     return E_FAIL;
81   } else {
82     *pbstr = NULL;
83   }
84   if (!pstrz) {
85     return S_OK;
86   }
87
88   i = MultiByteToWideChar(CP_ACP, 0, pstrz, -1, NULL, 0);
89   if ( i < 0 ) {
90     return E_FAIL;
91   }
92   *pbstr = SysAllocStringLen(NULL,i-1);
93   if (*pbstr != NULL) {
94     MultiByteToWideChar(CP_ACP, 0, pstrz, -1, *pbstr, i-1); 
95     //    (*pbstr)[i]=0;
96     return S_OK;
97   } else {
98     return E_FAIL;
99   }
100 }
101
102 static
103 char*
104 bstrToString( BSTR bstr )
105 {
106     int  i,len;
107     char *res;
108     int  blen;
109
110     if (!bstr) {
111         return NULL;
112     }
113     
114     blen =  SysStringLen(bstr);
115     
116     /* pass in NULL for the multi-byte arg in order to compute length first */
117     len = WideCharToMultiByte(CP_ACP, 0, bstr, blen,
118                               NULL, 0, NULL, NULL);
119     if (len == 0) return NULL;
120     
121     /* Allocate string of required length. */
122     res = (char*)malloc(sizeof(char) * (len + 1));
123     if (!res) return NULL;
124     
125     i = WideCharToMultiByte(CP_ACP, 0, bstr, blen,
126                             res, (len+1), NULL, NULL);
127                             
128     /* Poor error handling to map this to NULL. */
129     if ( i == 0 ) return NULL;
130
131     /* Terminate and return */
132     res[i] = '\0';
133     return res;
134 }
135
136 static
137 void
138 freeArgs ( SAFEARRAY* psa )
139 {
140   /* The argument SAFEARRAYs contain dynamically allocated
141    * VARIANTs. Release the VARIANT contents and its memory here.
142    */
143   long lb,ub;
144   int i;
145   HRESULT hr;
146   VARIANT *pv = NULL;
147   
148   hr = SafeArrayGetLBound(psa, 1, &lb);
149   if (FAILED(hr)) {
150     fprintf(stderr, "freeArgs: failed fetching lower bound\n");
151     SafeArrayDestroy(psa);
152     return;
153   }
154   hr = SafeArrayGetUBound(psa, 1, &ub);
155   if (FAILED(hr)) {
156     fprintf(stderr, "freeArgs: failed fetching upper bound\n");
157     SafeArrayDestroy(psa);
158     return;
159   }
160   for ( i = 0; i < (ub - lb); i++ ) {
161     hr = SafeArrayGetElement(psa,(long*)&i,(void*)pv);
162     if (FAILED(hr)) {
163       fprintf(stderr, "freeArgs: unable to fetch element %d\n", i);
164       SafeArrayDestroy(psa);
165       return;
166     }
167     VariantClear(pv);
168     free(pv);
169   }
170   SafeArrayDestroy(psa);
171 }
172
173 static
174 SAFEARRAY*
175 marshalArgs ( DotnetArg*   args,
176               unsigned int n_args )
177 {
178   SAFEARRAY *psa;
179   SAFEARRAYBOUND rgsabound[1];
180   int i;
181   long idxArr[1];
182   HRESULT hr;
183   VARIANT* var;
184
185   rgsabound[0].lLbound   = 0;
186   rgsabound[0].cElements = n_args;
187   psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
188   
189   for(i=0;i < n_args; i++) {
190     idxArr[0] = i;
191     var = toVariant(&args[i]);
192     hr = SafeArrayPutElement(psa, idxArr, (void*)var);
193   }
194   return psa;
195 }
196
197 /* 
198  * ***** Accessing the .NET object model *****
199  *
200  * General remarks:
201  *
202  *   - the functions report error conditions via their return value; a char*.
203  *     If NULL, the call was successful. If not, the returned string 
204  *     contains the (dynamically allocated) error message. 
205  * 
206  *     This unorthodox calling convetion is used to simplify the task
207  *     of interfacing to these funs from GHC-generated code.
208  */
209
210 /*
211  * Function: DN_invokeStatic()
212  *
213  * Given assembly and fully-qualified name of a static .NET method,
214  * invoke it using the supplied arguments.
215  *
216  * Returns NULL on success, pointer to error message if an error.
217  *
218  */
219 char*
220 DN_invokeStatic ( char       *assemName,
221                   char       *methName,
222                   DotnetArg  *args,
223                   int        n_args,
224                   DotnetType resultTy,
225                   void       *res)
226 {
227     SAFEARRAY* psa;
228     VARIANT    result;
229     HRESULT    hr;
230     BSTR       b_assemName;
231     BSTR       b_methName;
232     char*      errMsg = NULL;
233     
234     if (!pBridge && !startBridge(&errMsg)) {
235       return errMsg;
236     }
237     
238     /* Package up arguments */
239     psa = marshalArgs(args, n_args);
240     VariantInit(&result);
241     
242     hr = stringToBSTR(assemName, &b_assemName);
243     hr = stringToBSTR(methName, &b_methName);
244
245     hr = InvokeBridge_InvokeStaticMethod(pBridge,
246                                          b_assemName,
247                                          b_methName,
248                                          psa,
249                                          &result);
250     SysFreeString(b_assemName);
251     SysFreeString(b_methName);
252     if (FAILED(hr)) {
253         genError((IUnknown*)pBridge, hr, "DInvoke.invokeStatic", &errMsg);
254         return errMsg;
255     }
256    
257     fromVariant(resultTy, &result, res, &errMsg);
258     freeArgs(psa);
259   
260     return errMsg;
261 }
262
263 /*
264  * Function: DN_invokeMethod()
265  *
266  * Given method name and arguments, invoke .NET method on an object.
267  * The object ref / this-pointer is passed in as the last argument.
268  *
269  * Returns NULL on success, pointer to error message if an error.
270  *
271  */
272 char*
273 DN_invokeMethod ( char       *clsAndMethName,
274                   DotnetArg  *args,
275                   int        n_args,
276                   DotnetType resultTy,
277                   void       *res)
278 {
279     SAFEARRAY* psa;
280     VARIANT    result;
281     HRESULT    hr;
282     char*      methName;
283     BSTR       b_methName;
284     char*      errMsg = NULL;
285     VARIANT    *thisPtr;
286     
287     if (!pBridge && !startBridge(&errMsg)) {
288       return errMsg;
289     }
290     
291     if (n_args <= 0) {
292       genError(NULL, 0x0, "Invoke.invokeMethod - missing this pointer", &errMsg);
293       return errMsg;
294     }
295     
296     /* The this-pointer is last */
297     thisPtr = toVariant(&args[n_args-1]);
298
299     /* Package up arguments */
300     psa = marshalArgs(args, n_args-1);
301     VariantInit(&result);
302     
303     /* If the user has qualified method with class, ignore the class bit. */
304     if ( (methName = strrchr(clsAndMethName, '.')) == NULL) {
305       methName = clsAndMethName;
306     } else {
307       /* Skip past '.' */
308       methName++;
309     }
310     
311     hr = stringToBSTR(methName, &b_methName);
312     hr = InvokeBridge_InvokeMethod(pBridge,
313                                    *thisPtr,
314                                    b_methName,
315                                    psa,
316                                    &result);
317     SysFreeString(b_methName);
318     if (FAILED(hr)) {
319         genError((IUnknown*)pBridge, hr, "Invoke.invokeMethod", &errMsg);
320         return errMsg;
321     }
322     
323     fromVariant(resultTy, &result, res, &errMsg);
324     freeArgs(psa);
325   
326     return errMsg;
327 }
328
329 /*
330  * Function: DN_getField()
331  *
332  * Given a field name and an object pointer, read a field value.
333  * The object ref / this-pointer is passed in as the last argument.
334  *
335  * Returns NULL on success, pointer to error message if an error.
336  *
337  */
338 char*
339 DN_getField ( char       *clsAndMethName,
340               DotnetArg  *args,
341               int        n_args,
342               DotnetType resultTy,
343               void       *res)
344 {
345     VARIANT    result;
346     HRESULT    hr;
347     char*      methName;
348     BSTR       b_methName;
349     char*      errMsg = NULL;
350     VARIANT    *thisPtr;
351     
352     if (!pBridge && !startBridge(&errMsg)) {
353       return errMsg;
354     }
355     
356     if (n_args <= 0) {
357       genError(NULL, 0x0, "Invoke.getField - missing this pointer", &errMsg);
358       return errMsg;
359     }
360     
361     /* The this-pointer is last */
362     thisPtr = toVariant(&args[n_args-1]);
363     VariantInit(&result);
364     
365     /* If the user has qualified method with class, ignore the class bit. */
366     if ( (methName = strrchr(clsAndMethName, '.')) == NULL) {
367       methName = clsAndMethName;
368     } else {
369       /* Skip past '.' */
370       methName++;
371     }
372     
373     hr = stringToBSTR(methName, &b_methName);
374     hr = InvokeBridge_GetField(pBridge,
375                                *thisPtr,
376                                b_methName,
377                                &result);
378     SysFreeString(b_methName);
379     if (FAILED(hr)) {
380         genError((IUnknown*)pBridge, hr, "Invoke.getField", &errMsg);
381         return errMsg;
382     }
383     
384     fromVariant(resultTy, &result, res, &errMsg);
385     return errMsg;
386 }
387
388 /*
389  * Function: DN_setField()
390  *
391  * Given field name, a value and an object reference, set the field value of
392  * an object.
393  * The object ref / this-pointer is passed in as the last argument.
394  *
395  * Returns NULL on success, pointer to error message if an error.
396  *
397  */
398 char*
399 DN_setField ( char       *clsAndMethName,
400               DotnetArg  *args,
401               int        n_args,
402               /* next two args are ignored */
403               DotnetType resultTy,
404               void       *res)
405 {
406     HRESULT    hr;
407     char*      methName;
408     BSTR       b_methName;
409     char*      errMsg = NULL;
410     VARIANT    *thisPtr;
411     VARIANT    *pVal;
412
413     if (!pBridge && !startBridge(&errMsg)) {
414       return errMsg;
415     }
416     
417     if (n_args != 2) {
418       genError(NULL, 0x0, "Invoke.setField - missing this pointer", &errMsg);
419       return errMsg;
420     }
421     
422     /* The this-pointer is last */
423     thisPtr = toVariant(&args[1]);
424
425     /* Package up arguments */
426     pVal = toVariant(&args[0]);
427     
428     /* If the user has qualified method with class, ignore the class bit. */
429     if ( (methName = strrchr(clsAndMethName, '.')) == NULL) {
430       methName = clsAndMethName;
431     } else {
432       /* Skip past '.' */
433       methName++;
434     }
435     
436     hr = stringToBSTR(methName, &b_methName);
437     hr = InvokeBridge_SetField(pBridge,
438                                *thisPtr,
439                                b_methName,
440                                *pVal);
441     SysFreeString(b_methName);
442     VariantClear(pVal);
443     free(pVal);
444     free(thisPtr);
445
446     if (FAILED(hr)) {
447         genError((IUnknown*)pBridge, hr, "Invoke.setField", &errMsg);
448         return errMsg;
449     }
450     return errMsg;
451 }
452
453
454 /*
455  * Function: DN_createObject()
456  *
457  * Given assembly and fully-qualified name of a type,
458  * invoke its (possibly parameterised) constructor.
459  *
460  * Returns NULL on success, pointer to error message if an error.
461  *
462  */
463 char*
464 DN_createObject ( char       *assemName,
465                   char       *methName,
466                   DotnetArg  *args,
467                   int        n_args,
468                   DotnetType resultTy,
469                   void       *res)
470 {
471     SAFEARRAY* psa;
472     VARIANT    result;
473     HRESULT    hr;
474     BSTR       b_assemName;
475     BSTR       b_methName;
476     char*      errMsg = NULL;
477     
478     if (!pBridge && !startBridge(&errMsg)) {
479       return errMsg;
480     }
481     
482     /* Package up arguments */
483     psa = marshalArgs(args, n_args);
484     VariantInit(&result);
485     
486     hr = stringToBSTR(assemName, &b_assemName);
487     hr = stringToBSTR(methName, &b_methName);
488
489     hr = InvokeBridge_CreateObject(pBridge,
490                                    b_assemName,
491                                    b_methName,
492                                    psa,
493                                    &result);
494     SysFreeString(b_assemName);
495     SysFreeString(b_methName);
496     if (FAILED(hr)) {
497         genError((IUnknown*)pBridge, hr, "DN_createObject", &errMsg);
498         return errMsg;
499     }
500     
501     fromVariant(resultTy, &result, res, &errMsg);
502     freeArgs(psa);
503   
504     return errMsg;
505 }
506
507 /*
508  * Function: DN_getStatic()
509  *
510  * Given assembly and fully-qualified field name, fetch value of static
511  * field.
512  *
513  * Returns NULL on success, pointer to error message if an error.
514  *
515  */
516 char*
517 DN_getStatic ( char       *assemName,
518                char       *fieldClsName,
519                /* the next two args are ignored */
520                DotnetArg  *args,
521                int        n_args,
522                DotnetType resultTy,
523                void       *res)
524 {
525     VARIANT    result;
526     HRESULT    hr;
527     BSTR       b_assemName;
528     BSTR       b_clsName;
529     BSTR       b_fieldName;
530     char*      errMsg = NULL;
531     char*      fieldName;
532     char*      clsName = fieldName;
533     
534     if (!pBridge && !startBridge(&errMsg)) {
535       return errMsg;
536     }
537     
538     fieldName = (char*)malloc(sizeof(char) * (strlen(fieldClsName) + 1));
539     strcpy(fieldName, fieldClsName);
540     clsName = fieldName;
541     
542     if (( fieldName = strrchr(fieldName, '.')) == NULL ) {
543       genError((IUnknown*)pBridge, 0x0, "Invoke.getStatic - malformed field spec", &errMsg);
544       return errMsg;
545     }
546     *fieldName = '\0';
547     fieldName++;
548     
549     VariantInit(&result);
550     
551     hr = stringToBSTR(assemName, &b_assemName);
552     hr = stringToBSTR(fieldName, &b_fieldName);
553     hr = stringToBSTR(clsName, &b_clsName);
554     /* ToDo: honour assembly spec */
555     hr = InvokeBridge_GetStaticField(pBridge,
556                                      b_clsName,
557                                      b_fieldName,
558                                      &result);
559     SysFreeString(b_assemName);
560     SysFreeString(b_clsName);
561     SysFreeString(b_fieldName);
562     if (FAILED(hr)) {
563         genError((IUnknown*)pBridge, hr, "Invoke.getStatic", &errMsg);
564         return errMsg;
565     }
566     fromVariant(resultTy, &result, res, &errMsg);
567   
568     return errMsg;
569 }
570
571 /*
572  * Function: DN_setStatic()
573  *
574  * Given assembly and fully-qualified field name, set value of static
575  * field.
576  *
577  * Returns NULL on success, pointer to error message if an error.
578  *
579  */
580 char*
581 DN_setStatic ( char       *assemName,
582                char       *fieldClsName,
583                DotnetArg  *args,
584                int        n_args,
585                /* the next two args are ignored */
586                DotnetType resultTy,
587                void       *res)
588 {
589     VARIANT    result;
590     VARIANT    *pVal;
591     HRESULT    hr;
592     BSTR       b_assemName;
593     BSTR       b_clsName;
594     BSTR       b_fieldName;
595     char*      errMsg = NULL;
596     char*      fieldName;
597     char*      clsName = fieldName;
598     
599     if (!pBridge && !startBridge(&errMsg)) {
600       return errMsg;
601     }
602     
603     fieldName = (char*)malloc(sizeof(char) * (strlen(fieldClsName) + 1));
604     strcpy(fieldName, fieldClsName);
605     clsName = fieldName;
606     
607     if (( fieldName = strrchr(fieldName, '.')) == NULL ) {
608       genError((IUnknown*)pBridge, 0x0, "Invoke.setStatic - malformed field spec", &errMsg);
609       return errMsg;
610     }
611     *fieldName = '\0';
612     fieldName++;
613     
614     pVal = toVariant(&args[0]);
615     VariantInit(&result);
616     
617     hr = stringToBSTR(assemName, &b_assemName);
618     hr = stringToBSTR(fieldName, &b_fieldName);
619     hr = stringToBSTR(clsName, &b_clsName);
620     /* ToDo: honour assembly spec */
621     hr = InvokeBridge_SetStaticField(pBridge,
622                                      b_clsName,
623                                      b_fieldName,
624                                      *pVal);
625     SysFreeString(b_assemName);
626     SysFreeString(b_clsName);
627     SysFreeString(b_fieldName);
628     VariantClear(pVal);
629     free(pVal);
630     if (FAILED(hr)) {
631         genError((IUnknown*)pBridge, hr, "Invoke.setStatic", &errMsg);
632         return errMsg;
633     }
634     fromVariant(resultTy, &result, res, &errMsg);
635   
636     return errMsg;
637 }
638
639
640
641
642 /*
643  * Function: startBridge(pErrMsg)
644  *
645  * Instantiates an InvokeBridge component, which is then
646  * used to interact with the .NET world.
647  *
648  * If the component isn't available locally, zero is returned.
649  * Otherwise, 1.
650  */
651 static
652 int
653 startBridge(char** pErrMsg)
654 {
655     HRESULT   hr;
656     IUnknown *pUnk;
657
658     hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
659     if (FAILED(hr)) {
660         genError(NULL, hr, "DInvoke.createBridge.CoInitializeEx", pErrMsg);
661         return FALSE;
662     }
663
664     hr = CoCreateInstance( &CLSID_InvokeBridge,
665                            NULL,
666                            CLSCTX_INPROC_SERVER,
667                            &IID_IUnknown,
668                            (void**)&pUnk);
669     if (FAILED(hr)) {
670         genError(NULL, hr, "DInvoke.createBridge.CoCreateInstance", pErrMsg);
671         return 0;
672     }
673     
674     hr = IUnknown_QueryInterface(pUnk, &IID_InvokeBridge, (void**)&pBridge);
675     IUnknown_Release(pUnk);
676     if (FAILED(hr)) {
677         genError(pUnk, hr, "DInvoke.createBridge.QueryInterface.InvokeBridge", pErrMsg);
678         return 0;
679     }
680     
681     return 1;
682 }
683
684 /*
685  * Function: stopBridge()
686  *
687  * Releases the InvokeBridge object and closes the COM library.
688  * 
689  */
690 void
691 stopDotnetBridge()
692 {
693     if (pBridge) {
694         InvokeBridge_Release(pBridge);
695         pBridge = NULL;
696         CoUninitialize();
697     }
698     /* Match up the call to CoInitializeEx() in startBridge(). */
699 }
700
701 /*
702  * Function: genError()
703  *
704  * Construct a string describing an error condition given
705  * an HRESULT and a location. 
706  * 
707  * If an interface pointer is passed in via the first arg, 
708  * attempts are made to get at richer error information through
709  * the IErrorInfo interface. (Note: we don't currently look for
710  * the _Exception interface for even more detailed info.)
711  *
712  */
713 #define LOCATION_HDR "Location: "
714 #define HRESULT_HDR  "HRESULT: "
715 #define SOURCE_HDR   "Source: "
716 #define DESCR_HDR    "Description: "
717 #define NEWLINE_EXTRA 3
718
719 static
720 void
721 genError(IUnknown* pUnk,
722          HRESULT err,
723          char* loc,
724          char** pErrMsg)
725 {
726   HRESULT hr;
727   HRESULT invoke_hr = err;
728   char*   invoke_src   = NULL;
729   char*   invoke_descr = NULL;
730   char*   buf;
731   int     bufLen;
732   
733   /* If an interface pointer has been supplied, look for
734    * IErrorInfo in order to get more detailed information
735    * on the failure.
736    *
737    * The CLR's .NET COM Interop implementation does provide
738    * IErrorInfo, so we're not really clutching at straws here..
739    *
740    * Note: CLR also reflects .NET exceptions via the _Exception*
741    * interface..
742    *
743    */
744   if (pUnk) {
745     ISupportErrorInfo *pSupp;
746     IErrorInfo        *pErrInfo;
747     BSTR src   = NULL;
748     BSTR descr = NULL;
749
750     hr = IUnknown_QueryInterface(pUnk, 
751                                  &IID_ISupportErrorInfo,
752                                  (void**)&pSupp);
753     if ( SUCCEEDED(hr) ) {
754       hr = ISupportErrorInfo_InterfaceSupportsErrorInfo(pSupp,
755                                                         &IID_InvokeBridge);
756       if ( SUCCEEDED(hr) ) {
757         hr = GetErrorInfo(0,&pErrInfo);
758         if ( SUCCEEDED(hr) ) {
759           IErrorInfo_GetSource(pErrInfo,&src);
760           IErrorInfo_GetDescription(pErrInfo,&descr);
761           invoke_src   = bstrToString(src);
762           invoke_descr = bstrToString(descr);
763
764           IErrorInfo_Release(pErrInfo);
765           if (src)   { SysFreeString(src);   src = NULL;   }
766           if (descr) { SysFreeString(descr); descr = NULL; }
767         }
768         ISupportErrorInfo_Release(pSupp);
769       }
770     }
771   }
772   /* Putting it all together.. */
773   bufLen  = sizeof(LOCATION_HDR) + strlen(loc) + NEWLINE_EXTRA +
774             sizeof(HRESULT_HDR)  + 16 + NEWLINE_EXTRA + 
775             sizeof(SOURCE_HDR)   + (invoke_src ? strlen(invoke_src) : 16) + NEWLINE_EXTRA +
776             sizeof(DESCR_HDR)    + (invoke_descr ? strlen(invoke_descr) : 16) + NEWLINE_EXTRA;
777   buf = (char*) malloc(sizeof(char) * (bufLen + 1));
778   if (!buf) {
779     fprintf(stderr, "Unable to allocate %d for error message", (bufLen + 1));
780     *pErrMsg = NULL;
781     return;
782   }
783     
784   _snprintf(buf, bufLen, "%s%s\n%s0x%08x\n%s%s\n%s%s",
785            LOCATION_HDR, loc,
786            HRESULT_HDR,  invoke_hr,
787            SOURCE_HDR,   invoke_src,
788            DESCR_HDR,    invoke_descr);
789
790   /* Done with these chaps */
791   if (invoke_src)   free(invoke_src);
792   if (invoke_descr) free(invoke_descr);
793   
794   if (pErrMsg) *pErrMsg = buf;
795   fprintf(stderr, "**InvokeBridge Error:\n%s", buf); fflush(stderr);
796 }
797
798 /* Converting to/from VARIANTs */
799
800 /*
801  * Function: fromVariant()
802  *
803  * Unmarshal the contents of a VARIANT, converting its embedded value
804  * into the desired DotnetType (if possible.)
805  *
806  * Returns 1 if successful, 0 otherwise. If the conversion fails, 
807  * *pErrMsg holds the error message string.
808  */
809 static
810 int
811 fromVariant (DotnetType resTy, 
812              VARIANT* pVar, 
813              void* res,
814              char** pErrMsg)
815 {
816     VARIANT vNew;
817     HRESULT hr;
818
819     VariantInit(&vNew);
820     switch(resTy) {
821     case Dotnet_Byte:
822     case Dotnet_Char:
823         hr = VariantChangeType (&vNew, pVar, 0, VT_UI1);
824         if (FAILED(hr)) {
825             genError(NULL, hr, "DInvoke.fromVariant{VT_UI1}", pErrMsg);
826             return FALSE;
827         }
828         *((unsigned char*)res) = vNew.bVal;
829         return 1;
830     case Dotnet_Boolean:
831         hr = VariantChangeType (&vNew, pVar, 0, VT_BOOL);
832         if (FAILED(hr)) {
833             genError(NULL, hr, "DInvoke.fromVariant{VT_BOOL}", pErrMsg);
834             return 0;
835         }
836         *((unsigned char*)res) = vNew.bVal;
837         return 1;
838     case Dotnet_Int:
839         hr = VariantChangeType (&vNew, pVar, 0, VT_INT);
840         if (FAILED(hr)) {
841             genError(NULL, hr, "DInvoke.fromVariant{VT_INT}", pErrMsg);
842             return 0;
843         }
844         *((int*)res) = vNew.intVal;
845         return 1;
846     case Dotnet_Int8:
847         hr = VariantChangeType (&vNew, pVar, 0, VT_I1);
848         if (FAILED(hr)) {
849             genError(NULL, hr, "DInvoke.fromVariant{VT_I1}", pErrMsg);
850             return 0;
851         }
852         *((signed char*)res) = vNew.bVal;
853         return 1;
854     case Dotnet_Int16:
855         hr = VariantChangeType (&vNew, pVar, 0, VT_I2);
856         if (FAILED(hr)) {
857             genError(NULL, hr, "DInvoke.fromVariant{VT_I2}", pErrMsg);
858             return 0;
859         }
860         *((signed short*)res) = vNew.iVal;
861         return 1;
862     case Dotnet_Int32:
863         hr = VariantChangeType (&vNew, pVar, 0, VT_I4);
864         if (FAILED(hr)) {
865             genError(NULL, hr, "DInvoke.fromVariant{VT_I4}", pErrMsg);
866             return 0;
867         }
868         *((signed int*)res) = vNew.lVal;
869         return 1;
870     case Dotnet_Int64:
871         hr = VariantChangeType (&vNew, pVar, 0, VT_I8);
872         if (FAILED(hr)) {
873             genError(NULL, hr, "DInvoke.fromVariant{VT_I8}", pErrMsg);
874             return 0;
875         }
876 #ifdef _MSC_VER
877         *((__int64*)res) = vNew.llVal;
878 #else
879         *((long long*)res) = vNew.lVal;
880 #endif
881         return 1;
882     case Dotnet_Float:
883         hr = VariantChangeType (&vNew, pVar, 0, VT_R4);
884         if (FAILED(hr)) {
885             genError(NULL, hr, "DInvoke.fromVariant{VT_R4}", pErrMsg);
886             return 0;
887         }
888         *((float*)res) = vNew.fltVal;
889         return 1;
890     case Dotnet_Double:
891         hr = VariantChangeType (&vNew, pVar, 0, VT_R8);
892         if (FAILED(hr)) {
893             genError(NULL, hr, "DInvoke.fromVariant{VT_R4}", pErrMsg);
894             return 0;
895         }
896         *((double*)res) = vNew.dblVal;
897         return 1;
898     case Dotnet_Word8:
899         hr = VariantChangeType (&vNew, pVar, 0, VT_UI1);
900         if (FAILED(hr)) {
901             genError(NULL, hr, "DInvoke.fromVariant{VT_UI1}", pErrMsg);
902             return 0;
903         }
904         *((unsigned char*)res) = vNew.bVal;
905         return 1;
906     case Dotnet_Word16:
907         hr = VariantChangeType (&vNew, pVar, 0, VT_UI2);
908         if (FAILED(hr)) {
909             genError(NULL, hr, "DInvoke.fromVariant{VT_UI2}", pErrMsg);
910             return 0;
911         }
912         *((unsigned short*)res) = vNew.uiVal;
913         return 1;
914     case Dotnet_Word32:
915         hr = VariantChangeType (&vNew, pVar, 0, VT_UI4);
916         if (FAILED(hr)) {
917             genError(NULL, hr, "DInvoke.fromVariant{VT_UI4}", pErrMsg);
918             return 0;
919         }
920         *((unsigned int*)res) = vNew.ulVal;
921         return 1;
922     case Dotnet_Word64:
923         hr = VariantChangeType (&vNew, pVar, 0, VT_UI8);
924         if (FAILED(hr)) {
925             genError(NULL, hr, "DInvoke.fromVariant{VT_UI8}", pErrMsg);
926             return 0;
927         }
928 #ifdef _MSC_VER
929         *((unsigned __int64*)res) = vNew.ullVal;
930 #else
931         *((unsigned long long*)res) = vNew.lVal;
932 #endif
933         return 1;
934     case Dotnet_Ptr:
935         hr = VariantChangeType (&vNew, pVar, 0, VT_BYREF);
936         if (FAILED(hr)) {
937             genError(NULL, hr, "DInvoke.fromVariant{VT_BYREF}", pErrMsg);
938             return 0;
939         }
940         *((void**)res) = vNew.byref;
941         return 1;
942     case Dotnet_Unit:
943         return 0;
944     case Dotnet_Object:
945       if ( pVar->vt == VT_BSTR ) {
946         /* Special handling for strings. If the user has asked for
947          * the string in object form, give him/her that. 
948          */
949         VARIANT res;
950
951         VariantInit(&res);
952         hr = InvokeBridge_NewString(pBridge,
953                                     pVar->bstrVal,
954                                     &res);
955         if (SUCCEEDED(hr)) {
956           pVar = &res;
957         }
958       }
959         hr = VariantChangeType (&vNew, pVar, 0, VT_UNKNOWN);
960         if (FAILED(hr)) {
961             genError(NULL, hr, "DInvoke.fromVariant{VT_UNKNOWN}", pErrMsg);
962             return 0;
963         }
964         *((IUnknown**)res) = vNew.punkVal;
965         return 1;
966     case Dotnet_String:
967         hr = VariantChangeType (&vNew, pVar, 0, VT_BSTR);
968         if (FAILED(hr)) {
969             genError(NULL, hr, "DInvoke.fromVariant{VT_BSTR}", pErrMsg);
970             return 0;
971         }
972         /* Storage is allocated by malloc(), caller is resp for freeing. */
973         *((char**)res) = bstrToString(vNew.bstrVal);
974         return 1;
975     }
976     return 0;
977 }
978
979 /*
980  * Function: toVariant()
981  *
982  * Convert a DotnetArg into a VARIANT. The VARIANT
983  * is dynamically allocated.
984  *
985  * The result is the pointer to the filled-in VARIANT structure;
986  * NULL if allocation failed.
987  *
988  */
989 static
990 VARIANT*
991 toVariant ( DotnetArg* p )
992 {
993   VARIANT* v = (VARIANT*)malloc(sizeof(VARIANT));
994   if (!v) return NULL;
995   VariantInit(v);
996   switch (p->arg_type) {
997   case Dotnet_Byte:
998     v->vt = VT_UI1;
999     v->bVal = p->arg.arg_byte;
1000     break;
1001   case Dotnet_Char:
1002     v->vt = VT_UI1;
1003     v->bVal = p->arg.arg_char;
1004     break;
1005   case Dotnet_Boolean:
1006     v->vt = VT_BOOL;
1007     v->boolVal = p->arg.arg_bool;
1008     break;
1009   case Dotnet_Int:
1010     v->vt = VT_INT;
1011     v->intVal = p->arg.arg_int;
1012     break;
1013   case Dotnet_Int8:
1014     v->vt = VT_I1;
1015     v->bVal = p->arg.arg_int8;
1016     break;
1017   case Dotnet_Int16:
1018     v->vt = VT_I2;
1019     v->iVal = p->arg.arg_int16;
1020     break;
1021   case Dotnet_Int32:
1022     v->vt = VT_I4;
1023     v->lVal = p->arg.arg_int32;
1024     break;
1025   case Dotnet_Int64:
1026     v->vt = VT_I8;
1027 #ifdef _MSC_VER
1028     v->llVal = p->arg.arg_int64;
1029 #else
1030     (long long*)(v->lVal) = p->arg.arg_int64;
1031 #endif
1032     break;
1033   case Dotnet_Float:
1034     v->vt = VT_R4;
1035     v->fltVal = p->arg.arg_float;
1036     break;
1037   case Dotnet_Double:
1038     v->vt = VT_R8;
1039     v->dblVal = p->arg.arg_double;
1040     break;
1041   case Dotnet_Word8:
1042     v->vt = VT_UI1;
1043     v->bVal = p->arg.arg_word8;
1044     break;
1045   case Dotnet_Word16:
1046     v->vt = VT_UI2;
1047     v->uiVal = p->arg.arg_word16;
1048     break;
1049   case Dotnet_Word32:
1050     v->vt = VT_UI4;
1051     v->ulVal = p->arg.arg_word32;
1052     break;
1053   case Dotnet_Word64:
1054     v->vt = VT_UI8;
1055 #ifdef _MSC_VER
1056     v->ullVal = p->arg.arg_word64;
1057 #else
1058     (unsigned long long*)(v->lVal) = p->arg.arg_word64;
1059 #endif
1060     break;
1061   case Dotnet_Ptr:
1062     v->vt = VT_BYREF;
1063     v->byref = p->arg.arg_ptr;
1064     break;
1065   case Dotnet_Unit:
1066     v->vt = VT_EMPTY;
1067     break;
1068   case Dotnet_Object:
1069     v->vt = VT_UNKNOWN;
1070     v->punkVal = (IUnknown*)p->arg.arg_obj;
1071     break;
1072   case Dotnet_String: {
1073     BSTR b;
1074     HRESULT hr;
1075     v->vt = VT_BSTR;
1076     hr = stringToBSTR((const char*)p->arg.arg_str,&b);
1077     v->bstrVal = b;
1078     break; }
1079   }
1080   return v;
1081 }