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