プログラミング

C++でのCreateObject

2006年1月19日

前の記事の続き。IDispatchの取得方法。

 C++で"WScript.Shell"オブジェクトを作成し、Invokeで"CurrentDirectory"プロパティを取得してみた。

#include <windows.h>

UINT HexToByte(LPSTR hex,int pos){
    UINT b1,b2;
    static const LPSTR ZeroToF="0123456789ABCDEFabcdef";
    for (b1=0;hex[pos]!=ZeroToF[b1];b1++);
    if (15<b1) b1=b1-6;
    for (b2=0;hex[pos+1]!=ZeroToF[b2];b2++);
    if (15<b2) b2=b2-6;
    return (b1<<4)+b2;
}

IDispatch* CreateObject(LPSTR ComName){
    int i,j;
    char ANSI[MAX_PATH];

    //Resolve DLL file name
    HKEY key;
    CLSID clsid;
    for (i=0;ANSI[i]=ComName[i];i++);
    for (j=0;ANSI[i]="\\CLSID"[j++];i++);
    if (ERROR_SUCCESS!=RegOpenKeyEx(HKEY_CLASSES_ROOT,ANSI,0,KEY_READ,&key)) return 0;
    for (i=0;ANSI[i]="CLSID\\"[i];i++);
    i=MAX_PATH-6;
    if (ERROR_SUCCESS!=RegQueryValueEx(key,NULL,0,NULL,(LPBYTE)(ANSI+6),(LPDWORD)&i)) return 0;
    RegCloseKey(key);
    for (i=0;ANSI[i];i++);
    for (j=0;ANSI[i]="\\InProcServer32"[j++];i++);
    if (ERROR_SUCCESS!=RegOpenKeyEx(HKEY_CLASSES_ROOT,ANSI,0,KEY_READ,&key)) return 0;
    clsid.Data1=(((((HexToByte(ANSI,7)<<8)+HexToByte(ANSI,9))<<8)+HexToByte(ANSI,11))<<8)+HexToByte(ANSI,13);
    clsid.Data2=(HexToByte(ANSI,16)<<8)+HexToByte(ANSI,18);
    clsid.Data3=(HexToByte(ANSI,21)<<8)+HexToByte(ANSI,23);
    for (i=0;i<2;i++) clsid.Data4[i]=HexToByte(ANSI,26+i*2);
    for (i=2;i<8;i++) clsid.Data4[i]=HexToByte(ANSI,27+i*2);
    i=MAX_PATH;
    if (ERROR_SUCCESS!=RegQueryValueEx(key,NULL,0,NULL,(LPBYTE)ANSI,(LPDWORD)&i)) return 0;
    RegCloseKey(key);

    //Load DLL & check DllGetClassObject
    HINSTANCE hDLL;
    void* Address;
    if (!(hDLL=LoadLibrary(ANSI))) return 0;
    if (!(Address=GetProcAddress(hDLL,"DllGetClassObject"))) return 0;

    //DllGetClassObject(&clsid,IID_IClassFactory,(LPVOID*)&ppv);
    IClassFactory* ppv=0;
    void *Stack1,*Stack2,*Stack3;
    Stack3=&ppv;
    Stack2=(void*)&IID_IClassFactory;
    Stack1=&clsid;
    _asm push Stack3;
    _asm push Stack2;
    _asm push Stack1;
    _asm call Address;
    _asm mov i,eax;
    if (i!=S_OK || !ppv) return 0;

    IDispatch* ppvObject=0;
    if (S_OK!=ppv->QueryInterface(IID_IClassFactory, (void**) &ppv)) return 0;
    ppv->Release();
    if (S_OK!=ppv->CreateInstance(NULL,IID_IUnknown,(void**)&ppvObject)) return 0;
    ppv->Release();
    if (!ppvObject) return 0;
    if (S_OK!=ppvObject->QueryInterface(IID_IDispatch,(void**)&ppvObject)) return 0;
    ppvObject->Release();
    
    return ppvObject;
}

WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int intShowCmd) {

    IDispatch* pDisp=CreateObject("WScript.Shell");
    if (!pDisp) return 1;

    LPOLESTR* rgszNames;
    rgszNames=new LPOLESTR;
    DISPID* rgDispId;
    rgDispId=new DISPID;
    rgszNames[0]=L"CurrentDirectory";
    int ret=pDisp->GetIDsOfNames(GUID_NULL, rgszNames,1, NULL, rgDispId);
    if (ret!=S_OK) return ret;

    DISPPARAMS* pDispParams;
    VARIANT* pVarResult;
    pDispParams=new DISPPARAMS;
    pVarResult=new VARIANT;
    pDispParams->rgdispidNamedArgs = NULL;
    pDispParams->cNamedArgs = 0;
    pDispParams->cArgs=0;
    pDispParams->rgvarg=NULL;
    ret=pDisp->Invoke(rgDispId[0], GUID_NULL, NULL,DISPATCH_PROPERTYGET,pDispParams, pVarResult,NULL, NULL);
    if (ret!=S_OK) return ret;

    if (pVarResult->vt!=VT_BSTR) return 1;
    MessageBoxW(0,pVarResult->bstrVal,L"CurrentDirectory",0);
    return 0;
}

実行結果
CreateObject

コメント

Kat (2008年7月6日 16:11:33)

このコードでは問題ないが、利用するCOMオブジェクトによっては、

OleInitialize(NULL);

を最初に実行しておかないと、うまく働かないことがある。msscript.ocx(ScriptControl)などがそれ。

参考:
http://msdn.microsoft.com/en-us/library/ms690134(VS.85).aspx

コメント送信