Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Ticket #640 (assigned wishlist)

Opened 1 year ago

Last modified 5 months ago

add COM support to Tango

Reported by: yidabu Assigned to: kris (accepted)
Priority: major Milestone: 1.0
Component: Packaging Version: 0.99.1 RC4 Keep
Keywords: COM, Windows, triage Cc:

Description

COM is a great thing on Windows, you can find COM object everywhere (e.g. IE).

Juno (by Jonh C) wraped COM apis with Phobos.

add COM support to Tango, Just:

first:

port tlbimpd to Tango, to generate COM header(type library) automatically.
http://svn.dsource.org/projects/juno/trunk/tools/tlbimpd/

second:
port Juno.com package to Tango.

http://www.dsource.org/projects/juno

Change History

09/29/07 15:29:45 changed by kris

  • status changed from new to assigned.
  • milestone changed from 0.99.2 RC5 to 1.0.

09/29/07 16:24:40 changed by kris

Have you communicated with JC about this?

10/02/07 08:13:39 changed by yidabu

not. my English is poor, would you please communicate with JC ?

10/02/07 15:04:37 changed by kris

Here's a suggestion: if you add your Tango compatible version to the project tango.scrapple (http://dsource.org/projects/tango.scrapple) it will make it's way into Tango after people get a chance to play with it?

To add a tango.scrapple package, create a ticket and attach the code with a description of what it does

10/04/07 07:00:52 changed by yidabu

Since JC not planed on port Juno to with Tango, I plan do it myself.

A question is, place COM interfaces into tango.sys.win32.UserGdi?, and constants into tango.sys.win32.Types ?

10/04/07 07:36:58 changed by larsivi

Where are the Juno equivalents of these files? Could you please post links here?

10/04/07 12:11:00 changed by kris

Ultimately, that may be where they go (or we may split the responsibility). But for the interim, I suggest the API prototypes and constants be hidden inside the COM modules themselves?

10/04/07 18:04:27 changed by yidabu

10/07/07 22:42:58 changed by yidabu

I modified juno.com.core for use with Tango.
see dwin.sys.win32.com.Core.
tango.sys.win32.Types : GUID, VARIANT confilct with John C's implemention, how about remove GUID, VARIANT from tango.sys.win32.Types, or replaced with JC 's implemention ?

download:

http://down.yidabu.com/dwin.zip

10/07/07 23:11:20 changed by kris

what are the differences involved?

10/07/07 23:26:46 changed by yidabu

tango.sys.win32.Types.GUID:

align(1) struct __GUID
{

	union
	{
		struct
		{
			uint Data1;
			ushort Data2;
			ushort Data3;
			ubyte[1 + 7] Data4;
		}
		struct
		{
			uint D1;
			ushort D2;
			ushort D3;
			ubyte[1 + 7] D4;
		}
	}
}

alias __GUID* LPGUID;
alias __GUID _GUID;
alias __GUID TGUID;
alias __GUID* PGUID;
alias __GUID __CLSID;
alias __CLSID* LPCLSID;
alias __CLSID TCLSID;
alias __CLSID* PCLSID;


JC's:

struct GUID {

  uint a;
  ushort b, c;
  ubyte d, e, f, g, h, i, j, k;

