What kind of exception should you use for DX11 runtime exceptions - c++

I'm creating a 3D renderer in DirectX 11 and I'm trying to build an error handler for exceptions.
I'm using the built in HRESULTS now that DX is integrated into the main OS in combination with the D3D debug layer. My problem is the following line of code:
m_contextPtr->Draw(3u,0u);
Figuring out what the exceptions themselves are isn't the issue here but getting a try catch block to throw so I can display them on screen is proving to be an issue.
The full code:
try
{
m_contextPtr->Draw(3u,0u);
}
catch(std::runtime_error &e)
{
MessageBox(nullptr, e.what(), "Runtime Exception", MB_OK|MB_ICONERROR);
}
catch(GPUErrorHandler& e)
{
MessageBox(nullptr, e.what(), "DX Exception", MB_OK|MB_ICONERROR);
}
catch(ErrorHandler& e)
{
MessageBox(nullptr, e.what(), "Win32 Exception", MB_OK|MB_ICONERROR);
}
catch(std::exception& e)
{
MessageBox(nullptr, e.what(), "Standard Exception", MB_OK|MB_ICONERROR);
}
catch(...)
{
MessageBox(nullptr, "No details available", "Unknown Exception", MB_OK|MB_ICONQUESTION);
}
The custom error classes are derived from std::exception appropriate to the type of exception that is thrown.
Any help is appreciated, thanks.

Related

Failing to create Striped Backup with SQL VDI (Virtual Device Interface)

