D语言里面,可以通过version(Windows)来兼容COM接口,不过对于__uuidof却没有相应实现。
原始COM接口定义类似这样(找个简单的):
[
local,
object,
uuid(594f31d0-7f19-11d0-b194-00a0c90dc8bf)
]
interface IRpcChannelBuffer2 : IRpcChannelBuffer
{
HRESULT GetProtocolVersion
(
[in,out] DWORD *pdwVersion
);
}
VC++中可通过__uuidof操作符来获取COM接口中的uuid“元”信息。
转换为D接口后代码如下:
version(Windows) {
interface IRpcChannelBuffer2 : IRpcChannelBuffer
{
HRESULT GetProtocolVersion (DWORD* pdwVersion);
}
}
失去了uuid信息。只要稍作修改,在转换时保存uuid,即可以模板来模拟实现__uuidof操作符。
import std.c.windows.com;
import std.string;
import std.stdio;
private:
template HexStrToUbyte(char[] str)
{
const ubyte HexStrToUbyte = cast(ubyte)HexStrToUlong!(str);
}
template HexStrToUshort(char[] str)
{
const ushort HexStrToUshort = cast(ushort)HexStrToUlong!(str);
}
template HexStrToUint(char[] str)
{
const uint HexStrToUint = cast(uint)HexStrToUlong!(str);
}
template HexStrToUlong(char[] str)
{
static if (str.length == 1)
const ulong HexStrToUlong = HexToUbyte!(str[0..1]);
else
const ulong HexStrToUlong
= HexToUbyte!(str[length-1..length])
+ 16UL * HexStrToUlong!(str[0..length-1]);
}
private:
template HexToUbyte(char[] c)
{
static if (c[0] >= '0' && c[0] <= '9')
const ubyte HexToUbyte = c[0] - '0';
else static if (c[0] == 'A' || c[0] == 'a')
const ubyte HexToUbyte = 0xa;
else static if (c[0] == 'B' || c[0] == 'b')
const ubyte HexToUbyte = 0xb;
else static if (c[0] == 'C' || c[0] == 'c')
const ubyte HexToUbyte = 0xc;
else static if (c[0] == 'D' || c[0] == 'd')
const ubyte HexToUbyte = 0xd;
else static if (c[0] == 'E' || c[0] == 'e')
const ubyte HexToUbyte = 0xe;
else static if (c[0] == 'F' || c[0] == 'f')
const ubyte HexToUbyte = 0xf;
}
template HexToUbyte_bug(char c)
{
static if (c >= '0' && c <= '9')
const ubyte HexToUbyte1 = c - '0';
else static if (c == 'A' || c == 'a')
const ubyte HexToUbyte1 = 0xa;
else static if (c == 'B' || c == 'b')
const ubyte HexToUbyte1 = 0xb;
else static if (c == 'C' || c == 'c')
const ubyte HexToUbyte1 = 0xc;
else static if (c == 'D' || c == 'd')
const ubyte HexToUbyte1 = 0xd;
else static if (c == 'E' || c == 'e')
const ubyte HexToUbyte1 = 0xe;
else static if (c == 'F' || c == 'f')
const ubyte HexToUbyte1 = 0xf;
}
template IIDFromStr(char[] str)
{
const IID IIDFromStr = {
HexStrToUint!(str[0..8]),
HexStrToUshort!(str[9..13]),
HexStrToUshort!(str[14..18]),
[
HexStrToUbyte!(str[19..21]),
HexStrToUbyte!(str[21..23]),
HexStrToUbyte!(str[24..26]),
HexStrToUbyte!(str[26..28]),
HexStrToUbyte!(str[28..30]),
HexStrToUbyte!(str[30..32]),
HexStrToUbyte!(str[32..34]),
HexStrToUbyte!(str[34..36])
]
};
}
template __uuidof(T:IUnknown)
{
IID __uuidof = IIDFromStr!("00000000-0000-0000-C000-000000000046");
}
template __uuidof(T:IClassFactory)
{
IID __uuidof = IIDFromStr!("00000001-0000-0000-C000-000000000046");
}
void main()
{
IID iu = __uuidof!(IUnknown);
IID icp = __uuidof!(IClassFactory);
writefln(iu.Data1);
writefln(iu.Data2);
writefln(iu.Data3);
writefln(iu.Data4);
}
如上面代码,接口在转换时,把:
[
local,
object,
uuid(594f31d0-7f19-11d0-b194-00a0c90dc8bf)
]
interface IRpcChannelBuffer2 : IRpcChannelBuffer
{
HRESULT GetProtocolVersion
(
[in,out] DWORD *pdwVersion
);
}
转换为:
template __uuidof(T:IRpcChannelBuffer2)
{
IID __uuidof = IIDFromStr!("594f31d0-7f19-11d0-b194-00a0c90dc8bf");
}
version (Windows) {
interface IRpcChannelBuffer2 : IRpcChannelBuffer {
HRESULT GetProtocolVersion (DWORD* pdwVersion);
}
}
即可,这个可以交由自动化工具完成。
由于__uuidof模板值在编译期决议,没有实际的运行期开销。