1

I have a com dll that gets used in a c++ project. I have not registered the dll but its in the same solution. My application continuously breaks and I found that it breaks here

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

because I don't have a com class with that guid (rclsid). I did more digging and I found that it gets the guid from a .tlh file in a temp directory but the guid differs from my code.

.tlh file

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

c# code (com visable 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; }
    }

I tried changing the value to the correct value but it continuously gets changed and visual studio asks me to reload.

When I look at the class using com explorer I get a different clsid, and when I try to unregister it, it completes successfully but the item is still there and the file location is mscoree.

my c++ application uses the guid in the .tlh file but doesn't find the file.

public class DocMapEntry : IDocMapEntry
 {
   ...
 }

My questions are.

Do I need to register my com dll for this to work? how can I set the guid for the class? Why would it create a temp .tlh file with the wrong guid? (optional) why can't I change this file? (optional)

Thank you.

4

3 回答 3

2
 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)] 属性来避免这种情况。

于 2013-07-02T18:09:37.997 回答
1

不,您不必注册 COM DLL,但您需要注册一个负责创建 COM 对象的对象。CoRegisterClassObject通过在 COM 子系统初始化后调用(通过调用CoInitializeor CoInitializeEx)在您的应用程序中执行此操作。

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,但我怀疑它在你的构建设置中 - 可能在构建步骤中。

于 2013-07-02T17:21:50.243 回答
1

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

Guid("E98676B9-1965-4248-A9B6-74EC5EE5385A"):这是您的界面 GUID,而不是您的组件 guid。

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

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

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

于 2013-07-02T17:48:02.667 回答