This is an incredible long shot, but here goes. We are making a utility for database backup, using SQLVDI API (Virtual Device Interface). The single backup was implemented without problems. But when we started to implement the striped backup (using virtual_device), we got an issue with IClientVirtualDeviceSet2::OpenDevice method.
Our virtual device set is failing to open all devices. Only the first device is returned and on the second one we are getting VD_E_PROTOCOL error. Any suggestions would be greatly appreciated.
Our C++ code.
public: Void ExecuteCommandEx(System::String^ command, array<Stream^>^ commandStreamListIn)
{
try
{
//Initialize COM
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr))
{
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "CoInitializeEx Failed HRESULT: {0}", hr));
}
//Get an interface to the virtual device set
IClientVirtualDeviceSet2* vds = NULL;
hr = CoCreateInstance(CLSID_MSSQL_ClientVirtualDeviceSet, NULL, CLSCTX_INPROC_SERVER, IID_IClientVirtualDeviceSet2, (void**)&vds);
if (FAILED(hr))
{
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "Unable to get an interface to the virtual device set. Please check to make sure sqlvdi.dll is registered. HRESULT: {0}", hr));
}
//Configure the device configuration
VDConfig config = { 0 };
config.deviceCount = commandStreamListIn->Length; //The number of virtual devices to create
//Create a name for the device using a GUID
String^ DeviceName = Guid::NewGuid().ToString()->ToUpper(gcnew CultureInfo("en-US"));
WCHAR wVdsName[37] = { 0 };
Marshal::Copy(DeviceName->ToCharArray(), 0, (IntPtr)wVdsName, DeviceName->Length);
//Create the virtual device set
hr = vds->CreateEx(NULL, wVdsName, &config);
if (FAILED(hr))
{
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "Unable to create and configure the virtual device set. HRESULT: {0}", hr));
}
//Format the command
List<String^>^ vdNames = gcnew List<String^>();
vdNames->Add(DeviceName);
for (int i = 0; i < commandStreamListIn->Length-1; i++)
{
String^ streamName = Guid::NewGuid().ToString()->ToUpper(gcnew CultureInfo("en-US"));
vdNames->Add(streamName);
}
command = String::Format(gcnew CultureInfo("en-US"), command, vdNames->ToArray());
//Create and execute a new thread to execute the command
Thread^ OdbcThread = gcnew Thread(gcnew ParameterizedThreadStart(this, &VdiDotNetEx::VdiEngineEx::ThreadFunc));
OdbcThread->Start(command);
//Configure the virtual device set
hr = vds->GetConfiguration(INFINITE, &config);
if (hr != NOERROR)
{
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "GetConfiguration Failed. HRESULT: {0}", hr));
}
if (FAILED(hr))
{
switch (hr)
{
case VD_E_ABORT:
throw gcnew ApplicationException("GetConfiguration was aborted.");
break;
case VD_E_TIMEOUT:
throw gcnew ApplicationException("GetConfiguration timed out.");
break;
default:
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "Un unknown exception was thrown during GetConfiguration. HRESULT: {0}", hr));
break;
};
}
int count = 0;
array<IClientVirtualDevice*>^ vDevices= gcnew array<IClientVirtualDevice*>(commandStreamListIn->Length);
//Open all devices on the device set
//VD_E_OPEN may be returned without problem. The client may call OpenDevice by means of a loop until this code is returned.
//If more than one device is configured(for example, n devices),
//the virtual device set will return n unique device interfaces.
//The first device has the same name as the virtual device set.
//Other devices are named as specified with the VIRTUAL_DEVICE clauses of the BACKUP / RESTORE statement.
while (hr!= VD_E_OPEN)
{
IClientVirtualDevice* vd = NULL;
hr = vds->OpenDevice(wVdsName, &vd);
switch(hr)
{
case VD_E_OPEN:
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_OPEN. HRESULT: {0}", hr));
break;
case VD_E_BUSY:
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_BUSY. HRESULT: {0}", hr));
break;
case VD_E_CLOSE:
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_CLOSE. HRESULT: {0}", hr));
break;
case VD_E_UNEXPECTED:
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_UNEXPECTED. HRESULT: {0}", hr));
break;
case VD_E_INVALID:
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_INVALID. HRESULT: {0}", hr));
break;
case VD_E_NOTOPEN:
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_NOTOPEN. HRESULT: {0}", hr));
break;
case VD_E_PROTOCOL:
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_PROTOCOL. HRESULT: {0}", hr));
break;
}
if (FAILED(hr))
{
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. HRESULT: {0}", hr));
}
vDevices[count] = vd;
count++;
}
for (int i = 0; i < count; i++)
{
ExecuteDataTransfer(vDevices[i], commandStreamListIn[i]);
}
//Wait for the thread that issued the backup / restore command to SQL Server to complete.
OdbcThread->Join();
}
catch (Exception ^ex)
{
Debug::WriteLine("VDI: Exception=" + ex->Message->ToString());
Debug::WriteLine("VDI: Trace=" + ex->StackTrace);
Console::WriteLine(ex->Message);
LogException(ex);
throw gcnew ApplicationException(ex->Message);
}
}
The COM related code: (combaseapi.h)
#pragma region Application or OneCore Family
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
_Check_return_ WINOLEAPI
CoInitializeEx(
_In_opt_ LPVOID pvReserved,
_In_ DWORD dwCoInit
);
#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
#pragma endregion
_Check_return_ WINOLEAPI
CoCreateInstance(
_In_ REFCLSID rclsid,
_In_opt_ LPUNKNOWN pUnkOuter,
_In_ DWORD dwClsContext,
_In_ REFIID riid,
_COM_Outptr_ _At_(*ppv, _Post_readable_size_(_Inexpressible_(varies))) LPVOID FAR * ppv
);
OpenDevice is not working according to the SQLVDI documentation. For example don't expect VD_E_OPEN as a result, just 0 is OK. Also pass not only the virtual device set name to this method, but GUID of every virtual_device from your command. Look at this adjusted code.
for(int i = 0; i < vdNames->Count; i++)
{
IClientVirtualDevice* vd = NULL;
WCHAR wDevName[37] = { 0 };
String^ vdName = vdNames[i];
Marshal::Copy(vdName->ToCharArray(), 0, (IntPtr)wDevName, vdName->Length);
hr = vds->OpenDevice(wDevName, &vd);
switch(hr)
{
case VD_E_BUSY:
DBGPRINTW(L"VDI: Exception 15\n");
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_BUSY. HRESULT: {0}", hr));
break;
case VD_E_CLOSE:
DBGPRINTW(L"VDI: Exception 14\n");
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_CLOSE. HRESULT: {0}", hr));
break;
case VD_E_UNEXPECTED:
DBGPRINTW(L"VDI: Exception 11\n");
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_UNEXPECTED. HRESULT: {0}", hr));
break;
case VD_E_INVALID:
DBGPRINTW(L"VDI: Exception 06\n");
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_INVALID. HRESULT: {0}", hr));
break;
case VD_E_NOTOPEN:
DBGPRINTW(L"VDI: Exception 02\n");
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_NOTOPEN. HRESULT: {0}", hr));
break;
case VD_E_PROTOCOL:
DBGPRINTW(L"VDI: Exception 12\n");
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. VD_E_PROTOCOL. HRESULT: {0}", hr));
break;
}
if (FAILED(hr))
{
DBGPRINTW(L"VDI: Exception 08\n");
throw gcnew ApplicationException(String::Format(gcnew CultureInfo("en-US"), "OpenDevice Failed. HRESULT: {0}", hr));
}
vDevices[i] = vd;
count++;
}