  /**
   * A GUID whose value is all zeros.
   */
  static GUID empty = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };

  /**
   * Initializeds a new instance using the specified integers and bytes.
   * Params:
   *   a = The first 4 bytes.
   *   b = The next 2 bytes.
   *   c = The next 2 bytes.
   *   d = The next byte.
   *   e = The next byte.
   *   f = The next byte.
   *   g = The next byte.
   *   h = The next byte.
   *   i = The next byte.
   *   j = The next byte.
   *   k = The next byte.
   * Returns: The resulting GUID.
   */
  public static GUID opCall(uint a, ushort b, ushort c, ubyte d, ubyte e, ubyte f, ubyte g, ubyte h, ubyte i, ubyte j, ubyte k) {
    GUID result;
    result.a = a, result.b = b, result.c = c, result.d = d, result.e = e, result.f = f, result.g = g, result.h = h, result.i = i, result.j = j, result.k = k;
    return result;
  }

  /**
   * Initializes a new instance using the specified integets and byte array.
   * Params:
   *   a = The first 4 bytes.
   *   b = The next 2 bytes.
   *   c = The next 2 bytes.
   *   d = The remaining 8 bytes.
   * Returns: The resulting GUID.
   * Throws: ArgumentException if d is not 8 bytes long.
   */
  public static GUID opCall(uint a, ushort b, ushort c, ubyte[] d) {
    if (d.length != 8)
      throw new IllegalArgumentException("Byte array for GUID must be 8 bytes long.");

    GUID result;
    result.a = a, result.b = b, result.c = c, result.d = d[0], result.e = d[1], result.f = d[2], result.g = d[3], result.h = d[4], result.i = d[5], result.j = d[6], result.k = d[7];
    return result;
  }

  /**
   * Initializes a new instance using the value represented by the specified string.
   * Params: s = A string containing a GUID in groups of 8, 4, 4, 4 and 12 digits with hyphens between the groups. The GUID can optionally be enclosed in braces.
   * Returns: The resulting GUID.
   */
  public static GUID opCall(char[] s) {

    ulong parse(char[] s) {

      bool hexToInt(char c, out uint result) {
        if (c >= '0' && c <= '9') result = c - '0';
        else if (c >= 'A' && c <= 'F') result = c - 'A' + 10;
        else if (c >= 'a' && c <= 'f') result = c - 'a' + 10;
        else result = -1;
        return (result >= 0);
      }

      ulong result;
      uint value, index;
      while (index < s.length && hexToInt(s[index], value)) {
        result = result * 16 + value;
        index++;
      }
      return result;
    }

    if (s[0] == '{') {
      s = s[1 .. $];
      if (s[$ - 1] == '}')
        s = s[0 .. $ - 1];
    }

    if (s[0] == '[') {
      s = s[1 .. $];
      if (s[$ - 1] == ']')
        s = s[0 .. $ - 1];
    }

    //if (s.find('-') == -1)
    if (s.locate('-') == s.length)
      throw new FormatException("Unrecognised GUID format.");

    GUID g;
    g.a = cast(uint)parse(s[0 .. 8]);
    g.b = cast(ushort)parse(s[9 .. 13]);
    g.c = cast(ushort)parse(s[14 .. 18]);
    uint m = cast(uint)parse(s[19 .. 23]);
    g.d = cast(ubyte)(m >> 8);
    g.e = cast(ubyte)m;
    ulong n = parse(s[24 .. $]);
    m = cast(uint)(n >> 32);
    g.f = cast(ubyte)(m >> 8);
    g.g = cast(ubyte)m;
    m = cast(uint)n;
    g.h = cast(ubyte)(m >> 24);
    g.i = cast(ubyte)(m >> 16);
    g.j = cast(ubyte)(m >> 8);
    g.k = cast(ubyte)m;
    return g;
  }

  public static GUID newGuid() {
    GUID g;

    int hr;
    if ((hr = CoCreateGuid(g)) != S_OK)
      //throw new COMException(hr);
      throw new COMException( format(new char[64], hr, Style.HexUpper, Flags.Prefix) );

    return g;
  }

  public bool opEquals(GUID other) {
    return a == other.a
      && b == other.b
      && c == other.c
      && d == other.d
      && e == other.e
      && f == other.f
      && g == other.g
      && h == other.h
      && i == other.i
      && j == other.j
      && k == other.k;
  }

  /**
   * Retrieves the hash code for this instance.
   * Returns: The hash code for this instance.
   */
  public hash_t toHash() {
    return a ^ ((b << 16) | c) ^ ((f << 24) | k);
  }

  /**
   * Returns a string representation of the value of this instance in registry format.
   * Returns: A string formatted in this pattern: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx where the GUID is represented as a series of lowercase hexadecimal digits in groups of 8, 4, 4, 4 and 12 and separated by hyphens.
   */
  public char[] toString() {

    void hexToString(ref char[] s, ref uint index, uint a, int b) {

      char hexToChar(uint a) {
        a = a & 0x0F;
        return cast(char)((a > 9) ? a - 10 + 0x61 : a + 0x30);
      }

      s[index++] = hexToChar(a >> 4);
      s[index++] = hexToChar(a);
      s[index++] = hexToChar(b >> 4);
      s[index++] = hexToChar(b);
    }

    char[] s = new char[38];
    uint index = 1;

    s[0] = '{';
    hexToString(s, index, a >> 24, a >> 16);
    hexToString(s, index, a >> 8, a);
    s[index++] = '-';
    hexToString(s, index, b >> 8, b);
    s[index++] = '-';
    hexToString(s, index, c >> 8, c);
    s[index++] = '-';
    hexToString(s, index, d, e);
    s[index++] = '-';
    hexToString(s, index, f, g);
    hexToString(s, index, h, i);
    hexToString(s, index, j, k);
    s[$ - 1] = '}';

    return s;
  }

}



