ICP  1
variant_utils.cpp
Go to the documentation of this file.
1 #include "stdafx.h"
2 #include "variant_utils.h"
3 
4 
5 std::string COMexception::com_message(const std::string& message, HRESULT hr)
6 {
7  _com_error ce(hr);
8  std::ostringstream oss;
9  oss << message << ": " << ce.ErrorMessage();
10  return oss.str();
11 }
12 
13 // 0 on success, -1 on error
14 
15 int allocateArrayVariant(VARIANT* v, VARTYPE v_type, int* dims_array, int ndims)
16 {
17  int i;
18  V_VT(v) = VT_ARRAY | v_type;
19  SAFEARRAYBOUND* sab = new SAFEARRAYBOUND[ndims];
20  if (sab == NULL)
21  {
22  return -1;
23  }
24  // safe arrays are index other way round to C
25  for(i=0; i<ndims; i++)
26  {
27  sab[i].lLbound = 1;
28  sab[i].cElements = dims_array[ndims-i-1];
29  }
30  V_UNION(v,parray) = SafeArrayCreate(v_type, ndims, sab);
31  delete []sab;
32  if (V_UNION(v,parray) == NULL)
33  {
34  return -1;
35  }
36  return 0;
37 }
38 
39 
40 static int accessArrayVariant(VARIANT* v, void** values, VARTYPE vt)
41 {
42  VARTYPE vtt;
43  HRESULT hr;
44  *values = NULL;
45  hr = SafeArrayGetVartype(V_UNION(v,parray), &vtt);
46  if (!(vtt & vt))
47  {
48  return -1;
49  }
50  hr = SafeArrayAccessData(V_UNION(v,parray), values);
51  if ( FAILED(hr) || (*values == NULL) )
52  {
53  *values = NULL;
54  return -1;
55  }
56  return 0;
57 }
58 
59 int accessArrayVariant(VARIANT* v, float** values)
60 {
61  return accessArrayVariant(v, (void**)values, VT_R4);
62 }
63 
64 int accessArrayVariant(VARIANT* v, double** values)
65 {
66  return accessArrayVariant(v, (void**)values, VT_R8);
67 }
68 
69 int accessArrayVariant(VARIANT* v, long** values)
70 {
71  return accessArrayVariant(v, (void**)values, VT_I4);
72 }
73 
74 int accessArrayVariant(VARIANT* v, BSTR** values)
75 {
76  return accessArrayVariant(v, (void**)values, VT_BSTR);
77 }
78 
79 int accessArrayVariant(VARIANT* v, VARIANT** values)
80 {
81  return accessArrayVariant(v, (void**)values, VT_VARIANT);
82 }
83 
84 int unaccessArrayVariant(VARIANT* v)
85 {
86  HRESULT hr = SafeArrayUnaccessData(V_UNION(v,parray));
87  if (FAILED(hr))
88  {
89  return -1;
90  }
91  return 0;
92 }
93 
94 
95 int arrayVariantLength(VARIANT* v)
96 {
97  if (!(V_VT(v) & VT_ARRAY))
98  {
99  return 0;
100  }
101  SAFEARRAY* psa = V_UNION(v,parray);
102  if (psa == NULL)
103  {
104  return 0;
105  }
106  int ndims = SafeArrayGetDim(psa);
107  if (ndims <= 0)
108  {
109  return 0;
110  }
111  long lbounds, ubounds;
112  int len = 1;
113  int i;
114  for(i=0; i<ndims; i++)
115  {
116  lbounds = ubounds = 0;
117  SafeArrayGetLBound(psa, i+1, &lbounds);
118  SafeArrayGetUBound(psa, i+1, &ubounds);
119  len *= (ubounds - lbounds + 1);
120  }
121  return len;
122 }
123 
124 int arrayVariantDimensions(VARIANT* v, int dims_array[], int& ndims)
125 {
126  ndims = 0;
127  dims_array[0] = 0;
128  if (!(V_VT(v) & VT_ARRAY))
129  {
130  return -1;
131  }
132  SAFEARRAY* psa = V_UNION(v,parray);
133  if (psa == NULL)
134  {
135  return -1;
136  }
137  ndims = SafeArrayGetDim(psa);
138  long lbounds, ubounds;
139  for(int i=0; i<ndims; i++)
140  {
141  lbounds = ubounds = 0;
142  SafeArrayGetLBound(psa, i+1, &lbounds);
143  SafeArrayGetUBound(psa, i+1, &ubounds);
144  dims_array[i] = ubounds - lbounds + 1;
145  }
146  return 0;
147 }
148 
149 template <typename T>
150 int makeVariantFromArray(VARIANT* v, const std::vector<T>& the_array)
151 {
152  return makeVariantFromArray(v, &(the_array[0]), the_array.size());
153 }
154 
155 template <>
156 int makeVariantFromArray(VARIANT* v, const std::vector<std::string>& the_array)
157 {
158  int n = the_array.size();
159  allocateArrayVariant(v, VT_BSTR, &n, 1);
160  BSTR* v_array = NULL;
161  accessArrayVariant(v, &v_array);
162  for(int i=0; i<n; ++i)
163  {
164  CComBSTR bstr_wrapper(the_array[i].c_str());
165  v_array[i] = bstr_wrapper.Detach();
166  }
168  return 0;
169 }
170 
171 
172 template <const VARTYPE vt>
173 struct CPPType
174 {
175  typedef int type;
176 };
177 
178 template <>
179 struct CPPType<VT_I4>
180 {
181  typedef int type;
182 };
183 
184 template <>
185 struct CPPType<VT_R4>
186 {
187  typedef float type;
188 };
189 
190 template <typename T>
191 int makeVariantFromArray(VARIANT* v, const T* the_array, int n)
192 {
193  VARTYPE vt_type = CVarTypeInfo<T>::VT;
194  allocateArrayVariant(v, vt_type, &n, 1);
195  T* v_array = NULL;
196  accessArrayVariant(v, &v_array);
197  for(int i=0; i<n; ++i)
198  {
199  v_array[i] = the_array[i];
200  }
202  return 0;
203 }
204 
205 template <>
206 int makeVariantFromArray(VARIANT* v, const char* the_array, int n)
207 {
208  return -1;
209 }
210 
211 template int makeVariantFromArray(VARIANT* v, const std::vector<float>& the_array);
212 
213 #if 0
214 
215 static void GenieVariableToVariant(GenieVariable& gv, VARIANT* v, const char* opt)
216 {
217  int l, i;
218  static OOP gxcominterface = typeNameToOOP("GXCominterface");
219  HRESULT hr;
220  VARTYPE vt_type;
221 
222  VariantInit(v);
223  switch(gv.type())
224  {
225  case GenieIntegerType:
226  V_VT(v) = VT_I4;
227  V_UNION(v,lVal) = (GenieInteger)gv;
228  break;
229 
230  case GenieRealType:
231  V_VT(v) = VT_R8;
232  V_UNION(v,dblVal) = (GenieReal)gv;
233  break;
234 
235  case GenieStringType:
236  V_VT(v) = VT_BSTR;
237  MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
238  (GenieString)gv, -1, olestr_buffer, MAX_OLE_SIZE);
239  V_UNION(v,bstrVal) = SysAllocString(olestr_buffer);
240  break;
241 
242  case GenieWorkspaceType:
243  {
244  GenieWorkspace& gw = (GenieWorkspace&)gv;
245  if (gw.getClass() == gxcominterface)
246  {
247  GenieIntegerArray gia = gw("value");
248  l = (GenieInteger)gw("type");
249  V_VT(v) = l;
250  switch(l)
251  {
252  case VT_UNKNOWN:
253  memcpy(&(V_UNION(v,punkVal)), (g_integer*)gia, sizeof(IUnknown*));
254  break;
255 
256  case VT_DISPATCH:
257  memcpy(&(V_UNION(v,pdispVal)), (g_integer*)gia, sizeof(IDispatch*));
258  break;
259 
260  default:
261  gerr << "DCOM: GenieVariableToVariant(workspace, unknown type) " << l << std::endl;
262  break;
263  }
264  }
265  else
266  {
267  gerr << "DCOM: Unsupported workspace type" << std::endl;
268  }
269  }
270  break;
271 
272  case GenieWorkspaceArrayType:
273  {
274  GenieWorkspaceArray& gwa = (GenieWorkspaceArray&)gv;
275  VARIANT* tmp;
276  tmp = (VARIANT*)safeArraySetup(gwa, v, VT_VARIANT);
277  if (tmp == NULL)
278  {
279  gerr << "DCOM: error" << std::endl;
280  break;
281  }
282  for(i=0; i<gwa.length(); i++)
283  {
284  GenieWorkspace gw = gwa[i];
285  GenieVariable gv = gw("value");
286  GenieVariableToVariant(gv, &tmp[i], "");
287  }
288  hr = SafeArrayUnaccessData(V_UNION(v,parray));
289  if (FAILED(hr))
290  {
291  gerr << "DCOM: failed" << std::endl;
292  }
293 
294  }
295  break;
296 
297  case GenieIntegerArrayType:
298  {
299  GenieIntegerArray& gia = (GenieIntegerArray&)gv;
300  VARIANT* tmp;
301  vt_type = (*opt == 'A' ? VT_I4 : VT_VARIANT);
302  tmp = (VARIANT*)safeArraySetup(gia, v, vt_type);
303  if (tmp == NULL)
304  {
305  gerr << "DCOM: error" << std::endl;
306  break;
307  }
308  if (vt_type == VT_VARIANT)
309  {
310  for(i=0; i<gia.length(); i++)
311  {
312  V_VT(&tmp[i]) = VT_I4;
313  V_UNION(&tmp[i],lVal) = gia[i];
314  }
315  }
316  else
317  {
318  memcpy(tmp, (g_integer*)gia, gia.length() * 4);
319  }
320  hr = SafeArrayUnaccessData(V_UNION(v,parray));
321  if (FAILED(hr))
322  {
323  gerr << "DCOM: failed" << std::endl;
324  }
325  break;
326  }
327 
328  case GenieRealArrayType:
329  {
330  GenieRealArray& gra = (GenieRealArray&)gv;
331  VARIANT* tmp;
332  vt_type = (*opt == 'A' ? VT_R8 : VT_VARIANT);
333  tmp = (VARIANT*)safeArraySetup(gra, v, vt_type);
334  if (tmp == NULL)
335  {
336  gerr << "DCOM: error" << std::endl;
337  break;
338  }
339  if (vt_type == VT_VARIANT)
340  {
341  for(i=0; i<gra.length(); i++)
342  {
343  V_VT(&tmp[i]) = VT_R8;
344  V_UNION(&tmp[i],dblVal) = gra[i];
345  }
346  }
347  else
348  {
349  memcpy(tmp, (g_real*)gra, gra.length() * 8);
350  }
351  hr = SafeArrayUnaccessData(V_UNION(v,parray));
352  if (FAILED(hr))
353  {
354  gerr << "DCOM: failed" << std::endl;
355  }
356  break;
357  }
358 
359  case GenieStringArrayType:
360  {
361  GenieStringArray& gsa = (GenieStringArray&)gv;
362  VARIANT* tmp;
363  vt_type = (*opt == 'A' ? VT_BSTR : VT_VARIANT);
364  tmp = (VARIANT*)safeArraySetup(gsa, v, vt_type);
365  if (tmp == NULL)
366  {
367  gerr << "DCOM: error" << std::endl;
368  break;
369  }
370  for(i=0; i<gsa.length(); i++)
371  {
372  MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
373  (GenieString)gsa[i], -1, olestr_buffer,
374  MAX_OLE_SIZE);
375  if (vt_type == VT_VARIANT)
376  {
377  V_VT(&tmp[i]) = VT_BSTR;
378  V_UNION(&tmp[i],bstrVal) = SysAllocString(olestr_buffer);
379  }
380  else
381  {
382  ((BSTR*)tmp)[i] = SysAllocString(olestr_buffer);
383  }
384  }
385  hr = SafeArrayUnaccessData(V_UNION(v,parray));
386  if (FAILED(hr))
387  {
388  gerr << "DCOM: failed" << std::endl;
389  }
390  break;
391  }
392 
393  default:
394  gerr << "DCOM: GenieVariableToVariant(unknown type) " << std::endl;
395  break;
396  }
397 }
398 
399 static void VariantToGenieVariable(VARIANT* v, GenieVariable& gv);
400 
401 static int getVariantArrayLength(VARIANT* v)
402 {
403  if (!(V_VT(v) & VT_ARRAY))
404  {
405  return 0;
406  }
407  SAFEARRAY* psa = V_UNION(v,parray);
408  if (psa == NULL)
409  {
410  return 0;
411  }
412  int ndims = SafeArrayGetDim(psa);
413  long lbounds, ubounds;
414  int len = 1;
415  int i;
416  for(i=0; i<ndims; i++)
417  {
418  lbounds = ubounds = 0;
419  SafeArrayGetLBound(psa, i+1, &lbounds);
420  SafeArrayGetUBound(psa, i+1, &ubounds);
421  len *= (ubounds - lbounds + 1);
422  }
423  return len;
424 }
425 
426 static void VariantToGenieVariableArray(VARIANT* v, GenieVariable& gv)
427 {
428  SAFEARRAY* psa = V_UNION(v,parray); // *(v->pparray) ????
429  if (psa == NULL)
430  {
431  gerr << "DCOM: VariantToGenieVariableArray error" << std::endl;
432  return;
433  }
434  int ndims = SafeArrayGetDim(psa);
435  long *lbounds = new long[ndims];
436  long *ubounds = new long[ndims];
437  int* dims_array = new int[ndims];
438  int len = 1;
439  int i, j, l;
440  HRESULT hr;
441  for(i=0; i<ndims; i++)
442  {
443  SafeArrayGetLBound(psa, i+1, lbounds+i);
444  SafeArrayGetUBound(psa, i+1, ubounds+i);
445  dims_array[ndims - i - 1] = ubounds[i] - lbounds[i] + 1;
446  len *= dims_array[ndims - i - 1];
447  }
448 // check for variable type mismatch specified in array
449  VARTYPE vt, vvt;
450  vvt = (V_VT(v) & ~VT_ARRAY);
451  void *pdata = NULL;
452 #if !defined(__VMS)
453  hr = SafeArrayGetVartype(psa, &vt);
454  if ( FAILED(hr) || (vt != vvt) )
455  {
456  gerr << "DCOM: VariantToGenieVariableArray - possible data type mismatch?" << std::endl;
457  return;
458  }
459 #else
460  vt = vvt;
461 #endif /* !defined(__VMS) */
462  hr = SafeArrayAccessData(psa, &pdata);
463  if ( FAILED(hr) || (pdata == NULL) )
464  {
465  gerr << "DCOM: error" << std::endl;
466  return;
467  }
468  GenieIntegerArray* gia;
469  GenieRealArray* gra;
470  GenieStringArray *gsa;
471  GenieWorkspaceArray *gwa;
472  VARIANT *pv;
473  if (vt == VT_VARIANT)
474  {
475 // ginf << "Variant Array length " << len << std::endl;
476  gwa = new GenieWorkspaceArray(len);
477  for(i=0; i<len; i++)
478  {
479  pv = (VARIANT*)pdata + i;
480  GenieVariable gvv;
481  VariantToGenieVariable(pv, gvv);
482  GenieWorkspace gw;
483  gw("value", gvv.value());
484  (*gwa)(i, gw);
485  }
486  gv.newType(GenieWorkspaceArrayType, gwa->value());
487  }
488  else
489  {
490 // ginf << "Normal array length " << len << " type " << vt << std::endl;
491 // int elmsize = SafeArrayGetElemsize(psa);
492 // gerr << "element size = " << elmsize << std::endl;
493  switch(vt)
494  {
495 // case VT_UI1:
496 // case VT_I2:
497 // case VT_UI2:
498 // case VT_BOOL:
499 
500  case VT_I4:
501  case VT_UI4:
502  gia = new GenieIntegerArray((long*)pdata, dims_array, ndims);
503  gv.newType(GenieIntegerArrayType, gia->value());
504  break;
505 
506 
507  case VT_INT:
508  case VT_UINT:
509  gia = new GenieIntegerArray((int*)pdata, dims_array, ndims);
510  gv.newType(GenieIntegerArrayType, gia->value());
511  break;
512 
513  case VT_R4:
514  gra = new GenieRealArray((float*)pdata, dims_array, ndims);
515  gv.newType(GenieRealArrayType, gra->value());
516  break;
517 
518  case VT_R8:
519  gra = new GenieRealArray((double*)pdata, dims_array, ndims);
520  gv.newType(GenieRealArrayType, gra->value());
521  break;
522 
523  case VT_BSTR:
524  gsa = new GenieStringArray(dims_array, ndims);
525  BSTR* pBstr;
526  for(i=0; i<len; i++)
527  {
528  pBstr = (BSTR*)pdata + i;
529  l = SysStringLen(*pBstr);
530  j = WideCharToMultiByte(CP_ACP, 0, *pBstr, l,
531  str_buffer, MAX_OLE_SIZE, NULL, NULL);
532  str_buffer[j] = '\0';
533  (*gsa)(i, str_buffer);
534  }
535  gv.newType(GenieStringArrayType, gsa->value());
536  break;
537 
538  default:
539  gerr << "VariantToGenieVariableArray(unknown type) " << vt << std::endl;
540  break;
541  }
542  }
543  SafeArrayUnaccessData(psa);
544  delete []dims_array;
545  delete []ubounds;
546  delete []lbounds;
547 }
548 
549 static void VariantToGenieVariable(VARIANT* v, GenieVariable& gv)
550 {
551  int i, l;
552  VARIANT temp_v;
553  iunk_item iunk;
554  idisp_item idsp;
555  VariantInit(&temp_v);
556  GenieIntegerArray gia(2);
557  if (V_VT(v) & VT_ARRAY)
558  {
559 // ginf << "DCOM: got array" << std::endl;
560  VariantToGenieVariableArray(v, gv);
561  return;
562  }
563  switch(V_VT(v))
564  {
565  case VT_EMPTY:
566  break;
567 
568  case VT_I1:
569  case VT_UI1:
570  case VT_I2:
571  case VT_UI2:
572  case VT_I4:
573  case VT_UI4:
574  case VT_INT:
575  case VT_UINT:
576  {
577  GenieInteger gi;
578  VariantChangeType(&temp_v, v, 0, VT_I4);
579  gi = V_UNION(&temp_v,lVal);
580  gv.newType(GenieIntegerType, gi);
581  break;
582  }
583 
584  case VT_BOOL:
585  {
586  GenieInteger gi;
587  gi = (V_UNION(v,boolVal) != 0 ? 1 : 0);
588  gv.newType(GenieIntegerType, gi);
589  break;
590  }
591 
592  case VT_R4:
593  case VT_R8:
594  {
595  GenieReal gr;
596  VariantChangeType(&temp_v, v, 0, VT_R8);
597  gr = V_UNION(&temp_v,dblVal);
598  gv.newType(GenieRealType, gr);
599  break;
600  }
601  case VT_BSTR:
602  {
603  GenieString gs;
604  l = SysStringLen(V_UNION(v,bstrVal));
605  i = WideCharToMultiByte(CP_ACP, 0, V_UNION(v,bstrVal), l,
606  str_buffer, MAX_OLE_SIZE, NULL, NULL);
607  str_buffer[i] = '\0';
608  gs = str_buffer;
609  gv.newType(GenieStringType, gs);
610  break;
611  }
612 
613  case VT_UNKNOWN:
614  {
615  GenieWorkspace gw("GXCominterface");
616  gia((g_integer*)&(V_UNION(v,punkVal)), sizeof(IUnknown*) / sizeof(g_integer));
617  gw("name", "IUnknown");
618  gw("type", VT_UNKNOWN);
619  gw("value", gia);
620  gv.newType(GenieWorkspaceType, gw);
621  iunk_list.push(iunk_item(V_UNION(v,punkVal)));
622  break;
623  }
624 
625  case VT_DISPATCH:
626  {
627  GenieWorkspace gw("GXCominterface");
628  gia((g_integer*)&(V_UNION(v,pdispVal)), sizeof(IDispatch*) / sizeof(g_integer));
629  gw("name", "IDispatch");
630  gw("type", VT_DISPATCH);
631  gw("value", gia);
632  gv.newType(GenieWorkspaceType, gw);
633  idisp_list.push(idisp_item(V_UNION(v,pdispVal), 0));
634  break;
635  }
636 
637 
638  default:
639  gerr << "DCOM: VariantToGenieVariable(unknown type) " << V_VT(v) << std::endl;
640  break;
641  }
642 }
643 
644 
645 
646 static void DCOMCleanupVariant(VARIANT* v)
647 {
648  VARTYPE vt, vvt;
649  HRESULT hr;
650  VARIANT* pv = NULL;
651  int i, len;
652  vvt = V_VT(v);
653  vt = (vvt & ~VT_ARRAY);
654  if ( (vvt & VT_ARRAY) && (vt == VT_VARIANT) )
655  {
656  SAFEARRAY* psa = V_UNION(v,parray);
657  len = getVariantArrayLength(v);
658  hr = SafeArrayAccessData(psa, (void**)&pv);
659  if ( SUCCEEDED(hr) && (pv != NULL) )
660  {
661  for(i=0; i<len; i++)
662  {
663  DCOMCleanupVariant(pv + i);
664  }
665  SafeArrayUnaccessData(psa);
666  }
667  VariantClear(v); // now free up array itself
668  return;
669  }
670  switch(vt)
671  {
672  case VT_EMPTY:
673  case VT_R4:
674  case VT_R8:
675  case VT_I1:
676  case VT_UI1:
677  case VT_I2:
678  case VT_UI2:
679  case VT_I4:
680  case VT_UI4:
681  case VT_INT:
682  case VT_UINT:
683  case VT_BOOL:
684  case VT_BSTR:
685  VariantClear(v); // free contents and mark as empty
686  break;
687 
688  case VT_DISPATCH:
689  case VT_UNKNOWN:
690  VariantInit(v); // mark it as empty so it doesn't get freed
691  break;
692 
693  default:
694  gerr << "DCOM: CleanupVariant(unknown type) " << V_VT(v)<< "/" << vt << std::endl;
695  break;
696  }
697 }
698 
699 #endif
int allocateArrayVariant(VARIANT *v, VARTYPE v_type, int *dims_array, int ndims)
static int accessArrayVariant(VARIANT *v, void **values, VARTYPE vt)
int arrayVariantLength(VARIANT *v)
int arrayVariantDimensions(VARIANT *v, int dims_array[], int &ndims)
int unaccessArrayVariant(VARIANT *v)
static std::string com_message(const std::string &message, HRESULT hr)
int makeVariantFromArray(VARIANT *v, const std::vector< T > &the_array)