开发环境:VC7.1
我用VC7.1+ATL做了一个COM,很简单,就是取本地计算机的域名。在调试它的时候,我发现一个奇怪的事。
我用MFC做了一个程序来测试这个COM,结果我发现按照手头找到的资料不能正确的编码。大家请看下面的调用代码:
void CMFCTestDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
HRESULT hr = CoInitialize(NULL);
IDNSInfoPtr ptrDNSInfo(__uuidof(CDNSInfo)); BSTR bstrDomainName;
ptrDNSInfo->get_DomainName(&bstrDomainName);
CString cstrDomainName(bstrDomainName);
SetDlgItemText(IDC_STATIC, cstrDomainName.GetString());
         /*请注意下面这行,在我找到的所有资料中,都没有下面这一行,但如果我不把这个指针置空,执行CoUninitialize()时就会出错,提示不能Release。以我对C++的粗浅了解,这样把一个指针置空似乎有内存泄漏的危险?无论如何,现在程序是可以运行了,不过还是欢迎大家一起来讨论一下这个现象的原因。*/
ptrDNSInfo = NULL;
CoUninitialize();
}

解决方案 »

  1.   

    我认为ptrDNSInfo置空应该没问题ptrDNSInfo是智能指针,你置空的话,他就自动释放掉了
      

  2.   

    把ptrDNSInfo = NULL;改成ptrDNSInfo.Release();比较好
    ptrDNSInfo是智能指针,出作用域会自动析构,所以如果不手工释放,ptrDNSInfo将在CoUninitialize();之后释放,但是CoUninitialize();之后COM对象已经不存在了,所以再释放ptrDNSInfo就不对了,这和是不是用vc7.1没有关系。
      

  3.   

    Analyst() :
    试过Release,还是会非法操作,还有,这是指针,应该用->操作符吧
      

  4.   

    不过谢谢你提醒我,也许在置空之前Release一下会比较安全?有什么简单的办法可以检测内存泄漏吗?
    我本来是想把CoInitialize放在构造里,把CoUninitialize放在析构里……MFC里没有自动生成析构,我就懒得写了……
    良心谴责一下自己……
      

  5.   

    wrong
    应该用->操作符吧
    用. 正确,可以看看他的源码,
    用. 可以在  ptrDNSInfo.p==NULL的时候调用
      

  6.   

    MFC程序多用AfxOleInit来初始化COM
      

  7.   

    Analyst() is correct, the problem is that the object is released/destroyed when it goes out of the scope, but at that time, your CoUninitialize() is already called, so you got an error, try to put the code inside { ....} or in try/catch block
    HRESULT hr = CoInitialize(NULL);
    {
    IDNSInfoPtr ptrDNSInfo(__uuidof(CDNSInfo)); BSTR bstrDomainName;
    ptrDNSInfo->get_DomainName(&bstrDomainName);
    CString cstrDomainName(bstrDomainName);
    SetDlgItemText(IDC_STATIC, cstrDomainName.GetString());
    }CoUninitialize();
      

  8.   

    刚刚发现:在VC7.1中,如果创建项目时就指定该对话框为HTML对话框(也就是说,可以插入ActiveX),就不用进行CoInitialize/CoUninitialize操作,显然IDE已经自动生成这了部分代码。
    还有一个问题就是,如果我在类中定义一个智能指针成员变量,在构造中给它分配了资源,还需要在析构中释放它吗?它在类析构时会不会自动释放自己呢?
      

  9.   

    在类析构时会自动释放自己,但是你要保证在它释放之前CoUninitialize没有调用
      

  10.   

    Onega():我在构造中调用了CoInitialize的话,是不是应该显式的在析构中调用CoUninitialize呢?好像不这样的话,COM就会被锁定……上次好像就因为这个把我锁住了一次……
      

  11.   

    MFC程序一般在CXXApp::InitInstance()中调 AfxOleInit(),而不是调用CoInitialize()
    CoInitialize()在每个用到COM的线程中都要调用。SDK文档要求每一次成功的CoInitialize调用也要有相对应显式的调用CoUninitialize。不一定要在析构中
    你可以在ExitInstance()中 explicitly release smart pointer.也就是 设m_pXXX=NULL;
    或者,偷懒的办法:
    class Base
    {
    public:
    Base()
    {
    CoInitialize(NULL);
    }
    ~Base()
    {
    CoUninitialize();
    }
    };
    class Sub:private Base
    {
    //your smart point member here
    ...
    };
    因为base class的constructor在sub之前调用,destructor在sub之后调用,这样你不用手工release sub的smart point members
      

  12.   

    Analyst()讲的Release用法是对的,我一开始没有弄明白智能指针对.操作符和->所做的重载。.Release释放的是智能指针本身,->Release应该是所包装的对象吧……
    Onega() 的办法好
    看来今天要准备结贴了,不然区区三百分儿拿出来分有些对不起各位高手:)
      

  13.   

    有一个很想不通的事儿,在“解决方案”管理器里引用对象好像没用?不在代码中import还是不能用,只import,不在方案用引用,也一样用的挺好。
      

  14.   

    也就是说,.Release是智能指针的方法,而->Release其实是被包装的对象的方法。
      

  15.   

    >>好像不这样的话,COM就会被锁定……上次好像就因为这个把我锁住了一次……怎么锁定?好像就是资源没释放罢了。就象new了没有delete
    CoInitialize是初始化com库,CoUninitialize释放com库的资源。
      

  16.   

    就是楼上的意思,当时我的COM组件不能卸载,也不能删除,呵呵。
      

  17.   

    Onega() ( ) 的做法很聪明。我曾经做过类似的程序,我使用的是AfxOleInit,将smart pointer做为类的变量,类实例析构后smart pointer也将随之析构.
    还有实质不需要置空,只需要ptrDNSInfo.Release()之后CoUnitialize()就完事大吉。
      

  18.   

    挖塞,都是星星和多角呀,我来学习
    Analyst() is correct, the problem is that the object is released/destroyed when it goes out of the scope, but at that time, your CoUninitialize() is already called, so you got an error, try to put the code inside { ....} or in try/catch block
    HRESULT hr = CoInitialize(NULL);
    {
    IDNSInfoPtr ptrDNSInfo(__uuidof(CDNSInfo)); BSTR bstrDomainName;
    ptrDNSInfo->get_DomainName(&bstrDomainName);
    CString cstrDomainName(bstrDomainName);
    SetDlgItemText(IDC_STATIC, cstrDomainName.GetString());
    }CoUninitialize();