try catch on reflective loaded dll

I was testing this injection technique (Reflective dll injection) and found that any try/catch on the code rise an unhandle windows error (KERNELBASE.dll, code error e06d7363) and the host process dies.
I was injecting a test dll with a basic function.
the work flow is:
print "starting..." and then dies.
My dll.
bool WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
{
bool bReturnValue = TRUE;
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
function();
break;
}
return bReturnValue;
}
void function()
{
cout << "starting..." << std::endl;
try
{
throw std::exception();
}
catch (...)
{
cout << " exception... " << std::endl;
}
}
any technical explanation?
This is likely because the exception handling is not properly set up when you do the injection. See https://hackmag.com/uncategorized/exceptions-for-hardcore-users/.
What library are you using for injection? Does it support SEH? Or are you registering the handlers properly if you are doing it yourself?
I suspect however the issue is more complexe as I am having a similar issue with standard in-memory DLL loading with a lib (SimplePELoader) that supports SEH in my standard test case.

MSXML2::IXMLDOMNodePtr C++ exceptions

I noticed on the MSDN website that it used a catch all exception handler. I.e.:
try {
MSXML2::IXMLDOMDocumentPtr docPtr;
MSXML2::IXMLDOMNodePtr DOMNodePtr;
// init
TESTHR(CoInitialize(NULL));
TESTHR(docPtr.CreateInstance("Msxml2.DOMDocument.6.0"));
VARIANT vtTemp;
vtTemp.vt=VT_I2;
vtTemp.iVal = 1; //NODE_ELEMENT
// load a document
_variant_t varXml("c:\\Temp\\books.xml");
_variant_t varOut((bool)TRUE);
varOut = docPtr->load(varXml);
if ((bool)varOut == FALSE)
throw(0);
MessageBox(NULL, _bstr_t(docPtr->xml), _T("Original Document"), MB_OK);
DOMNodePtr = docPtr->createNode(vtTemp, "VIDEOS", "");
docPtr->documentElement->appendChild(DOMNodePtr);
MessageBox(NULL, _bstr_t(docPtr->xml), _T("New Document"), MB_OK);
} catch(...)
{
MessageBox(NULL, _T("Exception occurred"), _T("Error"), MB_OK);
}
Now my question is, does the function calls to the MSXML2::IXMLDOMDocumentPtr object throw any exceptions? I wasn't aware that a COM object could throw a C++ exception due to the COM boundary can interface with any language.
If it is just to catch the throw(0), then why not catch on an int? I know a little theory on COM but my knowledge is a little limited.

IDirect3DDevice9::GetFrontBufferData fails with segmentation fault

