在VC中只知道CLSID和IID怎么調用對象?


在VB里可以使用CreateObject來生成COM對象。
如set a = CreateObject("Wscript.Shell")
a.RegDelete ......
怎么在VC里使用呢?
生成一個象a一樣的對象?
 
以下是我的代碼:

defination
#include...
const IID IID_WSH_SHELL = 
{0xF935DC21,0x1CF0, 0x11d0, {0xAD, 0xB9, 0x00, 0xC0, 0x4F, 0xD5, 0x8A, 0x0B}};
    
const CLSID CLSID_WSH_SHELL = 
{0xF935DC22,0x1CF0, 0x11d0, {0xAD, 0xB9, 0x00, 0xC0, 0x4F, 0xD5, 0x8A, 0x0B}};
    
    EXTERN_C const IID IID_IWScriptShell;
    
    interface DECLSPEC_UUID("F935DC21-1CF0-11d0-ADB9-00C04FD58A0B")

IWScriptShell : public IUnknown
    {
    public:
        virtual LPDISPATCH STDMETHODCALLTYPE GetSpecialFolders() = 0;
        virtual LPDISPATCH STDMETHODCALLTYPE GetEnvironment(VARIANT* pvarType) = 0;
        virtual long STDMETHODCALLTYPE Run(LPCTSTR bstrCommand, VARIANT* pvarWindowStyle, VARIANT* pvarWaitOnReturn) = 0;
        virtual long STDMETHODCALLTYPE Popup(LPCTSTR bstrText, VARIANT* pvarSecondsToWait, VARIANT* pvarTitle, VARIANT* pvarType) = 0;
        virtual LPDISPATCH STDMETHODCALLTYPE CreateShortcut(LPCTSTR bstrPathLink) = 0;
        virtual LPSTR STDMETHODCALLTYPE ExpandEnvironmentStrings(LPCTSTR bstrSrc) = 0;
        virtual VARIANT STDMETHODCALLTYPE RegRead(LPCTSTR bstrName) = 0;
        virtual void STDMETHODCALLTYPE RegWrite(LPCTSTR bstrName, VARIANT* pvValue, VARIANT* pvarType) = 0;
        virtual void STDMETHODCALLTYPE RegDelete(LPCTSTR bstrName) = 0;
    };

usage:
    HRESULT sc;
    IWScriptShell *pWshShell = NULL;

    sc = CoCreateInstance( CLSID_WSH_SHELL, NULL, CLSCTX_SERVER, 
        IID_WSH_SHELL, (LPVOID *) &pWshShell );
    if( FAILED(sc) )
        return;

    pWshShell->.....(use it)
    pWshShell->Release();
但是不行,VC說wshom.ocx Loaded,但是無法使用其中的方法(sc Succeed)
如何解決?  

49 个解决方案

#1


http://www.csdn.net/expert/topic/196/196464.shtm
解決者請去那兒再拿100分。

#2


gz

#3


應該這樣就可以了啊,我試試

#4


CoInitialize(NULL);//你少了這句話
加載 CoCreateInstance(...)前面

#5


你這裡的 IWscriptShell 是如何來的? 不會是自己寫的吧.
我從 wshom.ocx 中 import 的 IWshShell 的定義不同, 至少是繼承於 IDispatch 的. 
所以直接通過類調用肯定有問題.
我覺得有兩種解決方法, 一是使用 #import "wshom.ocx" no_namespace ... 來取得各種 Interface 的定義, 再調用其中的方法, 另外是直接使用 IDispatch 的 Invoke 來調用
相應的方法.

#6


IWScriptShell我是根據wshom.ocx的導出信息來定義的一個類,我在想怎么調用,反正哪位大哥給出一個可以使用的例子就200分送上,可以的話,可以再加200。

#7


我使用RegDelete時沒有出錯信息,但是沒有正確執行。
RegRead時報錯。Access Denied。

#8


