ultimatepp/uppsrc/Ole/util.cpp
cxl 8ebdcbb0d5 uppsrc: NAMESPACE_UPP / END_UPP_NAMESPACE removed
git-svn-id: svn://ultimatepp.org/upp/trunk@10186 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2016-08-26 17:15:30 +00:00

455 lines
10 KiB
C++

#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<const dword *>(&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<const dword *>(&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<IDispatch> >(v))
{
OleVariant out(VT_DISPATCH);
IRef<IDispatch> disp = ValueTo< IRef<IDispatch> >(v);
if(!!disp) disp -> AddRef();
out.pdispVal = ~disp;
return out;
}
if(IsTypeRaw< IRef<IUnknown> >(v))
{
OleVariant out(VT_UNKNOWN);
IRef<IUnknown> unk = ValueTo< IRef<IUnknown> >(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<Value> 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<long> indices;
indices.SetCount(ndims, -1);
return SAFEARRAYToValueArrayPart(array, indices.Begin(), ndims - 1);
}
Vector<WString> SAFEARRAYToWStringVector(SAFEARRAY *array)
{
Vector<WString> out;
out.SetCount(array->rgsabound[0].cElements);
Vector<long> 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<WString>& 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<IDispatch>(disp));
}
Value UnknownToValue(IUnknown *unk)
{
return RawPickToValue(IRef<IUnknown>(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