c++应用程序找不到com dll,因为编译器使用不正确的guid生成.tlh文件

c++ application cannot find com dll because compiler generating .tlh file with incorrect guids

本文关键字:不正确 guid 生成 文件 tlh 编译器 找不到 应用程序 com dll 因为      更新时间:2023-10-16

我有一个在c++项目中使用的com dll。我没有注册dll,但它在同一个解决方案中。我的应用程序不断中断,我发现它在这里中断

hr = CoCreateInstance(rclsid, pOuter, dwClsContext, __uuidof(IUnknown), reinterpret_cast<void**>(&pIUnknown));

因为我没有具有该guid(rclsid)的com类。我做了更多的挖掘,发现它从临时目录中的.tlh文件中获取guid,但guid与我的代码不同。

.tlh文件

    struct __declspec(uuid("b10a18c8-7109-3f48-94d9-e48b526fc928"))
    DocMapEntry;
    // [ default ] interface _DocMapEntry
    // interface _Object
    // interface IDocMapEntry

c#代码(可视dll)

    [ComVisible(true)]
    [Guid("E98676B9-1965-4248-A9B6-74EC5EE5385A")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface IDocMapEntry
    {
        int Offset { get; set; }
        int PageOffset { get; set; }
        int PageNumber { get; set; }
    }

我尝试将值更改为正确的值,但它不断更改,visual studio要求我重新加载。

当我使用com资源管理器查看该类时,我会得到一个不同的clsid,当我尝试注销它时,它成功地完成了,但项目仍然存在,文件位置是mscoree。

我的c++应用程序使用.tlh文件中的guid,但找不到该文件。

public class DocMapEntry : IDocMapEntry
 {
   ...
 }

我的问题是。

我需要注册我的com dll才能工作吗?如何设置类的guid?为什么它会创建一个guid错误的临时.tlh文件?(可选)为什么我不能更改这个文件?(可选)

谢谢。

 public interface IDocMapEntry

COM强烈区分CLSID和IID。接口标识符IID标识COM对象实现的接口。我们可以看到,您使用[Guid]属性指定了它。您将它作为CoCreateInstance()的第四个参数传递,现在您将在其中传递IUnknown的IID。

您需要的是CLSID,类标识符。我们在您的代码片段中看不到它,它是用于实现您的IDocMapEntry的代码片段。它有可能被命名为DocMapEntry。还有你没有给它一个[Guid]的额外几率,所以CLR会自动为你生成一个。请注意,当您修改类时,它将更改,这可能是CoCreateObject()失败的原因之一。

忘记用Regasm.exe/codebase注册.NET程序集是另一个原因,您在问题中也提到了同样多的原因。这是必需的,否则COM将无法找到DLL并导致调用失败,错误代码为0x80040154,"类未注册"。把它放在同一个解决方案中是不够的,COM搜索规则与.NET.使用的规则完全不同

还要注意,您正在公开类的内部,通过在类上应用[ClassInterface(ClassInterfaceType.None)]特性来避免这种情况。

不需要注册COM DLL,但需要注册一个负责创建COM对象的对象。在COM子系统初始化后(通过调用CoInitializeCoInitializeEx),在应用程序中调用CoRegisterClassObject

IClassFactory *factory = new ObjectFactory();
// Register the factory responsible for creating our COM objects
DWORD classToken;
HRESULT hr = CoRegisterClassObject(
    Object_CLSIID,
    factory,
    CLSCTX_LOCAL_SERVER,
    REGCLS_MULTIPLEUSE,
    &classToken);
// Now we can create the objects
Object *obj = nullptr;
hr = CoCreateInstance(
    Object_CLSIID,
    nullptr,
    CLSCTX_LOCAL_SERVER,
    Object_IID,
    reinterpret_cast<void**>(&obj));

不确定它为什么要创建一个临时.tlh,但我怀疑这是您的构建设置中的内容——可能是在构建步骤中。

您的COM对象在C#dll中吗?如果是,您以前在系统中运行过regasm吗?系统可能已经注册了COM dll。

Guid("E98676B9-1965-4248-A9B6-74EE5385A"):这是您的接口Guid,而不是组件Guid。

您应该在实现类中为COM对象声明一个GUID,该GUID应该是b10a18c8-7109-3f48-94d9-e48b526fc928。

为什么它会创建一个guid错误的临时.tlh文件?

您确定没有使用#import关键字导入COM dll吗。