oledb32: Implement conversions to DBTYPE_BSTR.
[wine] / dlls / oledb32 / convert.c
1 /* OLE DB Conversion library
2  *
3  * Copyright 2009 Huw Davies
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include <stdarg.h>
21
22 #define COBJMACROS
23 #define NONAMELESSUNION
24 #define NONAMELESSSTRUCT
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "ole2.h"
30 #include "msdadc.h"
31 #include "oledberr.h"
32
33 #include "oledb_private.h"
34
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(oledb);
38
39 typedef struct
40 {
41     const struct IDataConvertVtbl *lpVtbl;
42     const struct IDCInfoVtbl *lpDCInfoVtbl;
43
44     LONG ref;
45
46     UINT version; /* Set by IDCInfo_SetInfo */
47 } convert;
48
49 static inline convert *impl_from_IDataConvert(IDataConvert *iface)
50 {
51     return (convert *)((char*)iface - FIELD_OFFSET(convert, lpVtbl));
52 }
53
54 static inline convert *impl_from_IDCInfo(IDCInfo *iface)
55 {
56     return (convert *)((char*)iface - FIELD_OFFSET(convert, lpDCInfoVtbl));
57 }
58
59 static HRESULT WINAPI convert_QueryInterface(IDataConvert* iface,
60                                              REFIID riid,
61                                              void **obj)
62 {
63     convert *This = impl_from_IDataConvert(iface);
64     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
65
66     *obj = NULL;
67
68     if(IsEqualIID(riid, &IID_IUnknown) ||
69        IsEqualIID(riid, &IID_IDataConvert))
70     {
71         *obj = iface;
72     }
73     else if(IsEqualIID(riid, &IID_IDCInfo))
74     {
75         *obj = &This->lpDCInfoVtbl;
76     }
77     else
78     {
79         FIXME("interface %s not implemented\n", debugstr_guid(riid));
80         return E_NOINTERFACE;
81     }
82
83     IDataConvert_AddRef(iface);
84     return S_OK;
85 }
86
87
88 static ULONG WINAPI convert_AddRef(IDataConvert* iface)
89 {
90     convert *This = impl_from_IDataConvert(iface);
91     TRACE("(%p)\n", This);
92
93     return InterlockedIncrement(&This->ref);
94 }
95
96
97 static ULONG WINAPI convert_Release(IDataConvert* iface)
98 {
99     convert *This = impl_from_IDataConvert(iface);
100     LONG ref;
101
102     TRACE("(%p)\n", This);
103
104     ref = InterlockedDecrement(&This->ref);
105     if(ref == 0)
106     {
107         HeapFree(GetProcessHeap(), 0, This);
108     }
109
110     return ref;
111 }
112
113 static int get_length(DBTYPE type)
114 {
115     switch(type)
116     {
117     case DBTYPE_I1:
118     case DBTYPE_UI1:
119         return 1;
120     case DBTYPE_I2:
121     case DBTYPE_UI2:
122         return 2;
123     case DBTYPE_I4:
124     case DBTYPE_UI4:
125         return 4;
126     case DBTYPE_I8:
127     case DBTYPE_UI8:
128         return 8;
129     case DBTYPE_BSTR:
130         return sizeof(BSTR);
131     default:
132         FIXME("Unhandled type %04x\n", type);
133         return 0;
134     }
135 }
136
137 static HRESULT WINAPI convert_DataConvert(IDataConvert* iface,
138                                           DBTYPE src_type, DBTYPE dst_type,
139                                           DBLENGTH src_len, DBLENGTH *dst_len,
140                                           void *src, void *dst,
141                                           DBLENGTH dst_max_len,
142                                           DBSTATUS src_status, DBSTATUS *dst_status,
143                                           BYTE precision, BYTE scale,
144                                           DBDATACONVERT flags)
145 {
146     convert *This = impl_from_IDataConvert(iface);
147     HRESULT hr;
148
149     TRACE("(%p)->(%d, %d, %d, %p, %p, %p, %d, %d, %p, %d, %d, %x)\n", This,
150           src_type, dst_type, src_len, dst_len, src, dst, dst_max_len,
151           src_status, dst_status, precision, scale, flags);
152
153     *dst_len = get_length(dst_type);
154     *dst_status = DBSTATUS_E_BADACCESSOR;
155
156     if(IDataConvert_CanConvert(iface, src_type, dst_type) != S_OK)
157     {
158         return DB_E_UNSUPPORTEDCONVERSION;
159     }
160
161     if(src_type == DBTYPE_STR)
162     {
163         BSTR b;
164         DWORD len;
165
166         if(flags & DBDATACONVERT_LENGTHFROMNTS)
167             len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0) - 1;
168         else
169             len = MultiByteToWideChar(CP_ACP, 0, src, src_len, NULL, 0);
170         b = SysAllocStringLen(NULL, len);
171         if(!b) return E_OUTOFMEMORY;
172         if(flags & DBDATACONVERT_LENGTHFROMNTS)
173             MultiByteToWideChar(CP_ACP, 0, src, -1, b, len + 1);
174         else
175             MultiByteToWideChar(CP_ACP, 0, src, src_len, b, len);
176
177         hr = IDataConvert_DataConvert(iface, DBTYPE_BSTR, dst_type, 0, dst_len,
178                                       &b, dst, dst_max_len, src_status, dst_status,
179                                       precision, scale, flags);
180
181         SysFreeString(b);
182         return hr;
183     }
184
185     if(src_type == DBTYPE_WSTR)
186     {
187         BSTR b;
188
189         if(flags & DBDATACONVERT_LENGTHFROMNTS)
190             b = SysAllocString(src);
191         else
192             b = SysAllocStringLen(src, src_len / 2);
193         if(!b) return E_OUTOFMEMORY;
194         hr = IDataConvert_DataConvert(iface, DBTYPE_BSTR, dst_type, 0, dst_len,
195                                       &b, dst, dst_max_len, src_status, dst_status,
196                                       precision, scale, flags);
197         SysFreeString(b);
198         return hr;
199     }
200
201     switch(dst_type)
202     {
203     case DBTYPE_I2:
204     {
205         signed short *d = dst;
206         switch(src_type)
207         {
208         case DBTYPE_EMPTY:       *d = 0; hr = S_OK;                              break;
209         case DBTYPE_I2:          *d = *(signed short*)src; hr = S_OK;            break;
210         case DBTYPE_I4:          hr = VarI2FromI4(*(signed int*)src, d);         break;
211         case DBTYPE_R4:          hr = VarI2FromR4(*(FLOAT*)src, d);              break;
212         case DBTYPE_R8:          hr = VarI2FromR8(*(double*)src, d);             break;
213         case DBTYPE_CY:          hr = VarI2FromCy(*(CY*)src, d);                 break;
214         case DBTYPE_DATE:        hr = VarI2FromDate(*(DATE*)src, d);             break;
215         case DBTYPE_BSTR:        hr = VarI2FromStr(*(WCHAR**)src, LOCALE_USER_DEFAULT, 0, d); break;
216         case DBTYPE_BOOL:        hr = VarI2FromBool(*(VARIANT_BOOL*)src, d);     break;
217         case DBTYPE_DECIMAL:     hr = VarI2FromDec((DECIMAL*)src, d);            break;
218         case DBTYPE_I1:          hr = VarI2FromI1(*(signed char*)src, d);        break;
219         case DBTYPE_UI1:         hr = VarI2FromUI1(*(BYTE*)src, d);              break;
220         case DBTYPE_UI2:         hr = VarI2FromUI2(*(WORD*)src, d);              break;
221         case DBTYPE_UI4:         hr = VarI2FromUI4(*(DWORD*)src, d);             break;
222         case DBTYPE_I8:          hr = VarI2FromI8(*(LONGLONG*)src, d);           break;
223         case DBTYPE_UI8:         hr = VarI2FromUI8(*(ULONGLONG*)src, d);         break;
224         default: FIXME("Unimplemented conversion %04x -> I2\n", src_type); return E_NOTIMPL;
225         }
226         break;
227     }
228
229     case DBTYPE_I4:
230     {
231         signed int *d = dst;
232         switch(src_type)
233         {
234         case DBTYPE_EMPTY:       *d = 0; hr = S_OK;                              break;
235         case DBTYPE_I2:          hr = VarI4FromI2(*(signed short*)src, d);       break;
236         case DBTYPE_I4:          *d = *(signed int*)src; hr = S_OK;              break;
237         case DBTYPE_R4:          hr = VarI4FromR4(*(FLOAT*)src, d);              break;
238         case DBTYPE_R8:          hr = VarI4FromR8(*(double*)src, d);             break;
239         case DBTYPE_CY:          hr = VarI4FromCy(*(CY*)src, d);                 break;
240         case DBTYPE_DATE:        hr = VarI4FromDate(*(DATE*)src, d);             break;
241         case DBTYPE_BSTR:        hr = VarI4FromStr(*(WCHAR**)src, LOCALE_USER_DEFAULT, 0, d); break;
242         case DBTYPE_BOOL:        hr = VarI4FromBool(*(VARIANT_BOOL*)src, d);     break;
243         case DBTYPE_DECIMAL:     hr = VarI4FromDec((DECIMAL*)src, d);            break;
244         case DBTYPE_I1:          hr = VarI4FromI1(*(signed char*)src, d);        break;
245         case DBTYPE_UI1:         hr = VarI4FromUI1(*(BYTE*)src, d);              break;
246         case DBTYPE_UI2:         hr = VarI4FromUI2(*(WORD*)src, d);              break;
247         case DBTYPE_UI4:         hr = VarI4FromUI4(*(DWORD*)src, d);             break;
248         case DBTYPE_I8:          hr = VarI4FromI8(*(LONGLONG*)src, d);           break;
249         case DBTYPE_UI8:         hr = VarI4FromUI8(*(ULONGLONG*)src, d);         break;
250         default: FIXME("Unimplemented conversion %04x -> I4\n", src_type); return E_NOTIMPL;
251         }
252         break;
253     }
254
255     case DBTYPE_BSTR:
256     {
257         BSTR *d = dst;
258         switch(src_type)
259         {
260         case DBTYPE_EMPTY:       *d = SysAllocStringLen(NULL, 0); hr = *d ? S_OK : E_OUTOFMEMORY;      break;
261         case DBTYPE_I2:          hr = VarBstrFromI2(*(signed short*)src, LOCALE_USER_DEFAULT, 0, d);   break;
262         case DBTYPE_I4:          hr = VarBstrFromI4(*(signed int*)src, LOCALE_USER_DEFAULT, 0, d);     break;
263         case DBTYPE_R4:          hr = VarBstrFromR4(*(FLOAT*)src, LOCALE_USER_DEFAULT, 0, d);          break;
264         case DBTYPE_R8:          hr = VarBstrFromR8(*(double*)src, LOCALE_USER_DEFAULT, 0, d);         break;
265         case DBTYPE_CY:          hr = VarBstrFromCy(*(CY*)src, LOCALE_USER_DEFAULT, 0, d);             break;
266         case DBTYPE_DATE:        hr = VarBstrFromDate(*(DATE*)src, LOCALE_USER_DEFAULT, 0, d);         break;
267         case DBTYPE_BSTR:        *d = SysAllocStringLen(*(BSTR*)src, SysStringLen(*(BSTR*)src)); hr = *d ? S_OK : E_OUTOFMEMORY;     break;
268         case DBTYPE_BOOL:        hr = VarBstrFromBool(*(VARIANT_BOOL*)src, LOCALE_USER_DEFAULT, 0, d); break;
269         case DBTYPE_DECIMAL:     hr = VarBstrFromDec((DECIMAL*)src, LOCALE_USER_DEFAULT, 0, d);        break;
270         case DBTYPE_I1:          hr = VarBstrFromI1(*(signed char*)src, LOCALE_USER_DEFAULT, 0, d);    break;
271         case DBTYPE_UI1:         hr = VarBstrFromUI1(*(BYTE*)src, LOCALE_USER_DEFAULT, 0, d);          break;
272         case DBTYPE_UI2:         hr = VarBstrFromUI2(*(WORD*)src, LOCALE_USER_DEFAULT, 0, d);          break;
273         case DBTYPE_UI4:         hr = VarBstrFromUI4(*(DWORD*)src, LOCALE_USER_DEFAULT, 0, d);         break;
274         case DBTYPE_I8:          hr = VarBstrFromI8(*(LONGLONG*)src, LOCALE_USER_DEFAULT, 0, d);       break;
275         case DBTYPE_UI8:         hr = VarBstrFromUI8(*(ULONGLONG*)src, LOCALE_USER_DEFAULT, 0, d);     break;
276         default: FIXME("Unimplemented conversion %04x -> BSTR\n", src_type); return E_NOTIMPL;
277         }
278         break;
279     }
280     default:
281         FIXME("Unimplemented conversion %04x -> %04x\n", src_type, dst_type);
282         return E_NOTIMPL;
283
284     }
285
286     if(hr == DISP_E_OVERFLOW)
287     {
288         *dst_status = DBSTATUS_E_DATAOVERFLOW;
289         hr = DB_E_ERRORSOCCURRED;
290     }
291     else if(hr == S_OK)
292         *dst_status = DBSTATUS_S_OK;
293
294     return hr;
295 }
296
297 static inline WORD get_dbtype_class(DBTYPE type)
298 {
299     switch(type)
300     {
301     case DBTYPE_I2:
302     case DBTYPE_R4:
303     case DBTYPE_R8:
304     case DBTYPE_I1:
305     case DBTYPE_UI1:
306     case DBTYPE_UI2:
307         return DBTYPE_I2;
308
309     case DBTYPE_I4:
310     case DBTYPE_UI4:
311         return DBTYPE_I4;
312
313     case DBTYPE_I8:
314     case DBTYPE_UI8:
315         return DBTYPE_I8;
316
317     case DBTYPE_BSTR:
318     case DBTYPE_STR:
319     case DBTYPE_WSTR:
320         return DBTYPE_BSTR;
321
322     case DBTYPE_DBDATE:
323     case DBTYPE_DBTIME:
324     case DBTYPE_DBTIMESTAMP:
325         return DBTYPE_DBDATE;
326     }
327     return type;
328 }
329
330 /* Many src types will convert to this group of dst types */
331 static inline BOOL common_class(WORD dst_class)
332 {
333     switch(dst_class)
334     {
335     case DBTYPE_EMPTY:
336     case DBTYPE_NULL:
337     case DBTYPE_I2:
338     case DBTYPE_I4:
339     case DBTYPE_BSTR:
340     case DBTYPE_BOOL:
341     case DBTYPE_VARIANT:
342     case DBTYPE_I8:
343     case DBTYPE_CY:
344     case DBTYPE_DECIMAL:
345     case DBTYPE_NUMERIC:
346         return TRUE;
347     }
348     return FALSE;
349 }
350
351 static inline BOOL array_type(DBTYPE type)
352 {
353     return (type >= DBTYPE_I2 && type <= DBTYPE_UI4);
354 }
355
356 static HRESULT WINAPI convert_CanConvert(IDataConvert* iface,
357                                          DBTYPE src_type, DBTYPE dst_type)
358 {
359     convert *This = impl_from_IDataConvert(iface);
360     DBTYPE src_base_type = src_type & 0x1ff;
361     DBTYPE dst_base_type = dst_type & 0x1ff;
362     WORD dst_class = get_dbtype_class(dst_base_type);
363
364     TRACE("(%p)->(%d, %d)\n", This, src_type, dst_type);
365
366     if(src_type & DBTYPE_VECTOR || dst_type & DBTYPE_VECTOR) return S_FALSE;
367
368     if(src_type & DBTYPE_ARRAY)
369     {
370         if(!array_type(src_base_type)) return S_FALSE;
371         if(dst_type & DBTYPE_ARRAY)
372         {
373             if(src_type == dst_type) return S_OK;
374             return S_FALSE;
375         }
376         if(dst_type == DBTYPE_VARIANT) return S_OK;
377         return S_FALSE;
378     }
379
380     if(dst_type & DBTYPE_ARRAY)
381     {
382         if(!array_type(dst_base_type)) return S_FALSE;
383         if(src_type == DBTYPE_IDISPATCH || src_type == DBTYPE_VARIANT) return S_OK;
384         return S_FALSE;
385     }
386
387     if(dst_type & DBTYPE_BYREF)
388         if(dst_base_type != DBTYPE_BYTES && dst_base_type != DBTYPE_STR && dst_base_type != DBTYPE_WSTR)
389             return S_FALSE;
390
391     switch(get_dbtype_class(src_base_type))
392     {
393     case DBTYPE_EMPTY:
394         if(common_class(dst_class)) return S_OK;
395         switch(dst_class)
396         {
397         case DBTYPE_DATE:
398         case DBTYPE_GUID:
399             return S_OK;
400         default:
401             if(dst_base_type == DBTYPE_DBTIMESTAMP) return S_OK;
402             return S_FALSE;
403         }
404
405     case DBTYPE_NULL:
406         switch(dst_base_type)
407         {
408         case DBTYPE_NULL:
409         case DBTYPE_VARIANT: return S_OK;
410         default: return S_FALSE;
411         }
412
413     case DBTYPE_I4:
414         if(dst_base_type == DBTYPE_BYTES) return S_OK;
415         /* fall through */
416     case DBTYPE_I2:
417         if(dst_base_type == DBTYPE_DATE) return S_OK;
418         /* fall through */
419     case DBTYPE_DECIMAL:
420         if(common_class(dst_class)) return S_OK;
421         if(dst_class == DBTYPE_DBDATE) return S_OK;
422         return S_FALSE;
423
424     case DBTYPE_BOOL:
425         if(dst_base_type == DBTYPE_DATE) return S_OK;
426     case DBTYPE_NUMERIC:
427     case DBTYPE_CY:
428         if(common_class(dst_class)) return S_OK;
429         return S_FALSE;
430
431     case DBTYPE_I8:
432         if(common_class(dst_class)) return S_OK;
433         if(dst_base_type == DBTYPE_BYTES) return S_OK;
434         return S_FALSE;
435
436     case DBTYPE_DATE:
437         switch(dst_class)
438         {
439         case DBTYPE_EMPTY:
440         case DBTYPE_NULL:
441         case DBTYPE_I2:
442         case DBTYPE_I4:
443         case DBTYPE_BSTR:
444         case DBTYPE_BOOL:
445         case DBTYPE_VARIANT:
446         case DBTYPE_I8:
447         case DBTYPE_DATE:
448         case DBTYPE_DBDATE:
449             return S_OK;
450         default: return S_FALSE;
451         }
452
453     case DBTYPE_IDISPATCH:
454     case DBTYPE_VARIANT:
455         switch(dst_base_type)
456         {
457         case DBTYPE_IDISPATCH:
458         case DBTYPE_ERROR:
459         case DBTYPE_IUNKNOWN:
460             return S_OK;
461         }
462         /* fall through */
463     case DBTYPE_BSTR:
464         if(common_class(dst_class)) return S_OK;
465         switch(dst_class)
466         {
467         case DBTYPE_DATE:
468         case DBTYPE_GUID:
469         case DBTYPE_BYTES:
470         case DBTYPE_DBDATE:
471             return S_OK;
472         default: return S_FALSE;
473         }
474
475     case DBTYPE_ERROR:
476         switch(dst_base_type)
477         {
478         case DBTYPE_BSTR:
479         case DBTYPE_ERROR:
480         case DBTYPE_VARIANT:
481         case DBTYPE_WSTR:
482             return S_OK;
483         default: return S_FALSE;
484         }
485
486     case DBTYPE_IUNKNOWN:
487         switch(dst_base_type)
488         {
489         case DBTYPE_EMPTY:
490         case DBTYPE_NULL:
491         case DBTYPE_IDISPATCH:
492         case DBTYPE_VARIANT:
493         case DBTYPE_IUNKNOWN:
494             return S_OK;
495         default: return S_FALSE;
496         }
497
498     case DBTYPE_BYTES:
499         if(dst_class == DBTYPE_I4 || dst_class == DBTYPE_I8) return S_OK;
500         /* fall through */
501     case DBTYPE_GUID:
502         switch(dst_class)
503         {
504         case DBTYPE_EMPTY:
505         case DBTYPE_NULL:
506         case DBTYPE_BSTR:
507         case DBTYPE_VARIANT:
508         case DBTYPE_GUID:
509         case DBTYPE_BYTES:
510             return S_OK;
511         default: return S_FALSE;
512         }
513
514     case DBTYPE_DBDATE:
515         switch(dst_class)
516         {
517         case DBTYPE_EMPTY:
518         case DBTYPE_NULL:
519         case DBTYPE_DATE:
520         case DBTYPE_BSTR:
521         case DBTYPE_VARIANT:
522         case DBTYPE_DBDATE:
523             return S_OK;
524         default: return S_FALSE;
525         }
526
527     }
528     return S_FALSE;
529 }
530
531 static HRESULT WINAPI convert_GetConversionSize(IDataConvert* iface,
532                                                 DBTYPE wSrcType, DBTYPE wDstType,
533                                                 DBLENGTH *pcbSrcLength, DBLENGTH *pcbDstLength,
534                                                 void *pSrc)
535 {
536     convert *This = impl_from_IDataConvert(iface);
537     FIXME("(%p)->(%d, %d, %p, %p, %p): stub\n", This, wSrcType, wDstType, pcbSrcLength, pcbDstLength, pSrc);
538
539     return E_NOTIMPL;
540 }
541
542 static const struct IDataConvertVtbl convert_vtbl =
543 {
544     convert_QueryInterface,
545     convert_AddRef,
546     convert_Release,
547     convert_DataConvert,
548     convert_CanConvert,
549     convert_GetConversionSize
550 };
551
552 static HRESULT WINAPI dcinfo_QueryInterface(IDCInfo* iface, REFIID riid, void **obj)
553 {
554     convert *This = impl_from_IDCInfo(iface);
555
556     return IDataConvert_QueryInterface((IDataConvert *)This, riid, obj);
557 }
558
559 static ULONG WINAPI dcinfo_AddRef(IDCInfo* iface)
560 {
561     convert *This = impl_from_IDCInfo(iface);
562
563     return IDataConvert_AddRef((IDataConvert *)This);
564 }
565
566 static ULONG WINAPI dcinfo_Release(IDCInfo* iface)
567 {
568     convert *This = impl_from_IDCInfo(iface);
569
570     return IDataConvert_Release((IDataConvert *)This);
571 }
572
573 static HRESULT WINAPI dcinfo_GetInfo(IDCInfo *iface, ULONG num, DCINFOTYPE types[], DCINFO **info_ptr)
574 {
575     convert *This = impl_from_IDCInfo(iface);
576     ULONG i;
577     DCINFO *infos;
578
579     TRACE("(%p)->(%d, %p, %p)\n", This, num, types, info_ptr);
580
581     *info_ptr = infos = CoTaskMemAlloc(num * sizeof(*infos));
582     if(!infos) return E_OUTOFMEMORY;
583
584     for(i = 0; i < num; i++)
585     {
586         infos[i].eInfoType = types[i];
587         VariantInit(&infos[i].vData);
588
589         switch(types[i])
590         {
591         case DCINFOTYPE_VERSION:
592             V_VT(&infos[i].vData) = VT_UI4;
593             V_UI4(&infos[i].vData) = This->version;
594             break;
595         }
596     }
597
598     return S_OK;
599 }
600
601 static HRESULT WINAPI dcinfo_SetInfo(IDCInfo* iface, ULONG num, DCINFO info[])
602 {
603     convert *This = impl_from_IDCInfo(iface);
604     ULONG i;
605     HRESULT hr = S_OK;
606
607     TRACE("(%p)->(%d, %p)\n", This, num, info);
608
609     for(i = 0; i < num; i++)
610     {
611         switch(info[i].eInfoType)
612         {
613         case DCINFOTYPE_VERSION:
614             if(V_VT(&info[i].vData) != VT_UI4)
615             {
616                 FIXME("VERSION with vt %x\n", V_VT(&info[i].vData));
617                 hr = DB_S_ERRORSOCCURRED;
618                 break;
619             }
620             This->version = V_UI4(&info[i].vData);
621             break;
622
623         default:
624             FIXME("Unhandled info type %d (vt %x)\n", info[i].eInfoType, V_VT(&info[i].vData));
625         }
626     }
627     return hr;
628 }
629
630 static const struct IDCInfoVtbl dcinfo_vtbl =
631 {
632     dcinfo_QueryInterface,
633     dcinfo_AddRef,
634     dcinfo_Release,
635     dcinfo_GetInfo,
636     dcinfo_SetInfo
637 };
638
639 HRESULT create_oledb_convert(IUnknown *outer, void **obj)
640 {
641     convert *This;
642
643     TRACE("(%p, %p)\n", outer, obj);
644
645     *obj = NULL;
646
647     if(outer) return CLASS_E_NOAGGREGATION;
648
649     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
650     if(!This) return E_OUTOFMEMORY;
651
652     This->lpVtbl = &convert_vtbl;
653     This->lpDCInfoVtbl = &dcinfo_vtbl;
654     This->ref = 1;
655     This->version = 0x110;
656
657     *obj = &This->lpVtbl;
658
659     return S_OK;
660 }