#include "Ole.h" #if defined(PLATFORM_WIN32) && defined(COMPILER_MSC) namespace Upp { ////////////////////////////////////////////////////////////////////// // GUID GUID GetCoClassGUID(const char *name, bool prog_id) { OleBstr uni = String(name); GUID guid; Zero(guid); if(prog_id && *name != '{') CLSIDFromProgID(~uni, &guid); else CLSIDFromString(~uni, &guid); return guid; } unsigned GetHashValue(const GUID& guid) { const dword *p = reinterpret_cast(&guid); return CombineHash(p[0], p[1], p[2], p[3]); } String Format(const GUID& guid) { String result; wchar_t buffer[128]; int length; if((length = StringFromGUID2(guid, buffer, __countof(buffer))) > 0) result = AsString(buffer, length - 1); return result; } String CFormat(const GUID& guid) { String value = Format("{ 0x%08x, 0x%04x, 0x%04x, { ", (int)guid.Data1, (int)guid.Data2, (int)guid.Data3); for(int i = 0; i < 8; i++) value << Format("0x%02x, ", guid.Data4[i]); return value << "} }"; } String GetInterfaceName(const GUID& guid) { if(IsNull(Guid(guid))) return Null; String goo = Format(guid); return Nvl(GetWinRegString(NULL, "Interface\\" + goo, HKEY_CLASSES_ROOT), goo); } String GetCoClassName(const GUID& guid) { if(IsNull(Guid(guid))) return Null; String goo = Format(guid); return Nvl(GetWinRegString(NULL, "CLSID\\" + goo + "\\ProgID", HKEY_CLASSES_ROOT), goo); } String GetDisplayName(const GUID& guid) { if(IsNull(Guid(guid))) return Null; String goo = Format(guid); return Nvl(GetWinRegString(NULL, "CLSID\\" + goo, HKEY_CLASSES_ROOT), goo); } bool Guid::IsNullInstance() const { const dword *p = reinterpret_cast(&guid); return (p[0] | p[1] | p[2] | p[3]) == 0; } ////////////////////////////////////////////////////////////////////// // VARIANT Value AsValue(const VARIANT& variant) { switch(variant.vt) { case VT_ERROR: return ErrorValue(GetErrorMessage(variant.scode)); case VT_EMPTY: return Value(); // void case VT_NULL: return Null; case VT_BOOL: case VT_UI1: return (int)variant.bVal; case VT_I2: return (int)variant.iVal; case VT_I4: return (int)variant.lVal; case VT_R4: return variant.fltVal; case VT_R8: return variant.dblVal; case VT_CY: return GetCurrency(variant.cyVal); case VT_DATE: return FromDATE(variant.date); case VT_BSTR: return BSTRToWString(variant.bstrVal); case VT_DECIMAL: { const DECIMAL& d = variant.decVal; double h = (d.Lo32 + d.Mid32 * (65536.0 * 65536.0)) * pow(0.1, d.scale); return d.sign ? -h : h; } case VT_ARRAY | VT_UI1: { int nelem = variant.parray->rgsabound[0].cElements; void *bits = 0; if(SUCCEEDED(SafeArrayAccessData(variant.parray, &bits)) && bits) { String out((const char *)bits, nelem); SafeArrayUnaccessData(variant.parray); return out; } break; } } return ErrorValue(Format("Unknown variant type %d", variant.vt)); } OleVariant AsVariant(Value value) { OleVariant out(VT_NULL); if(value.IsNull()) return out; switch(value.GetType()) { case BOOL_V: out.vt = VT_UI1; out.bVal = (byte)(int)value; break; case INT_V: out.vt = VT_I4; out.lVal = (int)value; break; case DOUBLE_V: out.vt = VT_R8; out.dblVal = value; break; case STRING_V: out.vt = VT_BSTR; out.bstrVal = StringToBSTR(value); break; case WSTRING_V: out.vt = VT_BSTR; out.bstrVal = WStringToBSTR(value); break; case DATE_V: case TIME_V: out.vt = VT_DATE; out.date = ToDATE((Time)value); // todo: VALUEARRAY_V ?? default: break; } return out; } double GetCurrency(const win32_CY_& currency) { return (currency.Hi * (65536.0 * 65536.0) + currency.Lo) / 10000.0; } OleVariant ValueToVariant(Value v) { if(IsTypeRaw< IRef >(v)) { OleVariant out(VT_DISPATCH); IRef disp = ValueTo< IRef >(v); if(!!disp) disp -> AddRef(); out.pdispVal = ~disp; return out; } if(IsTypeRaw< IRef >(v)) { OleVariant out(VT_UNKNOWN); IRef unk = ValueTo< IRef >(v); if(!!unk) unk -> AddRef(); out.punkVal = ~unk; return out; } return AsVariant(v); } void ReturnVariant(VARIANT *var, const Value& v) { *var = AsVariant(v); } ////////////////////////////////////////////////////////////////////// // BSTR String BSTRToString(BSTR bstr) { int l; if(!bstr || !(l = SysStringLen(bstr))) return Null; byte cs = GetDefaultCharset(); if(cs == CHARSET_UTF8) return ToUtf8(TWchar(bstr)); StringBuffer out(l); FromUnicode(out, TWchar(bstr), l, cs); return out; } BSTR StringToBSTR(String s) { int len = s.GetLength(); if(len == 0) return NULL; byte cs = GetDefaultCharset(); if(cs == CHARSET_UTF8) return WStringToBSTR(FromUtf8(s)); BSTR bstr = SysAllocStringLen(NULL, len); ToUnicode(TWchar(bstr), s, len, cs); return bstr; } void ReturnString(BSTR *dest, String s) { if(*dest) SysFreeString(*dest); *dest = StringToBSTR(s); } HRESULT CheckReturnString(BSTR *bstr, String s) { if(!bstr) return E_INVALIDARG; ReturnString(bstr, s); return S_OK; } void ReturnWString(BSTR *dest, WString s) { if(*dest) SysFreeString(*dest); *dest = WStringToBSTR(s); } HRESULT CheckReturnWString(BSTR *bstr, WString s) { if(!bstr) return E_INVALIDARG; ReturnWString(bstr, s); return S_OK; } static ValueArray SAFEARRAYToValueArrayPart(SAFEARRAY *array, long *indices, int dim_index) { Vector dim_array; int nelem = array->rgsabound[dim_index].cElements; dim_array.SetCount(nelem); for(int e = 0; e < nelem; e++) { indices[dim_index] = e; if(dim_index > 0) dim_array[e] = SAFEARRAYToValueArrayPart(array, indices, dim_index - 1); else { OleVariant var; HRESULT hr = SafeArrayGetElement(array, indices, &var); if(SUCCEEDED(hr)) dim_array[e] = AsValue(var); else { String dims; for(int i = 0; i < dim_index; i++) dims << (i ? ", " : "") << indices[i]; dim_array[e] = ErrorValue(NFormat("SafeArrayGetElement(%s): error %08lx", dims, hr)); } } } return ValueArray(pick(dim_array)); } ValueArray SAFEARRAYToValueArray(SAFEARRAY *array) { int ndims = array->cDims; Vector indices; indices.SetCount(ndims, -1); return SAFEARRAYToValueArrayPart(array, indices.Begin(), ndims - 1); } Vector SAFEARRAYToWStringVector(SAFEARRAY *array) { Vector out; out.SetCount(array->rgsabound[0].cElements); Vector indices; indices.SetCount(array->cDims, 0); for(int i = 0; i < out.GetCount(); i++) { OleBstr s; indices[0] = i; HRESULT hr = SafeArrayGetElement(array, indices.Begin(), s.Set()); out[i] = s; } return out; } SAFEARRAY *ToSAFEARRAY(const ValueArray& varray) { SAFEARRAY *a = SafeArrayCreateVector(VT_VARIANT, 0, varray.GetCount()); if(!a) return NULL; for(long index = 0; index < varray.GetCount(); index++) { OleVariant var = AsVariant(varray[(int)index]); SafeArrayPutElement(a, &index, &var); } return a; } SAFEARRAY *ToSAFEARRAY(const Vector& vstr) { SAFEARRAY *a = SafeArrayCreateVector(VT_BSTR, 0, vstr.GetCount()); if(!a) return NULL; for(long index = 0; index < vstr.GetCount(); index++) { OleBstr var = vstr[(int)index]; SafeArrayPutElement(a, &index, ~var); } return a; } ////////////////////////////////////////////////////////////////////// // special types Color PackColor(long rgb) { if(rgb < 0) return Null; return Color((rgb >> 16) & 255, (rgb >> 8) & 255, (rgb >> 0) & 255); } long UnpackColor(Color c) { if(IsNull(c)) return -1; return (c.GetR() << 16) | (c.GetG() << 8) | (c.GetB() << 0); } HRESULT CheckReturnColor(long *ptr, Color c) { if(!ptr) return E_INVALIDARG; *ptr = UnpackColor(c); return S_OK; } ////////////////////////////////////////////////////////////////////// // errors OleExc::OleExc(HRESULT hresult) : Exc(NFormat("COM[%08x]: %s", (int)hresult, GetErrorMessage(hresult))) , hresult(hresult) { } OleExc::OleExc(HRESULT hresult, const char *text) : Exc(NFormat("COM[%08x]: %s: %s", (int)hresult, GetErrorMessage(hresult), text)) , hresult(hresult) { LOG("OleExc::OleExc " << *this); } HRESULT LogResult(HRESULT hr) { LOGF("<= return 0x%08x: %s\r\n", hr, GetErrorMessage(hr)); return hr; } HRESULT LogError(HRESULT hr) { if(FAILED(hr)) LogResult(hr); return hr; } ////////////////////////////////////////////////////////////////////// // interfaces Value DispatchToValue(IDispatch *disp) { return RawPickToValue(IRef(disp)); } Value UnknownToValue(IUnknown *unk) { return RawPickToValue(IRef(unk)); } ////////////////////////////////////////////////////////////////////// // OleStream:: OleStream::OleStream(IUnknown *stream) { Open(stream); } bool OleStream::Open(IUnknown *stream) { Close(); if(!stream) return false; if(FAILED(stream -> QueryInterface(IID_IStream, (void **)&istream))) return false; STATSTG stat; Zero(stat); // HRESULT statres = istream -> Stat(&stat, STATFLAG_NONAME); int mode = READWRITE; // if(SUCCEEDED(statres) && (stat.grfMode & (STGM_READ | STGM_WRITE | STGM_READWRITE)) == STGM_READ) // mode = READ; ULARGE_INTEGER pos = AsULarge(0), len; HRESULT hr; if(FAILED(hr = istream -> Seek(AsLarge(0), STREAM_SEEK_CUR, &pos)) || FAILED(hr = istream -> Seek(AsLarge(0), STREAM_SEEK_END, &len))) SetError(hr); current_offset = len.QuadPart; OpenInit(mode, len.QuadPart); Seek(pos.QuadPart); return true; } void OleStream::Close() { if(!(bool)istream) return; int64 pos = GetPos(); Flush(); HRESULT hr; if(FAILED(hr = istream -> Seek(AsLarge(pos), STREAM_SEEK_SET, 0))) SetError(hr); istream = 0; } void OleStream::SetStreamSize(dword size) { ASSERT((bool)istream && (GetStyle() & STRM_WRITE)); HRESULT hr; if(FAILED(hr = istream -> SetSize(AsULarge(size)))) SetError(hr); ULARGE_INTEGER pos = AsULarge(0); if(FAILED(hr = istream -> Seek(AsLarge(0), STREAM_SEEK_CUR, &pos))) SetError(hr); current_offset = pos.LowPart; } dword OleStream::Read(int64 at, void *ptr, dword size) { ASSERT((bool)istream && (GetStyle() & STRM_READ)); RawSeek(at); dword done = 0; HRESULT hr; if(FAILED(hr = istream -> Read(ptr, size, &done))) SetError(hr); else current_offset += done; return done; } void OleStream::Write(int64 at, const void *data, dword size) { ASSERT((bool)istream && (GetStyle() & STRM_WRITE)); RawSeek(at); dword done = 0; HRESULT hr; if(FAILED(hr = istream -> Write(data, size, &done)) || done != size) SetError(hr); current_offset += done; } void OleStream::RawSeek(int64 pos) { if(current_offset == pos) return; ULARGE_INTEGER new_pos = AsULarge(pos); HRESULT hr; if(FAILED(hr = istream -> Seek(AsLarge(pos), STREAM_SEEK_SET, &new_pos))) SetError(hr); pos = new_pos.LowPart; } ////////////////////////////////////////////////////////////////////// } #endif