我做了一個簡單的 Win32 Console 測試程序, 運行沒有什麼問題, 可是Debug時有First-Chance Exception. :-(

#include <stdio.h>

#import "wshom.ocx" no_namespace

void dump_com_error( _com_error &e ) 
{     
char buf[2048];      
sprintf(buf, "Oops - hit an error!\n\tCode = %08lx\n\tCode meaning = %s\n",
e.Error(), e.ErrorMessage());     
OutputDebugString(buf); 
}  

int main()
{
HRESULT hr;
_bstr_t bstrValue;

CoInitialize(NULL);
try
{
IWshShellPtr pShell;

hr = pShell.CreateInstance(__uuidof(IWshShell_Class));
if(FAILED(hr))
{
CoUninitialize();
return 0;
}
pShell->Run("Notepad.exe");
}
catch(_com_error &e)
{
dump_com_error(e);
}
CoUninitialize();
return 1;
}

#9


注意, 要找到 wshom.ocx 並把它 Copy 到工程路徑下.

#10


高手,老實說,我還看不太懂,呵呵。但是這個程序有那么一點意思了。
能否給個E-mail,討論一下,在下對COM還不熟呢。呵呵。
smint@21cn.com

#11


copy我知道。我指定路徑就可以了。

#12


copy好象用不着,最好也別那樣做,如果你的控件是真的已經注冊了的話,那樣做反而不好。

我看好象不應該有那么多問題,根據COM的做法,知道CLSID后,無非由CoGetClassObject找到類廠,然后得到一個COM對象,再后來QueryInterface,可以得到接口,然后可以調用函數了

怎么啦?

#13


對的。不然使用指定的方法,似乎失去了COM的一些優越性,變得和DLL一樣了阿?

#14


不過我把Wshom.ocx的導出信息改寫為.h形式再include進來是可以使用的。
根據導出的信息,針對IWshShell寫了以下這個頭文件:
wshshell.h

#include <comdef.h>

struct __declspec(uuid("f935dc21-1cf0-11d0-adb9-00c04fd58a0b"))
/* dual interface */ IWshShell;

struct /* coclass */ IWshShell_Class;

_COM_SMARTPTR_TYPEDEF(IWshShell, __uuidof(IWshShell));

struct __declspec(uuid("f935dc21-1cf0-11d0-adb9-00c04fd58a0b"))
IWshShell : IDispatch
{
    int Run (
        _bstr_t bstrCommand,
        VARIANT * pvarWindowStyle = &vtMissing,
        VARIANT * pvarWaitOnReturn = &vtMissing );
    int Popup (
        _bstr_t bstrText,
        VARIANT * pvarSecondsToWait = &vtMissing,
        VARIANT * pvarTitle = &vtMissing,
        VARIANT * pvarType = &vtMissing );
    IDispatchPtr CreateShortcut (
        _bstr_t bstrPathLink );
    _bstr_t ExpandEnvironmentStrings (
        _bstr_t bstrSrc );
    _variant_t RegRead (
        _bstr_t bstrName );
    HRESULT RegWrite (
        _bstr_t bstrName,
        VARIANT * pvValue,
        VARIANT * pvarType = &vtMissing );
    HRESULT RegDelete (
        _bstr_t bstrName );

    //
    // Raw methods provided by interface
    //

    virtual HRESULT __stdcall get_SpecialFolders (
        struct IWshCollection * * out_pFolders ) = 0;
    virtual HRESULT __stdcall get_Environment (
        VARIANT * pvarType,
        struct IWshEnvironment * * out_pEnv ) = 0;
    virtual HRESULT __stdcall raw_Run (
        BSTR bstrCommand,
        VARIANT * pvarWindowStyle,
        VARIANT * pvarWaitOnReturn,
        int * out_nExitCode ) = 0;
    virtual HRESULT __stdcall raw_Popup (
        BSTR bstrText,
        VARIANT * pvarSecondsToWait,
        VARIANT * pvarTitle,
        VARIANT * pvarType,
        int * out_nButton ) = 0;
    virtual HRESULT __stdcall raw_CreateShortcut (
        BSTR bstrPathLink,
        IDispatch * * out_pShortcut ) = 0;
    virtual HRESULT __stdcall raw_ExpandEnvironmentStrings (
        BSTR bstrSrc,
        BSTR * bstrDst ) = 0;
    virtual HRESULT __stdcall raw_RegRead (
        BSTR bstrName,
        VARIANT * out_varValue ) = 0;
    virtual HRESULT __stdcall raw_RegWrite (
        BSTR bstrName,
        VARIANT * pvValue,
        VARIANT * pvarType = &vtMissing ) = 0;
    virtual HRESULT __stdcall raw_RegDelete (
        BSTR bstrName ) = 0;
};


struct __declspec(uuid("f935dc22-1cf0-11d0-adb9-00c04fd58a0b"))
IWshShell_Class;

//
// interface IWshShell wrapper method implementations
//

inline int IWshShell::Run ( _bstr_t bstrCommand, VARIANT * pvarWindowStyle, VARIANT * pvarWaitOnReturn ) {
    int _result;
    HRESULT _hr = raw_Run(bstrCommand, pvarWindowStyle, pvarWaitOnReturn, &_result);
    if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
    return _result;
}

inline int IWshShell::Popup ( _bstr_t bstrText, VARIANT * pvarSecondsToWait, VARIANT * pvarTitle, VARIANT * pvarType ) {
    int _result;
    HRESULT _hr = raw_Popup(bstrText, pvarSecondsToWait, pvarTitle, pvarType, &_result);
    if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
    return _result;
}

inline IDispatchPtr IWshShell::CreateShortcut ( _bstr_t bstrPathLink ) {
    IDispatch * _result;
    HRESULT _hr = raw_CreateShortcut(bstrPathLink, &_result);
    if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
    return IDispatchPtr(_result, false);
}

inline _bstr_t IWshShell::ExpandEnvironmentStrings ( _bstr_t bstrSrc ) {
    BSTR _result;
    HRESULT _hr = raw_ExpandEnvironmentStrings(bstrSrc, &_result);
    if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
    return _bstr_t(_result, false);
}

inline _variant_t IWshShell::RegRead ( _bstr_t bstrName ) {
    VARIANT _result;
    VariantInit(&_result);
    HRESULT _hr = raw_RegRead(bstrName, &_result);
    if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
    return _variant_t(_result, false);
}

inline HRESULT IWshShell::RegWrite ( _bstr_t bstrName, VARIANT * pvValue, VARIANT * pvarType ) {
    HRESULT _hr = raw_RegWrite(bstrName, pvValue, pvarType);
    if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
    return _hr;
}

inline HRESULT IWshShell::RegDelete ( _bstr_t bstrName ) {
    HRESULT _hr = raw_RegDelete(bstrName);
    if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
    return _hr;
}

把原來#import "wshom.ocx" no_namespace的地方改為#include "wshshell.h"就可以了。但是原來的程序我不太了解,不知道,能不能解釋介紹一下。

#15


還有ahphone(阿豐)老兄說的話也太抽象了。聽來如墜雲霧里。

#16


因為只看書,基本不動手寫的緣故~~~~~~

#17


你可以這樣試一試:
    HRESULT sc;
    IWScriptShell *pWshShell = NULL;

    sc = CoCreateInstance( CLSID_WSH_SHELL, NULL, CLSCTX_SERVER, 
        IID_IUnknown, (LPVOID *) &pWshShell );
    if( FAILED(sc) )
        return;

    //pWshShell->.....(use it)
    pWshShell->Release();

還有就是確定一下dwClsContex,或通過錯誤代碼找一下原因.

/*usage@263.net*/

#18


To usage():
你的意思是使用以上的頭文件,然后使用這個方法來創建對象嗎?
To SuperChen(兔子):
那個問題解決了嗎?好像只有在使用Run的時候才有這個問題的。

#19


程序結構是懂了,怎么感覺有點不一樣?
smint(smint) :你要是先看潘愛民的那本COM原理與應用,對我的話就不雲里霧里了。

#20


不是不懂你的話,只是對於應用無補阿!
什么地方說起COM就是這幾句話阿,哈哈。

#21


理論和應用始終是有差距的。

#22


gz

#23


媽的,什么唧唧歪歪的!
都說看書,還要CSDN的BBS干嗎?好像很拽的樣子,掂掂自己份量先!

#24


我還是比較欣賞實干的人,不要老是跟我說什么什么書上有。煩!
我手頭沒有書,只有MSDN!

#25


使用以下函數
STDAPI CoCreateInstance(
  REFCLSID rclsid,     //要創建的了的CLSID
  LPUNKNOWN pUnkOuter, //一般為空!除非有聚合類
  DWORD dwClsContext,  //服務器的類型!有如下三種
//CLSCTX_INPROC_SERVER, CLSCTX_INPROC_HANDLER, CLSCTX_LOCAL_SERVER
//分別對應近程內的!進程間!本地服務器
  REFIID riid,         //要申請的接口ID
  LPVOID * ppv         //要放接口的指針變量的地址!是地址喲
);
然后你就可以使用這個接口調用函數了

#26


這個MSDN上有的。一般COM就是用這個東西的

#27


我現在想知道First-Chance Exception問題的解決和SuperChen(兔子)代碼的含義。他的代碼和普通用CoCreateInstance不同的。

#28


Exception 的問題還沒搞定.

不是不能使用 CoCreateInstance, 關鍵的是那個 Interface(IWshShell) 的定義一定要是正確的, 實際上 IWshShell 和你的定義不同, 其中的真正 Method 的位置和你所定義的有偏差, 所以你調用其中的方法可能因為參數不合要求會出錯.

我寫的那幾行Code只是使用了VC所提供的封裝 COM 常用功能的類, 具體什麼意思可以查一下MSDN, 或者直接到 include 目錄下看一下 comdef.h, comip.h, comutil.h ... 相信很容易理解.

#29


對的。本來的我的類定義運行后總是說有問題的。或者干脆什么都沒有。

#30


還有如果使用CoCreateInstance的方法,不知道可不可以的?怎么作?

#31


CoCreateInstance

#32


STDAPI CoCreateInstance(
  REFCLSID rclsid,     //Class identifier (CLSID) of the object
  LPUNKNOWN pUnkOuter, //Pointer to whether object is or isn't part 
                       // of an aggregate
  DWORD dwClsContext,  //Context for running executable code
  REFIID riid,         //Reference to the identifier of the interface
  LPVOID * ppv         //Address of output variable that receives 
                       // the interface pointer requested in riid
);
 

#33


COM對象是進程外組件啊!並且IWScriptShell接口不是自動化接口(從IDispath派生),
這時調用IWScriptShell方法需要注冊proxy/stub(列集/散集)鏈接庫(XXXps.dll)支持.好像VC中調用COM需要xxxx_i.c和xxxx.h頭文件支持!


XXXps.dll生成/注冊方法:
   nmake -f XXXps.mk
   regsvr32 XXXps.dll

  

#34


樓上的:有兩種COM啦,第一種就是作者提到的,還有一種是你提到的。

不過我一種都不熟,嘻。

#35


davidprg():
   哈哈,看花眼了!對不起大家!

#36


COM好復雜,沒時間玩。。。

#37


SuperChen(兔子)說的很對!

#38


“不是不能使用 CoCreateInstance, 關鍵的是那個 Interface(IWshShell) 的定義一定要是正確的, 實際上 IWshShell 和你的定義不同, 其中的真正 Method 的位置和你所定義的有偏差, 所以你調用其中的方法可能因為參數不合要求會出錯.”

SuperChen(兔子)的這句話一針見血!這就是出錯的原因

#39


對的。但是我們只有一個編譯好的組件,如wshom.ocx如果要生成正確的定義。怎么做呢?
VB中很簡單的。VC中如何來申明呢?又如何生成一個對象的實例呢?

#40


能說得詳細明了的,請到
http://www.csdn.net/expert/topic/196/196464.shtm
取另100分。

#41


SuperChen(兔子)已經說得很清楚了.我的試驗也反映IWshShell的定義和你給的不一樣.
你無需自己去定義組件接口,使用import方法就產生了相關接口定義(wshom.tlh中).而且也無需你改為.h和include.
至於Debug時有First-Chance Exception.我想可以不用理會.
我在Debug MSDN的sample時也常有這樣的問題.

#42


不是的。import必須指定路徑。難道這種方式也就是vc的COM方式?我們現在最好就是只有CLSID和IID和它的一些接口,然后來使用。

#43


import只是輔助.
其實只需要一個idl.這才是原始的方式.

#44


#import只是生成了接口定義文件,而這個文件僅僅在編譯時需要使用,一旦生成可執行文件,就與路徑無關了。
換句話說,#import是給編譯程序用的,用來生成接口定義文件,編譯生成可執行文件后,就與#import中指定的路徑無關了。

#45


大家都是高手,我學了很長時間的vc++,還沒學會。
能告訴我怎么學嗎?

#46


zch_kitty(香水百合):
1、領導分配你一個任務,要求用VC完成;
2、找高手帶一把。

#47


我是搞硬件的,導師不在,去了美國。
師兄的水平很高,可也神龍見首不見尾!

#48


很簡單,包含頭文件#include <IWSHom.h>即可
直接使用其中的組件和接口的定義,而不是自己再去生成。

#49


&Ouml;

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com