tango.sys.win32.Types.VARIANT:

struct TVARIANT
{
	TVARTYPE vt;
	ushort wReserved1;
	ushort wReserved2;
	ushort wReserved3;

	union
	{
		struct
		{
			ubyte bVal;
		}
		struct
		{
			byte iVal;
		}
		struct
		{
			int lVal;
		}
		struct
		{
			float fltVal;
		}
		struct
		{
			double dblVal;
		}
		struct
		{
			ushort vbool;
		}
		struct
		{
			HRESULT scode;
		}
		struct
		{
			ubyte* pbVal;
		}
		struct
		{
			byte* piVal;
		}
		struct
		{
			int* plVal;
		}
		struct
		{
			float* pfltVal;
		}
		struct
		{
			double* pdblVal;
		}
		struct
		{
			ushort* pbool;
		}
		struct
		{
			HRESULT* pscode;
		}
		struct
		{
			POINTER byRef;
		}
	}
}

alias TVARIANT VARIANT;

JC's:

struct VARIANT {

  union {
    struct {
      /// Describes the type of the instance.
      VARTYPE vt;
      ushort wReserved1;
      ushort wReserved2;
      ushort wReserved3;
      union {
        long llVal;
        int lVal;
        ubyte bVal;
        short iVal;
        float fltVal;
        double dblVal;
        VARIANT_BOOL boolVal;
        int scode;
        long cyVal;
        double date;
        wchar* bstrVal;
        IUnknown punkVal;
        IDispatch pdispVal;
        SAFEARRAY* parray;
        ubyte* pbVal;
        short* piVal;
        int* plVal;
        long* pllVal;
        float* pfltVal;
        double* pdblVal;
        VARIANT_BOOL* pboolVal;
        int* pscode;
        long* pcyVal;
        double* pdate;
        wchar** pbstrVal;
        IUnknown* ppunkVal;
        IDispatch* ppdispVal;
        SAFEARRAY* pparray;
        VARIANT* pvarVal;
        void* byref;
        byte cVal;
        ushort uiVal;
        uint ulVal;
        ulong ullVal;
        int intVal;
        uint uintVal;
        DECIMAL* pdecVal;
        byte* pcVal;
        ushort* puiVal;
        uint* pulVal;
        ulong* pullVal;
        int* pintVal;
        uint* puintVal;
        struct {
          void* pvRecord;
          IRecordInfo pRecInfo;
        }
      }
    }
    DECIMAL decVal;
  }

  /**
   * Initializes a new instance using the specified _value and _type.
   * Params:
   *   value = A _value of one of the acceptable types.
   *   type = The VARTYPE identifying the _type of value.
   * Returns: The resulting VARIANT.
   */
  public static VARIANT opCall(T)(T value, VARTYPE type = VariantType!(T)) {
    VARIANT v;
    v.vt = type;

    static if (is(T == ubyte))
      v.bVal = value;
    else static if (is(T == byte))
      v.cVal = value;
    else static if (is(T == ushort))
      v.uiVal = value;
    else static if (is(T == short))
      v.iVal = value;
    else static if (is(T == uint))
      v.ulVal = value;
    else static if (is(T == int))
      v.lVal = value;
    else static if (is(T == ulong))
      v.ullVal = value;
    else static if (is(T == long))
      v.llVal = value;
    else static if (is(T == float))
      v.fltVal = value;
    else static if (is(T == double))
      v.dblVal = value;
    else static if(is(T == DECIMAL))
      v.decVal = value;
    else static if (is(T : IDispatch))
      v.pdispVal = value, value.AddRef();
    else static if (is(T : IUnknown))
      v.punkVal = value, value.AddRef();
    else static if (is(T : Object))
      v.byref = cast(void*)value;
    else static if(is(T E == enum))
      v = VARIANT(cast(E)value);
    else static if(is(T == bool))
      v.boolVal = (value == true) ? VARIANT_TRUE : VARIANT_FALSE;
    else static if (is(T : char[]))
      v.bstrVal = value.toBStr();
    else static if (is(T == wchar*))
      v.bstrVal = SysAllocString(value);
    //else static if (is(T == DateTime))
      //v.date = value.toOleDate();
    else static assert(false, "The type '" ~ typeof(T).stringof ~ "' must be one of the allowed types.");

    return v;
  }

