我正在为OBS Studio创建Heartrate Monitor插件。这个想法是在C#端访问Bluetooth GATT服务,以从Smart BT HRM中获取数据,进行渲染,然后将其传输到充当OBS Studio插件本身的C ++ dll。
我设法使所有工作正常进行,我可以从C ++端在C#中调用一个函数,该函数返回一个图像数据数组,然后可以将其提供给OBS。但是,这需要注册C#DLL。我不想用无用的DLL信息来污染注册表,所以我研究了免费注册COM。 (这也将使分发/安装lot更简单)
经过多番摆弄,我陷入了僵局。通过sxstrace,我知道并排系统正在拾取适当的库:
=================
Begin Activation Context Generation.
Input Parameter:
Flags = 0
ProcessorArchitecture = AMD64
CultureFallBacks = en-US;en
ManifestPath = C:\Program Files\obs-studio\obs-plugins\64bit\HrmPlugin.dll
AssemblyDirectory = C:\Program Files\obs-studio\obs-plugins\64bit\
Application Config File =
-----------------
INFO: Parsing Manifest File C:\Program Files\obs-studio\obs-plugins\64bit\HrmPlugin.dll.
INFO: Manifest Definition Identity is HrmPlugin,processorArchitecture="AMD64",type="win32",version="1.0.0.0".
INFO: Reference: OBSBluetoothHeartrate,processorArchitecture="*",type="win32",version="1.0.0.0"
INFO: Resolving reference OBSBluetoothHeartrate,processorArchitecture="*",type="win32",version="1.0.0.0".
INFO: Resolving reference for ProcessorArchitecture AMD64.
INFO: Resolving reference for culture Neutral.
INFO: Applying Binding Policy.
INFO: No binding policy redirect found.
INFO: Begin assembly probing.
INFO: Did not find the assembly in WinSxS.
INFO: Attempt to probe manifest at C:\Program Files\obs-studio\obs-plugins\64bit\OBSBluetoothHeartrate.DLL.
INFO: Manifest found at C:\Program Files\obs-studio\obs-plugins\64bit\OBSBluetoothHeartrate.DLL.
INFO: End assembly probing.
INFO: Resolving reference OBSBluetoothHeartrate.mui,language="*",processorArchitecture="AMD64",type="win32",version="1.0.0.0".
INFO: Resolving reference for ProcessorArchitecture AMD64.
INFO: Resolving reference for culture en-US.
INFO: Applying Binding Policy.
INFO: No binding policy redirect found.
INFO: Begin assembly probing.
INFO: Did not find the assembly in WinSxS.
INFO: Did not find manifest for culture en-US.
INFO: End assembly probing.
INFO: Resolving reference for culture en.
INFO: Applying Binding Policy.
INFO: No binding policy redirect found.
INFO: Begin assembly probing.
INFO: Did not find the assembly in WinSxS.
INFO: Did not find manifest for culture en.
INFO: End assembly probing.
INFO: Parsing Manifest File C:\Program Files\obs-studio\obs-plugins\64bit\OBSBluetoothHeartrate.DLL.
INFO: Manifest Definition Identity is OBSBluetoothHeartrate,processorArchitecture="AMD64",type="win32",version="1.0.0.0".
INFO: Activation Context generation succeeded.
End Activation Context Generation.
但是,当我尝试从COM对象本身创建类时,出现未找到类错误。创建它的代码如下:
static void Initialize(hrm_source *context)
{
if (context->init_failed) return;
try
{
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
IHrmPluginPtr pHRM(CLSID_HrmPlugin);
context->pHRM = pHRM;
}
catch (_com_error _com_err)
{
MessageBox(NULL, _com_err.ErrorMessage(), L"Failed to initialize COM", MB_OK);
context->pHRM = NULL;
context->init_failed = (context->pHRM == NULL);
}
}
问题是,如果A)我注册了程序集或B)我从exe中使用了,那么整个事情就可以了。实际上,如果我将输出类型更改为.exe,则将main()添加到plugin-dll-source并从那里创建它,我可以运行该exe,并且它可以正常工作。
| C++ Exe | C++ DLL
-------------------------------------
Registered | Works | Works
Register Free | Works | Doesn't Work
显然,清单文件中缺少某些配置标志(井,手指交叉)或设置或属性缺失。
所以,这里的问题是:如何使托管的C#COM服务器和本机C ++ DLL作为COM客户端使用免费注册的COM?
这里还有清单文件:
COM服务器(C#DLL)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32"
name="OBSBluetoothHeartrate"
version="1.0.0.0"
processorArchitecture="amd64"/>
<clrClass clsid="{54667DC4-13CD-4D25-BB9E-C3BDDFAF019F}"
progid="OBSBluetoothHeartrate.HrmPlugin"
threadingModel="Both"
name="OBSBluetoothHeartrate.HrmPlugin"
runtimeVersion="v4.0.30319"/>
</assembly>
COM客户端(C ++ DLL)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32"
name="HrmPlugin"
version="1.0.0.0"
processorArchitecture="amd64"/>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32"
name="OBSBluetoothHeartrate"
version="1.0.0.0"
processorArchitecture="amd64"/>
</dependentAssembly>
</dependency>
</assembly>
2020年1月17日更新
我也向C ++ DLL添加了assemblyIdentity,以防它有所帮助(根据注释中的问题)。唯一更改的是,现在当它由并行系统加载时,它将获得一个身份而不是(null)-不需要身份,因为我没有将C ++ DLL用作COM服务器。但是,我已经更新了C ++ DLL清单和sxstrace日志-从技术上来说,这现在“更正确”,因此至少我们知道这不是原因。
2020年1月29日更新
我不小心将C#DLL COM服务器清单复制为C ++ DLL COM客户端清单。现在已更新为正确的版本。确保仔细检查它,但是即使sxstrace说找到并加载了正确的dll,也仍然找不到该类。我将尝试作为答案提供的手动激活上下文创建并进行报告(当然,如果可以使用它,则将其标记为正确的答案)
这里是使用手动激活上下文的答案的骨架...函数ReportError()是一个存根...用它来做您想做的...日志,跟踪,消息框或将其删除...] >
ACTCTX ctx = { sizeof(ctx), ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID, _T("NameOfYourDotNet.manifest")};
ctx.lpAssemblyDirectory = szPath; // path is drive and directory where your COM DLL is
HANDLE hCtx = CreateActCtx(&ctx);
if (hCtx != INVALID_HANDLE_VALUE)
{
DWORD_PTR dwCookie = 0;
BOOL bActivated = ActivateActCtx(hCtx, &dwCookie);
if (bActivated)
{
wcout << L"After activating ActCtx..." << endl;
// Do stuff with your .NET COM server here
DeactivateActCtx(0, dwCookie);
}
else
{
ReportError(L"Could not activate context: ", GetLastError());
}
ReleaseActCtx(hCtx);
}
else
{
ReportError(_T("Problem creating ActCtx: "), GetLastError());
}