1

I'm building a COM component C#, where the customer can set binary data. It would be nice if the COM component returns exception rather than error code but I realized it would be difficult to handle exceptions in (Delphi, C + + and JScritp). Instead, I chose to receive data in hexadecimal (and internally convert to binary) and return in hexadecimal (internally convert binary to hexadecimal).
The method getData can return the data and an error code, now my question is: how to do this in C# interop?

in C++ COM, HRESULT exists

HRESULT getData([in] int __position, [out,retval] BSTR* __data); // can Return __data or error -1 data not exists
HRESULT setData([in] BSTR __data, [out,retval] int* __status);

But what is it's equivalent in C#?

int getData ??? // return __status or __data;
int setData(String __data); // return __status;

Thanks in advance!

6
  • Where is your problem? There's no question here. Commented Jul 25, 2011 at 20:09
  • I tried to amend the wording. Commented Jul 25, 2011 at 20:17
  • I think you are trying to ask, how do you control the HRESULT value in a COM Interface method. See my answer below. Commented Jul 25, 2011 at 20:21
  • @Shane Powell, Sorry for the confusion, not handle but throw. I would like to return error code or data. Exception solve, but it is difficult to capture C# Interop COM exception in Delphi, C++ and JScript. Commented Jul 25, 2011 at 20:31
  • 1
    Exceptions is how .net runtime handle COM HRESULTS (that are errors). .net runtime converts HRESULT values to from/to exceptions. How the COM client handles HRESULT is up to language runtime. In C++ you just get the HRESULT and you have to handle it. In other runtimes it will differ. Commented Jul 25, 2011 at 20:39

4 Answers 4

6

C# maps known C# exceptions to HRESULT values. Here is Microsoft's documentation on the mapping list. You can get further control by throwing a COMException.

Sign up to request clarification or add additional context in comments.

3 Comments

Hi @Shane Powell. You are saying I can throw an exception in C# Interop and capture in (Delphi, C++ and JScript) ?
No, I'm saying that you throw an exception and the .net runtime converts it to a HRESULT return value. How the HRESULT COM value is interrupted on the other side is up to them. For example in C++ you get the raw HRESULT value, if called from C# it will convert the HRESULT back into a exception. I don't know what happens in Delphi or JScript, you will have to look up how those languages interop with COM.
use safecall in delphi and the HRESULT will be transformed into an exception.
2

You should return an HRESULT from each COM method and return the data in out parameters. However, the COM interop layer shields this from you by automatically translating between COM HRESULT error codes and C# exceptions. I think your code should really look like this:

MIDL

HRESULT getData([out,retval] BSTR* pData);
HRESULT setData([in] BSTR data);

C#

String getData();
void setData(String data);

The key point is that the COM function return value is always an HRESULT. If the function succeeds then S_OK is returned—otherwise you an appropriate error code that describes the reason for failure is returned. The true return value, data in this example, is returned through an out parameter rather than the return value. But of course, the COM interop layer hides that implementation detail from you.

Your question appears to suggest that you wish for the return value to be either an HRESULT in case of failure, or a string in case of success. This is not possible since function return values are statically typed.

12 Comments

Thanks, this is what I need. Thus, the method may return error code or data. Sorry for my vague question.
Technically you return both error code and data but data only means something when error code is S_OK.
S_OK in C#? I did not understand. I tryed here, return data and -1 and works (C# to C++), I will return 0 if ok.
int getData(out String __data); will look in COM as HRESULT getData([out] BSTR* __data, [out, retval] int*), as in msdn.microsoft.com/en-us/library/aa367158%28v=vs.85%29.aspx. You cannot mix the COM HRESULT semantics with the C# method return value, they represent different things.
Your own post uses the same convention, does it not? Point is that the c++ signature will take the int return of C# as an output parameter (int*), not as the return C/C++ value. You cannot return an int in C# (S_OK) and expect this to be the HRESULT value seen by the COM caller.
|
2

Just throw an exception in C#. The C# interop layer will know how to catch the exception, return a E_FAIL hresult (or other appropriate value if the C# exception is known or a COMException that specifies the value explicitly) and setup the IErrorInfo on your COM object. The C++ smart COM pointers like _com_ptr_t know how to handle this case and will raise an appropriate C++ exception.

See Handling COM Interop Exceptions.

5 Comments

in C# i did public int getData(out String ret){ ret = "data"; throw new Exception(); return -1;} in C++ try { BSTR test; int error = objCOM->getData(&test); } catch(exception e) { }. But not works.
is objCom a smart pointer (_com_ptr_t) or a raw pointer? A row pointer has to go the long route (query interface for IErrorInfo and then ask the error infor from there). Use a smart pointer and will take care of the details for you.
Actually I may remember things wrong. _com_ptr_t does not throw automatically, you still need to check the HRESULT and raise an _com_Error explcitly. See codereview.stackexchange.com/questions/259/…
thanks, i tried with CComPtr but Unhandled exception at 0x7c812afb, this is my code: HRESULT errorCheck; ATL::CComPtr<IMyClassCOM> objCOM; CoInitialize(NULL); errorCheck = objCOM.CoCreateInstance(CLSID_MyClassCOM, 0, CLSCTX_INPROC_SERVER); if (SUCCEEDED(errorCheck)) { try { BSTR test; int error = objCOM->getData(&test); } catch(exception e) ... C# throw new Exception, C++ can't handle. C# code: public int getData(out String ret) { ret = "data"; throw new Exception(); return -1; }
CComPtr throws CAtlException I think, so catch(exception e) will not work because CAtlException is not derived from std::exception. Try adding a catch(CAtlExceptio& e) and/or a catch(...) in the C++ code.
0

This should work:

[DllImport(DllName)]
static extern int getData(int __position, StringBuilder __data);

3 Comments

Hi @SwDevMan81. I'm not using c++ dll, I only want to write a method thats can return (String or Error code) in C# COM. Thanks.
@Cobaia - To return two values you could use a KeyValuePair (like here: dotnetperls.com/multiple-return-values). Or you can assign values to the parameters using the 'out' keyword
DLLImport and StringBuilder are not appropriate here. This is COM interop rather than P/invoke.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.