Exception de managé à non managé
Bonjour,
j'ai une Dll c++/cli qui fait le pont entre une lib C# et une appli C++.
Je souhaite pouvoir attrapper toutes les exceptions managés pour lancer des exceptions non managé en transmettant le message d'erreur.
Je pense que le mieux c'est de le faire dans le code managé. Le problème c'est que depuis là, je n'arrive pas à créer un objet de type exception non managé car le type "Exception" est managé de ce point de vue là de la Dll.
Donc voilà, comment lancer une Exception non managé depuis du code managé ?
catch exception in unmanaged code via managed code
bonjour
le mieux à faire c'est que tu dis et ce que l'api .Net Framework permet .Le support .Net FrameWork est fourni pour des appels P/INVOKE et des Appel à des Interfaces Com .
1/PINVOKE (attribut Importdll)
-System.Exception.Marshal.GetLastWin32Error
-ennui: il faut se taper la sdk WIN32 pour les messages correspondant à chaque error code renvoye par la fonction.
code c# sharp
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
|
using System;
using System.Runtime.InteropServices;
internal class Win32
{
// Use DllImportAttribute to inport the Win32 MessageBox
// function. Set the SetLastError flag to true to allow
// the function to set the Win32 error.
[DllImportAttribute("user32.dll", SetLastError=true)]
public static extern int MessageBox(IntPtr hwnd, String text, String caption, uint type);
}
class Program
{
static void Run()
{
// Call the MessageBox with normal parameters.
Console.WriteLine("Calling Win32 MessageBox without error...");
Win32.MessageBox(new IntPtr(0), "Press OK...", "Press OK Dialog", 0);
// Get the last error and display it.
int error = Marshal.GetLastWin32Error();
Console.WriteLine("The last Win32 Error was: " + error);
// Call the MessageBox with an invalid window handle to
// produce a Win32 error.
Console.WriteLine("Calling Win32 MessageBox with error...");
Win32.MessageBox(new IntPtr(123132), "Press OK...", "Press OK Dialog", 0);
// Get the last error and display it.
error = Marshal.GetLastWin32Error();
Console.WriteLine("The last Win32 Error was: " + error);
}
static void Main(string[] args)
{
Run();
}
}
// This code example displays the following to the console:
//
// Calling Win32 MessageBox without error...
// The last Win32 Error was: 0
// Calling Win32 MessageBox with error...
// The last Win32 Error was: 1400 |
code c++/cli:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
|
using namespace System;
using namespace System::Runtime::InteropServices;
public value struct Point
{
public:
property int X;
property int Y;
};
extern bool CloseHandle(IntPtr h);
int main()
{
// Demonstrate the use of public static fields of the Marshal
// class.
Console::WriteLine(
"SystemDefaultCharSize={0},SystemMaxDBCSCharSize={1}",
Marshal::SystemDefaultCharSize,
Marshal::SystemMaxDBCSCharSize);
// Demonstrate the use of the SizeOf method of the Marshal
// class.
Console::WriteLine("Number of bytes needed by a Point object: {0}",
Marshal::SizeOf(Point::typeid));
Point point;
Console::WriteLine("Number of bytes needed by a Point object: {0}",
Marshal::SizeOf(point));
// Demonstrate how to call GlobalAlloc and
// GlobalFree using the Marshal class.
IntPtr hglobal = Marshal::AllocHGlobal(100);
Marshal::FreeHGlobal(hglobal);
// Demonstrate how to use the Marshal class to get the Win32
// error code when a Win32 method fails.
bool isCloseHandleSuccess = CloseHandle(IntPtr(-1));
if (!isCloseHandleSuccess)
{
Console::WriteLine(
"CloseHandle call failed with an error code of: {0}",
Marshal::GetLastWin32Error());
}
};
// This is a platform invoke prototype. SetLastError is true,
// which allows the GetLastWin32Error method of the Marshal class
// to work correctly.
[DllImport("Kernel32", ExactSpelling = true, SetLastError = true)]
extern bool CloseHandle(IntPtr h);
// This code produces the following output.
//
// SystemDefaultCharSize=2, SystemMaxDBCSCharSize=1
// Number of bytes needed by a Point object: 8
// Number of bytes needed by a Point object: 8
// CloseHandle call failed with an error code of: 6 |
1/Appel à des interfaces COM
Lorsque du code managé lève une exception, le runtime passe la valeur HRESULT au client COM(NB:passe automatiquement au system qui a genere la var exception HRESULT pour qu'il renseinge ses champs "). Lorsque du code non managé retourne une erreur, la valeur HRESULT est convertie en une exception qui est ensuite levée par le runtime .Net FrameWork.
utilisation de "Exception.HResult" en code c# :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
// Example for the Exception.HResult property.
using System;
namespace NDP_UE_CS
{
// Create the derived exception class.
class SecondLevelException : Exception
{
const int SecondLevelHResult = unchecked( (int)0x81234567 );
// Set HResult for this exception, and include it in
// the exception message.
public SecondLevelException( string message, Exception inner ) :
base( string.Format( "(HRESULT:0x{1:X8}) {0}",
message, SecondLevelHResult ), inner )
{
HResult = SecondLevelHResult;
}
}
class HResultDemo
{
public static void Main()
{
Console.WriteLine(
"This example of Exception.HResult " +
"generates the following output.\n" );
// This function forces a division by 0 and throws
// a second exception.
try
{
try
{
int zero = 0;
int ecks = 1 / zero;
}
catch( Exception ex )
{
throw new SecondLevelException(
"Forced a division by 0 and threw " +
"a second exception.", ex );
}
}
catch( Exception ex )
{
Console.WriteLine( ex.ToString( ) );
}
}
}
}
/*
This example of Exception.HResult generates the following output.
NDP_UE_CS.SecondLevelException: (HRESULT:0x81234567) Forced a division by 0 and
threw a second exception. ---> System.DivideByZeroException: Attempted to divi
de by zero.
at NDP_UE_CS.HResultDemo.Main()
--- End of inner exception stack trace ---
at NDP_UE_CS.HResultDemo.Main()
*/ |
utilisation de "Exception.HResult" code c++/cli :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
|
// Example for the Exception::HResult property.
using namespace System;
namespace NDP_UE_CPP
{
// Create the derived exception class.
ref class SecondLevelException: public Exception
{
private:
static int SecondLevelHResult = (int)0x81234567;
public:
// Set HResult for this exception, and include it in
// the exception message.
SecondLevelException( String^ message, Exception^ inner )
: Exception( String::Format( "(HRESULT:0x{1:X8}) {0}", message, SecondLevelHResult ), inner )
{
HResult = SecondLevelHResult;
}
};
// This function forces a division by 0 and throws
// a second exception.
void DivideBy0()
{
try
{
try
{
int zero = 0;
int ecks = 1 / zero;
}
catch ( Exception^ ex )
{
throw gcnew SecondLevelException( "Forced a division by 0 and threw "
"a second exception.",ex );
}
}
catch ( Exception^ ex )
{
Console::WriteLine( ex->ToString() );
}
}
}
int main()
{
Console::WriteLine( "This example of Exception::HResult "
"generates the following output.\n" );
NDP_UE_CPP::DivideBy0();
}
/*
This example of Exception::HResult generates the following output.
NDP_UE_CPP.SecondLevelException: (HRESULT:0x81234567) Forced a division by 0 an
d threw a second exception. ---> System.DivideByZeroException: Attempted to div
ide by zero.
at NDP_UE_CPP.DivideBy0()
--- End of inner exception stack trace ---
at NDP_UE_CPP.DivideBy0()
*/ |
voici un exemple d'error handling pour un composant "hypothetique ATLCOMERRORSERVERLib" Com en c# que tu peux transposer en c+/cli :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
|
using System;
using ATLCOMERRORSERVERLib;
using System.Runtime.InteropServices;
namespace CSharpComErrorClient
{
class ComErrorClient
{
// Helper function.
static void ReportCOMError(COMException e)
{
Console.WriteLine("*********************");
Console.WriteLine("Raw HRESULT: {0}", e.ErrorCode);
Console.WriteLine("Message: {0}", e.Message);
Console.WriteLine("Source of error: {0}", e.Source);
Console.WriteLine("Method Name: {0}", e.TargetSite);
Console.WriteLine("**********************\n");
}
[STAThread]
static void Main(string[] args)
{
// Create the ATL coclass.
TheBrokenObjectClass b = new TheBrokenObjectClass();
// Trigger the errors.
try
{
b.ReturnFailedHRESULT();
}
catch(COMException comEx)
{
ReportCOMError(comEx);
}
try
{
b.ReturnComErrorObject();
}
catch(COMException comEx)
{
ReportCOMError(comEx);
}
}
}
} |
nb: ennui des mappages des description d'error code n'existe pas en COM.
bon code...