////////////////////////////////////////////////////////////////////////
//
// 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);
			}
		}
	}
Exemple #2
0
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);
}
Exemple #3
0
/* 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);
}
Exemple #4
0
/********************************************************************
 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;
}