//////////////////////////////////////////////////////////////////////// // // Client Side Errors - translate a COM failure to a Python exception // //////////////////////////////////////////////////////////////////////// PyObject *PyCom_BuildPyException(HRESULT errorhr, IUnknown *pUnk /* = NULL */, REFIID iid /* = IID_NULL */) { PyObject *obEI = NULL; TCHAR scodeStringBuf[512]; GetScodeString(errorhr, scodeStringBuf, sizeof(scodeStringBuf)/sizeof(scodeStringBuf[0])); #ifndef MS_WINCE // WINCE doesnt appear to have GetErrorInfo() - compiled, but doesnt link! if (pUnk != NULL) { assert(iid != IID_NULL); // If you pass an IUnknown, you should pass the specific IID. // See if it supports error info. ISupportErrorInfo *pSEI; HRESULT hr; Py_BEGIN_ALLOW_THREADS hr = pUnk->QueryInterface(IID_ISupportErrorInfo, (void **)&pSEI); if (SUCCEEDED(hr)) { hr = pSEI->InterfaceSupportsErrorInfo(iid); pSEI->Release(); // Finished with this object } Py_END_ALLOW_THREADS if (SUCCEEDED(hr)) { IErrorInfo *pEI; Py_BEGIN_ALLOW_THREADS hr=GetErrorInfo(0, &pEI); Py_END_ALLOW_THREADS if (hr==S_OK) { obEI = PyCom_PyObjectFromIErrorInfo(pEI, errorhr); PYCOM_RELEASE(pEI); } } }
void WINAPI _com_issue_errorex(HRESULT hr, IUnknown *punk, REFIID riid) { void *pv; IErrorInfo *perrinfo = NULL; if (SUCCEEDED(punk->QueryInterface(riid, &pv))) { ISupportErrorInfo *pserrinfo = static_cast<ISupportErrorInfo *>(pv); if (pserrinfo->InterfaceSupportsErrorInfo(riid) == S_OK) (void)GetErrorInfo(0, &perrinfo); pserrinfo->Release(); } com_error_handler(hr, perrinfo); }
/* Determines whether we can use the error information from the source object and if so, throws that as an error. If serr is non-NULL, then the error is not thrown in R but a COMSErrorInfo object is returned with the information in it. */ HRESULT checkErrorInfo(IUnknown *obj, HRESULT status, SEXP *serr) { HRESULT hr; ISupportErrorInfo *info; fprintf(stderr, "<checkErrorInfo> %X \n", (unsigned int) status); if(serr) *serr = NULL; hr = obj->QueryInterface(IID_ISupportErrorInfo, (void **)&info); if(hr != S_OK) { fprintf(stderr, "No support for ISupportErrorInfo\n");fflush(stderr); return(hr); } info->AddRef(); hr = info->InterfaceSupportsErrorInfo(IID_IDispatch); info->Release(); if(hr != S_OK) { fprintf(stderr, "No support for InterfaceSupportsErrorInfo\n");fflush(stderr); return(hr); } IErrorInfo *errorInfo; hr = GetErrorInfo(0L, &errorInfo); if(hr != S_OK) { /* fprintf(stderr, "GetErrorInfo failed\n");fflush(stderr); */ COMError(status); return(hr); } /* So there is some information for us. Use it. */ SEXP klass, ans, tmp; BSTR ostr; char *str; errorInfo->AddRef(); if(serr) { PROTECT(klass = MAKE_CLASS("SCOMErrorInfo")); PROTECT(ans = NEW(klass)); PROTECT(tmp = NEW_CHARACTER(1)); errorInfo->GetSource(&ostr); SET_STRING_ELT(tmp, 0, COPY_TO_USER_STRING(FromBstr(ostr))); SET_SLOT(ans, Rf_install("source"), tmp); UNPROTECT(1); PROTECT(tmp = NEW_CHARACTER(1)); errorInfo->GetDescription(&ostr); SET_STRING_ELT(tmp, 0, COPY_TO_USER_STRING(str = FromBstr(ostr))); SET_SLOT(ans, Rf_install("description"), tmp); UNPROTECT(1); PROTECT(tmp = NEW_NUMERIC(1)); NUMERIC_DATA(tmp)[0] = status; SET_SLOT(ans, Rf_install("status"), tmp); *serr = ans; UNPROTECT(3); errorInfo->Release(); PROBLEM "%s", str WARN; } else { errorInfo->GetDescription(&ostr); str = FromBstr(ostr); errorInfo->GetSource(&ostr); errorInfo->Release(); PROBLEM "%s (%s)", str, FromBstr(ostr) ERROR; } return(hr); }
/******************************************************************** SqlGetErrorInfo - gets error information from the last SQL function call NOTE: pbstrErrorSource and pbstrErrorDescription are optional ********************************************************************/ extern "C" HRESULT DAPI SqlGetErrorInfo( __in IUnknown* pObjectWithError, __in REFIID IID_InterfaceWithError, __in DWORD dwLocaleId, __out_opt BSTR* pbstrErrorSource, __out_opt BSTR* pbstrErrorDescription ) { HRESULT hr = S_OK; Assert(pObjectWithError); // interfaces needed to extract error information out ISupportErrorInfo* pISupportErrorInfo = NULL; IErrorInfo* pIErrorInfoAll = NULL; IErrorRecords* pIErrorRecords = NULL; IErrorInfo* pIErrorInfoRecord = NULL; // only ask for error information if the interface supports it. hr = pObjectWithError->QueryInterface(IID_ISupportErrorInfo,(void**)&pISupportErrorInfo); ExitOnFailure(hr, "No error information was found for object."); hr = pISupportErrorInfo->InterfaceSupportsErrorInfo(IID_InterfaceWithError); ExitOnFailure(hr, "InterfaceWithError is not supported for object with error"); // ignore the return of GetErrorInfo it can succeed and return a NULL pointer in pIErrorInfoAll anyway hr = ::GetErrorInfo(0, &pIErrorInfoAll); ExitOnFailure(hr, "failed to get error info"); if (S_OK == hr && pIErrorInfoAll) { // see if it's a valid OLE DB IErrorInfo interface that exposes a list of records hr = pIErrorInfoAll->QueryInterface(IID_IErrorRecords, (void**)&pIErrorRecords); if (SUCCEEDED(hr)) { ULONG cErrors = 0; pIErrorRecords->GetRecordCount(&cErrors); // get the error information for each record for (ULONG i = 0; i < cErrors; ++i) { hr = pIErrorRecords->GetErrorInfo(i, dwLocaleId, &pIErrorInfoRecord); if (SUCCEEDED(hr)) { if (pbstrErrorSource) { pIErrorInfoRecord->GetSource(pbstrErrorSource); } if (pbstrErrorDescription) { pIErrorInfoRecord->GetDescription(pbstrErrorDescription); } ReleaseNullObject(pIErrorInfoRecord); break; // TODO: return more than one error in the future! } } ReleaseNullObject(pIErrorRecords); } else // we have a simple error record { if (pbstrErrorSource) { pIErrorInfoAll->GetSource(pbstrErrorSource); } if (pbstrErrorDescription) { pIErrorInfoAll->GetDescription(pbstrErrorDescription); } } } else { hr = E_NOMOREITEMS; } LExit: ReleaseObject(pIErrorInfoRecord); ReleaseObject(pIErrorRecords); ReleaseObject(pIErrorInfoAll); ReleaseObject(pISupportErrorInfo); return hr; }
int _tmain(int argc, _TCHAR* argv[]) { HRESULT hr; // COM 戻り値用変数 IClassTest* pClassTest; // COMインターフェイスポインタ // COMの初期化 ◆◆追加 hr = ::CoInitialize(NULL); if(FAILED(hr)){ printf("CoInitialize 失敗\n"); return 0; } // ---------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------- // <以下のコードは、アーリーバインディング方式での呼び出し> // インスタンスの作成(CLSID:[CLSID_ClassTest]とIID:[IID_IClassTest]を指定して、ポインタを取得) hr = ::CoCreateInstance((REFCLSID) CLSID_ClassTest, 0, CLSCTX_INPROC_SERVER, (REFIID) IID_IClassTest, (LPVOID*)&pClassTest); if(FAILED(hr)){ printf("CoCreateInstance 失敗\n"); return 0; } // BSTRを処理する場合は、_bstr_tが楽(解放など) // http://mzs184.blogspot.com/2008/04/bstrbstrt.html // _bstr_t Class // http://msdn.microsoft.com/ja-jp/library/zthfhkd6.aspx // _bstr_t::operator = // http://msdn.microsoft.com/ja-jp/library/7bh2f8sk.aspx _bstr_t bstrText = L"だいすけ"; _bstr_t bstrCaption = L"にしの"; _bstr_t bstrRetVal; // メソッド呼び出し // _bstr_t::wchar_t*, _bstr_t::char* // BSTRはOLECHAR(= WCHAR)のポインタなので適用可能。 // http://msdn.microsoft.com/ja-jp/library/btdzb8eb.aspx // _bstr_t::GetAddress // http://msdn.microsoft.com/ja-jp/library/t2x13207.aspx hr = pClassTest->MethodTest(bstrText, bstrCaption, bstrRetVal.GetAddress()); if(FAILED(hr)){ printf("MethodTest 失敗\n"); return 0; } MessageBox(NULL, bstrRetVal, L"戻り値", MB_OK); // bstrRetValをクリア(DetachしてSysFreeString) // _bstr_t::Detach // http://msdn.microsoft.com/en-us/library/3c73x1sf.aspx // SysFreeString // http://msdn.microsoft.com/ja-jp/site/ms221481 BSTR bstr = bstrRetVal.Detach(); if(bstr != NULL) { SysFreeString(bstr); } // bstrCaptionの再設定 bstrCaption = L""; // メソッド呼び出し(同上) hr = pClassTest->MethodTest(bstrText, bstrCaption, bstrRetVal.GetAddress()); // Dr.GUI Online // Dr.GUI と COM オートメーション、 // 第 3 部:続 COM のすばらしきデータ型 // http://msdn.microsoft.com/ja-jp/library/cc482694.aspx // ISupportErrorInfo、IErrorInfoでエラー情報を取得 if(FAILED(hr)) { // IID_ISupportErrorInfoインターフェイスを取得 ISupportErrorInfo *pSupport; hr = pClassTest->QueryInterface(IID_ISupportErrorInfo, (void**)&pSupport); if (SUCCEEDED(hr)) { hr = pSupport->InterfaceSupportsErrorInfo(IID_IClassTest); if (hr == S_OK) { // can't use SUCCEEDED here! S_FALSE succeeds! IErrorInfo *pErrorInfo; hr = GetErrorInfo(0, &pErrorInfo); if (SUCCEEDED(hr)) { // FINALLY can call methods on pErrorInfo! ...and handle the error! _bstr_t bstrErrorDescription; pErrorInfo->GetDescription(bstrErrorDescription.GetAddress()); // エラー情報 MessageBox(NULL, bstrErrorDescription, L"ErrorDescription", MB_OK); // don't forget to release! pErrorInfo->Release(); } } // don't forget to release! pSupport->Release(); } } // don't forget to release! pClassTest->Release(); // ---------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------- // <以下のコードは、レイトバインディング方式での呼び出し> // CLSID の取得 CLSID clsid; hr = CLSIDFromProgID(L"VC_COM.ClassTest", &clsid); if(FAILED(hr)){ printf("CLSIDFromProgID 失敗\n"); return 0; } // インスタンスの作成(CLSIDとIID:[IID_IDispatch]を指定して、ポインタを取得) IDispatch* pDisp = NULL; hr = ::CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IDispatch, (void**)&pDisp); if(FAILED(hr)){ printf("CoCreateInstance 失敗\n"); return 0; } // COMディスパッチ識別子の取得 DISPID dispID; OLECHAR* wszName = L"MethodTest"; hr = pDisp->GetIDsOfNames(IID_NULL, &wszName, 1, LOCALE_USER_DEFAULT, &dispID); if(FAILED(hr)){ printf("GetIDsOfNames 失敗\n"); exit(1); } // CComVariant クラス(CComVariant は VARIANT 型から派生) // http://msdn.microsoft.com/ja-jp/library/ac97df2h.aspx // 引数を VARIANT 配列に設定 CComVariant pvArgs[2]; pvArgs[0] = L"だいすけ"; pvArgs[1] = L"にしの"; // 戻り値を VARIANT変数 CComVariant pvResult; // DISPPARAMS の設定 DISPPARAMS dispParams; dispParams.rgvarg = pvArgs; dispParams.rgdispidNamedArgs = NULL; dispParams.cArgs = 2; dispParams.cNamedArgs = 0; // メソッドにレイトバインド(Invoke) hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispParams, &pvResult, NULL, NULL); if(FAILED(hr)){ printf("MethodTest 失敗\n"); return 0; } // BSTRで格納されている時、tagVARIANTのメンバ、bstrValで取得可能。 // BSTRはOLECHAR(= WCHAR)のポインタなのでLPWSTRにキャスト可能。 MessageBox(NULL, (LPWSTR)pvResult.bstrVal, L"戻り値", MB_OK); // don't forget to release! pDisp->Release(); // ---------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------- // COMの終了処理 ◆◆追加 ::CoUninitialize(); return 0; }