I created a really simple DirectX program to capture the screen. It works well on my machine, but fails on another machine in the following line with a segmentation fault (SIGSEV):
g_pd3dDevice->GetFrontBufferData(0, g_pSurface);
The following function is used to initialize DirectX:
HRESULT InitD3D(HWND hWnd)
{
D3DDISPLAYMODE ddm;
D3DPRESENT_PARAMETERS d3dpp;
if((g_pD3D=Direct3DCreate9(D3D_SDK_VERSION))==NULL)
{
ErrorMessage("Unable to Create Direct3D ");
return E_FAIL;
}
if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&ddm)))
{
ErrorMessage("Unable to Get Adapter Display Mode");
return E_FAIL;
}
ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
d3dpp.Windowed=WINDOW_MODE;
d3dpp.Flags=D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
d3dpp.BackBufferFormat=ddm.Format;
d3dpp.BackBufferHeight=nDisplayHeight=gScreenRect.bottom =ddm.Height;
d3dpp.BackBufferWidth=nDisplayWidth=gScreenRect.right =ddm.Width;
d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;
d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow=hWnd;
d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_DEFAULT;
d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;
if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_REF,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING ,&d3dpp,&g_pd3dDevice)))
{
ErrorMessage("Unable to Create Device");
return E_FAIL;
}
if(FAILED(g_pd3dDevice->CreateOffscreenPlainSurface(ddm.Width, ddm.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &g_pSurface, NULL)))
{
ErrorMessage("Unable to Create Surface");
return E_FAIL;
}
return S_OK;
}
Any ideas why this would throw a segmentation fault?
Solution: The DirectX driver was not correctly installed.

Handling Exception in MFC

I got this exception in my program:
Unhandled exception at 0x0051cce0 in
JSONDataParsing.exe: 0xC0000005:
Access violation reading location
0x00000004
.
I tried catching the Exception, but of no use. I know where the problem occurs. But wanted to know how I can trap the exception. I used try, catch block around the code where exception occurs.
Is this an exception which can not be caught?
The catch statements are:
catch (bad_alloc&)
{
TCHAR msgbuf[MAX_PATH];
swprintf(msgbuf, L"bad_alloc \n");
OutputDebugString(msgbuf);
}
catch (bad_cast&)
{
TCHAR msgbuf[MAX_PATH];
swprintf(msgbuf, L"bad_cast \n");
OutputDebugString(msgbuf);
}
catch (bad_exception&)
{
TCHAR msgbuf[MAX_PATH];
swprintf(msgbuf, L"babad_exceptiond_alloc \n");
OutputDebugString(msgbuf);
}
catch (bad_typeid&)
{
TCHAR msgbuf[MAX_PATH];
swprintf(msgbuf, L"bad_alloc \n");
OutputDebugString(msgbuf);
}
catch( CMemoryException* e )
{
TCHAR msgbuf[MAX_PATH];
swprintf(msgbuf, L"CMemoryException \n");
OutputDebugString(msgbuf);
// Handle the out-of-memory exception here.
}
catch( CFileException* e )
{
TCHAR msgbuf[MAX_PATH];
swprintf(msgbuf, L"CFileException \n");
OutputDebugString(msgbuf);
// Handle the file exceptions here.
}
catch( CException* e )
{
TCHAR msgbuf[MAX_PATH];
swprintf(msgbuf, L"CException \n");
OutputDebugString(msgbuf);
// Handle the exception here.
// "e" contains information about the exception.
e->Delete();
}
You can only catch such exception with a special try-catch handler:
try
{
// code that triggers such an exception. for example:
int * a = NULL;
*a = 0;
}
catch (...)
{
// now that exception is handled here
}
But generally, it is bad practice to do this. Instead you should not get such an exception but check your parameters and variables.
See here for more details:
http://members.cox.net/doug_web/eh.htm
This type of low level exception can be caught using __try -except statement, but you should fix the cause of it rather than reporting it. In VS, while debugging hit CTRL+ALT+E and check all exceptions there, then continue to run your app until the exception occurs. The prompt will stop on the offending line.
See
http://msdn.microsoft.com/en-us/library/s58ftw19.aspx
for details.