c ++应用程序无法找到com dll,因为编译器生成带有错误guid的.tlh文件

时间:2013-07-02 17:17:00

标签: c++ visual-studio-2008 com

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

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

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

.tlh文件

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

c#c​​ode(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; }
    }

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

当我使用com explorer查看该类时,我得到了一个不同的clsid,当我尝试取消注册它时,它成功完成但该项仍然存在且文件位置是mscoree。

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

public class DocMapEntry : IDocMapEntry
 {
   ...
 }

我的问题是。

我是否需要注册我的com dll才能使用? 我怎样才能为班级设置指导? 为什么会用错误的guid创建一个temp .tlh文件? (可选的) 为什么我不能改变这个文件? (可选)

谢谢。

3 个答案:

答案 0 :(得分:2)

 public interface IDocMapEntry

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

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

忘记用Regasm.exe / codebase注册.NET程序集是另一个原因,你在问题中说了很多。这是必需的,否则COM将无法找到DLL并使调用失败,错误代码为0x80040154,“类未注册”。在相同的解决方案中,足够,COM搜索规则与.NET使用的规则不同。

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

答案 1 :(得分:1)

不,您不必注册COM DLL,但您需要注册一个负责创建COM对象的对象。在COM子系统初始化后(通过调用CoRegisterClassObjectCoInitialize)调用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,但我怀疑它是你的构建设置中的东西 - 可能是在构建步骤中。

答案 2 :(得分:1)

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

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

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

为什么会用错误的guid创建一个temp .tlh文件?

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