感谢任意见解.细节:
cpp
>dmd --version
DMD64 D Compiler v2.107.0
我只使用了ComObject
类和隐式
继承了IUnknown
接口,用用ImportC
编译并包含以下内容的comheaders.c
编写了一些COM
测试代码.
cpp
#define WINVER 0x0A00
#define _WIN32_WINNT 0x0A00
#define _WIN32_DCOM
#include <wtypes.h>
#include <oleauto.h>
#include <oaidl.h>
用来编译的main.d
文件如下.
cpp
import std.stdio;
import comheaders;
static import com = core.sys.windows.com;
pragma(lib, "onecore"); //修复两个不相关符号的链接
void main() {
auto COMobject = new com.ComObject();
//auto COMobject = new ComObject();
IUnknown* ip = cast(IUnknown*)COMobject;
writeln(COMobject.count);
writeln(" ip 虚表: ", ip.lpVtbl);
auto 虚表 = COMobject.__vptr;
writeln("COMobject 虚表: ", 虚表);
writeln("ip &AddRef: ", &ip.lpVtbl.AddRef);
writeln("ip offset: ", cast(void*)&ip.lpVtbl.AddRef - cast(void*)ip.lpVtbl);
auto ipaddref = cast(void*)ip.lpVtbl.AddRef;
writeln(" ip AddRef: ", ipaddref);
auto addref = cast(void*)(&COMobject.AddRef).funcptr;
writeln("COMobject AddRef: ", addref);
writeln("COMobject AddRef : ip AddRef offset: ", addref - ipaddref);
COMobject.AddRef();
writeln(COMobject.count);
ip.lpVtbl.AddRef(ip);
writeln(COMobject.count);
}
在此,我从静态
导入的core.sys.windows.com
创建了一个ComObject
,但避免使用D窗口库
中的其他内容
.该对象包含一个应调用AddRef
递增的引用计数
.输出
如下.
cpp
0
ip 虚表: 7FF756091A30
COMobject 虚表: 7FF756091A30
ip &AddRef: 7FF756091A38
ip offset: 8
ip AddRef: 7FF756027970
COMobject AddRef: 7FF756022EC0
COMobject AddRef : ip AddRef offset: -19120
1
1
即,正确偏移的AddRef
调用未干活,且与com.ComObject
中AddRef
的函数指针
不同.因此,无法同外部世界代码
正常工作.用
cpp
dmd main.d comheaders.c vcintrinsics.lib -P/wd5105
编译,vcintrinsics.lib
是我构建的解决DMD
不知道一系列MSVC
内部函数的问题的一个库
,即按此处满足链接器
的,而-P/wd5105
是在ImportC
用作C预处理器
时,用来抑制MSVC
警告.
我在unknwn.d
中,复制了不方便命名
的IUnknown
接口的源码
,并从com.d
复制了ComObject
类的源码,两者都在C:\D\dmd2\src\druntime\src\core\sys\windows\
中.
进入main.d
的底部并实验
.我用上面活动
的注释行,新建了个本地ComObject
.一项更改
解决了该问题:使用extern(C++)
,其他链接属性
不工作.
这是工作代码
.我不得不编辑IUnknown
接口,但现在是comheaders.c
中的一个结构
,在QueryInterface
中,并编辑到IUnknown*
,并把E_NOINTERFACE
编辑到com.E_NOINTERFACE
.
并用与IUnknown
结构不同的名字定义D接口
,所以我设置它为_IUnknown_
,但除此
外,除了不使用extern(Windows)
并以extern(C++)
为前缀
外,源码
不变.
这是main.d
的其余部分.
cpp
import core.atomic;
extern(C++):
interface _IUnknown_ {
HRESULT QueryInterface(IID* riid, void** pvObject);
ULONG AddRef();
ULONG Release();
}
class ComObject : _IUnknown_
{
HRESULT QueryInterface(const(IID)* riid, void** ppv)
{
if (*riid == IID_IUnknown)
{
*ppv = cast(void*)cast(IUnknown*)this;
AddRef();
return S_OK;
}
else
{ *ppv = null;
return com.E_NOINTERFACE;
}
}
ULONG AddRef()
{
return atomicOp!"+="(*cast(shared)&count, 1);
}
ULONG Release()
{
LONG lRef = atomicOp!"-="(*cast(shared)&count, 1);
if (lRef == 0)
{
//`free`对象,如果删除该对象,则从`Release()`返回时调用的`postinvariant`将失败.让`GC`收获吧.`删 本;`
return 0;
}
return cast(ULONG)lRef;
}
LONG count = 0;//对象引用计数
}
现在如下输出
:
cpp
0
ip 虚表: 7FF76B9C0360
COMobject 虚表: 7FF76B9C0360
ip &AddRef: 7FF76B9C0368
ip offset: 8
ip AddRef: 7FF76B951580
COMobject AddRef: 7FF76B951580
COMobject AddRef : ip AddRef offset: 0
1
2
显示在ComObjects
虚表中,查找AddRef
会生成与通过COM
接口相同的函数指针
,且两者都工作
.
工作假设:通过导入core.sys.windows.com
引入的ComObject
和IUnknown
都被破坏了,这是Phobos
中对COM
的所有支持.请确认或拒绝
.
你错误
地声明了接口变量
.试试如下:
cpp
auto COMobject = new com.ComObject();
//auto COMobject = new ComObject();
IUnknown ip = COMobject;
writeln(COMobject.count);
writeln(" ip 虚表: ", ip.lpVtbl);
auto 虚表 = COMobject.__vptr;
writeln("COMobject 虚表: ", 虚表);
writeln("ip &AddRef: ", &ip.lpVtbl.AddRef);
writeln("ip offset: ", cast(void*)&ip.lpVtbl.AddRef - cast(void*)ip.lpVtbl);
auto ipaddref = cast(void*)ip.lpVtbl.AddRef;
writeln(" ip AddRef: ", ipaddref);
auto addref = cast(void*)(&COMobject.AddRef).funcptr;
writeln("COMobject AddRef: ", addref);
writeln("COMobject AddRef : ip AddRef offset: ", addref - ipaddref);
COMobject.AddRef();
writeln(COMobject.count);
ip.lpVtbl.AddRef(ip);
writeln(COMobject.count);