  /**
   * Clears the value of this instance and releases any associated memory.
   * See_Also: $(LINK2 http://msdn2.microsoft.com/en-us/library/ms221165.aspx, VariantClear).
   */
  public void clear() {
    if (isCOMInitialized) {
      VariantClear(this);
    }
  }

  /**
   * Copies this instance to the destination.
   * Params: dest = The destination VARIANT.
   * See_Also: $(LINK2 http://msdn2.microsoft.com/en-us/library/ms221697.aspx, VariantCopy).
   */
  public void copyTo(out VARIANT dest) {
    VariantCopy(&dest, this);
  }

  public T get(T)() {
    static if (is(T == bool)) {
      if (vt == VARTYPE.VT_BOOL)
        return (boolVal == VARIANT_TRUE) ? true : false;
    }
    else static if (is(T == ubyte)) {
      if (vt == VARTYPE.VT_UI1)
        return bVal;
    }
    static if (is(T == byte)) {
      if (vt == VARTYPE.VT_I1)
        return cVal;
    }
    else static if (is(T == ushort)) {
      if (vt == VARTYPE.VT_UI2)
        return uiVal;
    }
    else static if (is(T == short)) {
      if (vt == VARTYPE.VT_I2)
        return iVal;
    }
    else static if (is(T == uint)) {
      if (vt == VARTYPE.VT_UI4)
        return ulVal;
      else if (vt == VARTYPE.VT_UINT)
        return uintVal;
    }
    else static if (is(T == int)) {
      if (vt == VARTYPE.VT_I4)
        return lVal;
      else if (vt == VARTYPE.VT_INT)
        return intVal;
    }
    else static if (is(T == ulong)) {
      if (vt == VARTYPE.VT_UI8)
        return ullVal;
      else if (vt == VARTYPE.VT_I8)
        return llVal;
    }
    else static if (is(T == float)) {
      if (vt == VARTYPE.VT_R4)
        return fltVal;
    }
    else static if (is(T == double)) {
      if (vt == VARTYPE.VT_R8)
        return dblVal;
    }
    else static if (is(T == char[])) {
      if (vt == VARTYPE.VT_BSTR)
        return fromBStr(bstrVal);
    }
    else static if (is(T == DECIMAL)) {
      if (vt == VARTYPE.VT_DECIMAL)
        return decVal;
    }
    else static if (is(T : IDispatch)) {
      if (vt == VARTYPE.VT_DISPATCH)
        return pdispVal;
    }
    else static if (is(T : IUnknown)) {
      if (vt == VARTYPE.VT_UNKNOWN)
        return punkVal;
    }
    else static if (is(T == DateTime)) {
      if (vt == VARTYPE.VT_DATE)
        return DateTime.fromOleDate(date);
    }
    else static if (is(T : Object)) {
      if (vt == VARTYPE.VT_BYREF)
        return cast(T)byref;
    }
    return T.init;
  }

  /**
   * Converts the value contained in this instance to a string.
   * Returns: A string representation of the value contained in this instance.
   */
  public char[] toString() {
    if (vt == VARTYPE.VT_EMPTY || vt == VARTYPE.VT_NULL)
      return null;

    if (vt == VARTYPE.VT_BSTR)
      return fromBStr(bstrVal);

    VARIANT temp;
    if (VariantChangeTypeEx(&temp, this, LOCALE_USER_DEFAULT, 0, VARTYPE.VT_BSTR) == S_OK)
      return fromBStr(temp.bstrVal);

    return null;
  }

}

10/08/07 00:13:24 changed by kris

Just for now, I recommend you rename Variant and Guid within your ported code, so that they do not conflict with Win32.Types -- there are dependencies on the latter, so we can't swap them out right away ...

10/08/07 01:09:21 changed by yidabu

OK, I just renamed GUID to Guid, and VARIANT to Variant.

10/16/07 00:09:33 changed by yidabu

Ported juno.com.core and juno.com.client to Tango.

see: http://svn.dsource.org/projects/dwin/trunk/sys/win32/com/

some COM types and APIs into dwin.sys.win32.Types and dwin.sys.win32.UserGdi?.

all COM interfaces into dwin.sys.win32.intefaces.

01/23/08 18:03:39 changed by sean

(In [3118]) Added IUnknown, for COM support. This refs #640

05/24/08 14:21:58 changed by larsivi

  • keywords changed from COM, Windows to COM, Windows, triage.