I'm migrating some C# Demo Code from a Command Window Application to an WPF Application. The Demo Code is accessing a wrapped unmanaged C++ Library. The library is provided by a third party, so I don't have access to the code.
While the Demo Code is running fine, the exact same code crashes in my WPF application after a while. The library is accessed, some configuration files are loaded but when I'm calling a certain method my application is throwing an error (I had to enable "Unmanaged Code Debuggin" to see it):
First-chance exception at 0x7726c41f in Application.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x279ce1b4..
SCAPE exception caught: bad allocation
This is the part where the error is thrown:
unsafe
{
fixed (S_DATA* pim = &_im)
{
bool success = false;
try
{
success = RunAnalytics(_im); // <--- returns false, error message in debugger
}
catch (Exception ex)
{
throw new ScrException("ERROR: Unmanaged exception", ex);
}
}
}
Both applications are running on ".NET Framework 4.0 Client Profile".
Any hints how to proceed from here on? I'm out of ideas...
Edit:
I spent the last days setting up different scenarios trying to figure out, what's the source for the issue.
Original WPF in Original Solution > fails
Original WPF in Dummy Solution > works
Dummy CMD in Original Solution > works
Dummy CMD in Dummy Solution > works
Minimal WPF in Dummy Solution > works
Minimal WPF in Original Solution > works
I'm not really any wiser...
Edit 2: After a long, long time I figured it out - a post-build script interfered with some local resources that were copied on top of one another, so I was using an outdated configuration file with some new settings... not a very satisfying solution.
Related
I have a C# .NET app that makes calls into a 3rd party library. The app compiles and runs fine when the library is present, but halts on launch when it isn't.
The user has to install the referenced program separately from my program, so I would like to be able to warn the user that my program won't operate properly if the referenced program hasn't been installed.
I have tried checking the registry for the appropriate entries, and I have tried instantiating the reference object and making a simple method/property call inside a try/catch block, but these never get a chance to work, as Windows pops an exception when it tries to load the referenced library on program startup.
Is there any way I can catch this exception and warn the user nicely that the required program needs to be installed?
TIA,
Frank
So the answer, at least for my issue, was pretty simple once I really understood the problem. My C# .NET app crashed on load when a referenced library was missing. After looking through the above comments and doing some more reading, I discovered that .NET apps by default don't load reference libs until they are needed, so what was happening to me shouldn't be happening. After looking a little more closely at my code, I found this:
//private BCObject bc = null; //11/12/22 assigning bc crashes when BC not installed
private BCObject bc; //11/12/22 this doesn't, so can chk later in frmMain.Shown()
The commented-out line caused .NET to load the referenced dll, and when it failed, I got an unhandled exception. After some trial-and-error, I figured out that I could replace it with the uncommented line, which puts the 'bc' object at frmMain scope, but doesn't trigger a load because it's just a declaration, not a call. This allowed me to write the following in the frmMain.Shown() event:
private void frmMain_Shown(object sender, EventArgs e)
{
//11/12/22 added dummy call to BC object to check for pgm install. Can't use registry to check
bInitialized = true;
UpdateControls();
//string logstr = string.Format("Checking install status of Bridge Composer....", programDisplayName);
//IsProgramInstalled("BridgeComposer");
string logstr = string.Format("Checking Bridge Composer install status ....");
try
{
if (bc == null)
{
bc = new BCObject(); //this will cause an exception if BC not installed
}
bc.Noui = true;
logstr += "INSTALLED";
AppendToLog(logstr, Color.Green);
bBridgeComposerAvail = true;
}
catch (Exception)
{
logstr += "NOT INSTALLED! See https://bridgecomposer.com/Download.htm";
AppendToLog(logstr, Color.Red);
bBridgeComposerAvail = false;
}
if (chkFTP.CheckState == CheckState.Checked)
{
DoFtpUrlCheck();
}
//added 11/11/17
if (chkEmail.CheckState == CheckState.Checked)
{
DoEmailListFileCheck();
}
//moved to bottom 11/11/17
UpdateControls();
}
Here I instantiate the declared 'bc'object using
bc = new BCObject(); //this will cause an exception if BC not installed
And now this is where .NET attempts to load the library. If it exists, great. If it doesn't, then the exception gets handled properly - yay!
This approach also solved another problem, in that previously I had attempted to do this by checking for a registry entry. This works when the 32-bit version of the library is installed, because my app is 32-bit and thus the library registry entries are in the same registry hive that my app accesses by default. However, if the user installs the 64-bit version of the library, then by default my app can't see the registry entries, and thinks the library is missing even when it isn't. Moreover, my previous solution only worked when the registry key search succeeded, which makes it no solution at all.
.NET is happy to load either the 32-bit library or the 64-bit library and the change I made to delay the load operation into frmMain.Shown() works fine for either 'bitness' library.
I am currently working on a simple WPF application for serial data acquisition from an Arduino Mega Board (for testing purposes at this time, to be scaled to other serial devices).
Environment and packages:
Target Framework: .NET Framework 4.8, Visual Studio 2019
SerialPortStream (by Jason Curl - RJCP) version: 2.3.1
Please note that I recently started playing around with C# and I am more familiar with C++ ;)
My app searches and fills the serial ports present in my PC on a ListBox upon loading, then I must select the desired port from the ListBox and open it with a Button. Its callback configures the SerialPortStream object.
After successfully selecting the port, as seen in the console image below, the following exception is thrown to the console and the app just hangs:
Therefore, I decided to insert a breakpoint at the beginning of my code, to inspect my USBPort object, and the object shows errors in the Length, Static Members and Position properties. Inspecting the same object (USBPort) in the method where is configured shows the same errors
A short snippet of my main application code is the following (the lines marked with (*) represent my inserted breakpoints for debugging):
using RJCP.IO.Ports;
using System;
// ... and others
myApp{
public partial class MainWindow: Window {
private string ComPortName;
private int BaudRate;
private SerialPortStream USBPort = new SerialPortStream();
// ... plus other declarations
public MainWindow(){
InitializeComponent();
(*) BaudRate = 115200; // Inserted a breakpoint here to inspect USBPort in the debugger
}
// Start communication Callback/Binding --> Connect button Click binding
private void StartCOM_Click(object sender, RoutedEventArgs e){
try{
(*) USBPort = new SerialPortStream(ComPortName, BaudRate);
USBPort.Open(); // Inserting a breakpoint here shows the same errors in the watch window
// ...subsequent actions
} catch(Exception ex){
if(ex is IOException){
throw new IOException("Unable to create serial port"); // Message does NOT get displayed
}
}
}
Please note that my approach USED to work just fine and I was able to read lines from the serial port. Something broke after I refactored some parts of my code NOT related to the SerialPortStream object. I even tried with an old version of my code and now it keeps throwing the same error every time.
Is my way of pre-declaring my USBPort object using the empty constructor, then configuring it inside the callback correct?
What is the "specified method" that the Length property refers to?
Does the RJCP dll strongly depend on the framework used? According to the GitHub repo, it should work fine in 4.8.
Are different Windows 10 versions related to this issue? My code worked fine yesterday on my laptop at work and it doesn't on my Home's PC. (At the moment I have no access to that laptop).
Should I fall back to previous versions of the RJCP package?
Thank you, guys
Going over your individual questions:
Is my way of pre-declaring my USBPort object using the empty constructor, then configuring it inside the callback correct?
Yes. This is fine. They're just properties until the port is Open()ed.
But your code snippet you provide ignores this, because in StartCOM_Click you instantiate a new instance of SerialPortStream anyway. Check that you haven't opened the same port twice, which may lead to a resource conflict (Windows doesn't allow opening the same serial port from one or more applications more than once).
What is the "specified method" that the Length property refers to?
The Length and Position property are not defined, that the CanSeek property is false in this particular implementation.
Does the RJCP dll strongly depend on the framework used? According to the GitHub repo, it should work fine in 4.8.
Using package 2.3.1 has libraries for .NET 4.0, .NET 4.5 and .NET Standard 1.5. The NuGet package manager should be choosing the .NET 4.5 compiled version when running on top of .NET 4.8 which is described by Supporting Multiple Target Frameworks.
you can confirm this by checking the library RJCP.SerialPortStream.dll that is given next to your compiled program. Just check the sizes. The .NET 4.5 version is 233kB, the .NET Standard version is 246kB.
You probably know that the runtime itself, if you have .NET 4.8 installed, is a high compatibility in place upgrade for all other versions. So software targetting .NET 4.5 or .NET 4.8 runs essentially the same code underneath (I say essentially, because MS does have some compatibility checks, but they aren't relevant here).
Are different Windows 10 versions related to this issue? My code worked fine yesterday on my laptop at work and it doesn't on my Home's PC. (At the moment I have no access to that laptop).
It's more likely that this is related to the driver itself, not liking something in particular. Unfortunately, from the description given, it's difficult to tell what. To debug this, it's best to track in the GitHub issue.
Should I fall back to previous versions of the RJCP package?
There has been a few bugfixes, etc. but nothing described here that suggests this would make a difference.
My winform application incorporates a 3rd-party dll (under the .NET 4.5) made by a device manufacturer in which I can use the exposed functions of its class to communicate with the device. But due to their crappy design once any function might fail no error detail can be retrieved from the class itself, but the class somehow put some information into the console window (appeared in the Output tab under Debug filter) in case of anything wrong.
Now the problem is, the application can only be executed on the computer that is authorized to communicate otherwise the class won't initiate. So when I test my application on the trusted computer, I can only know that some functions return false but no debug info available. I've tried to add TraceListener to Trace.Listeners but nothing shows from this answer, I also tried Debug.Listeners with no result even I manually flushes after each while.
System.Diagnostics.Trace.Listeners.Add(new System.Diagnostics.TextWriterTraceListener("debug.txt"));
System.Diagnostics.Trace.AutoFlush = true;
The DebugView won't generate anything either, I don't know it's because I don't know how to properly use this tool or not. I just opened it, and nothing shows whatever I do to my application.
I'm highly suspicious that this DLL might just use some try...catch snippet to capture its own exceptions and output those info not by using Debug.Write(). What else I can do? I simply can't just install another Visual Studio on that trusted machine and debug my application there.
Try adding a First-Chance Exception Handler:
using System;
using System.Runtime.ExceptionServices;
class Example
{
static void Main()
{
AppDomain.CurrentDomain.FirstChanceException +=
(object source, FirstChanceExceptionEventArgs e) =>
{
Console.WriteLine("FirstChanceException event raised in {0}: {1}",
AppDomain.CurrentDomain.FriendlyName, e.Exception.Message);
};
How to: Receive First-Chance Exception Notifications
I've recently made a release build of a demo game. I've tested it on all my machines at home, a combination of Windows 7 and Windows 8 machines, all 64 bit operating systems.
I passed the demo to a friend who said it is crashing on his machine.
I've built the game as an x86 release so it should work in most Windows environments. As a test I loaded it up here at work and it also fails. I'm combing logs to try and work out why it is failing but don't quite understand the issue if someone could have a look for me.
According to the registry I do have a version of .NET 4.5.1 installed which is good. My .NET crash log provides the following error.
Application: Monochromia.exe Framework Version: v4.0.30319 Description: The process was terminated due to an unhandled exception. Exception Info: System.IO.FileNotFoundException Stack: at Monochromia.Program.Main(System.String[])
I've had a look at my main Method (which again works on other machines) and it looks as follows:
using System;
namespace Monochromia {
#if WINDOWS || XBOX
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(string[] args)
{
using (Game1 game = new Game1())
{
game.Run();
}
}
}
#endif
}
Is there anywhere I can go to find out specifically which file is missing? So I can try and work out why it is breaking. As a I said this is working fine on about 4-5 other machines I have run it on and I imagine there is a common element missing on other machines but I am not sure where to start looking to find out the missing element.
If it helps here is an actual crash log from the game:
Version=1
EventType=APPCRASH
EventTime=130597875140383880
ReportType=2
Consent=1
ReportIdentifier=91cf3b49-6606-11e4-93c4-c8600067af2a
IntegratorReportIdentifier=91cf3b48-6606-11e4-93c4-c8600067af2a
WOW64=1
Response.type=4
Sig[0].Name=Application Name
Sig[0].Value=Monochromia.exe
Sig[1].Name=Application Version
Sig[1].Value=1.0.0.0
Sig[2].Name=Application Timestamp
Sig[2].Value=5459faaf
Sig[3].Name=Fault Module Name
Sig[3].Value=KERNELBASE.dll
Sig[4].Name=Fault Module Version
Sig[4].Value=6.1.7601.18409
Sig[5].Name=Fault Module Timestamp
Sig[5].Value=53159a86
Sig[6].Name=Exception Code
Sig[6].Value=e0434352
Sig[7].Name=Exception Offset
Sig[7].Value=0000c42d
DynamicSig[1].Name=OS Version
DynamicSig[1].Value=6.1.7601.2.1.0.768.3
DynamicSig[2].Name=Locale ID
DynamicSig[2].Value=3081
DynamicSig[22].Name=Additional Information 1
DynamicSig[22].Value=0a9e
DynamicSig[23].Name=Additional Information 2
DynamicSig[23].Value=0a9e372d3b4ad19135b953a78882e789
DynamicSig[24].Name=Additional Information 3
DynamicSig[24].Value=0a9e
DynamicSig[25].Name=Additional Information 4
DynamicSig[25].Value=0a9e372d3b4ad19135b953a78882e789
UI[2]=C:\Users\Admin1\Downloads\Release\Monochromia.exe
UI[3]=Monochromia has stopped working
UI[4]=Windows can check online for a solution to the problem.
UI[5]=Check online for a solution and close the program
UI[6]=Check online for a solution later and close the program
UI[7]=Close the program
LoadedModule[0]=C:\Users\Admin1\Downloads\Release\Monochromia.exe
LoadedModule[1]=C:\Windows\SysWOW64\ntdll.dll
LoadedModule[2]=C:\Windows\SYSTEM32\MSCOREE.DLL
LoadedModule[3]=C:\Windows\syswow64\KERNEL32.dll
LoadedModule[4]=C:\Windows\syswow64\KERNELBASE.dll
LoadedModule[5]=C:\Windows\syswow64\ADVAPI32.dll
LoadedModule[6]=C:\Windows\syswow64\msvcrt.dll
LoadedModule[7]=C:\Windows\SysWOW64\sechost.dll
LoadedModule[8]=C:\Windows\syswow64\RPCRT4.dll
LoadedModule[9]=C:\Windows\syswow64\SspiCli.dll
LoadedModule[10]=C:\Windows\syswow64\CRYPTBASE.dll
LoadedModule[11]=C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscoreei.dll
LoadedModule[12]=C:\Windows\syswow64\SHLWAPI.dll
LoadedModule[13]=C:\Windows\syswow64\GDI32.dll
LoadedModule[14]=C:\Windows\syswow64\USER32.dll
LoadedModule[15]=C:\Windows\syswow64\LPK.dll
LoadedModule[16]=C:\Windows\syswow64\USP10.dll
LoadedModule[17]=C:\Windows\system32\IMM32.DLL
LoadedModule[18]=C:\Windows\syswow64\MSCTF.dll
LoadedModule[19]=C:\PROGRA~2\KASPER~1\KASPER~1\mzvkbd3.dll
LoadedModule[20]=C:\PROGRA~2\KASPER~1\KASPER~1\sbhook.dll
LoadedModule[21]=C:\Windows\syswow64\ole32.dll
LoadedModule[22]=C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
LoadedModule[23]=C:\Windows\system32\MSVCR110_CLR0400.dll
LoadedModule[24]=C:\Windows\assembly\NativeImages_v4.0.30319_32\mscorlib\ce5f61c5754789df97be8dc991c47d07\mscorlib.ni.dll
LoadedModule[25]=C:\Windows\Microsoft.NET\Framework\v4.0.30319\clrjit.dll
LoadedModule[26]=C:\Windows\syswow64\OLEAUT32.dll
LoadedModule[27]=C:\Windows\Microsoft.NET\Framework\v4.0.30319\diasymreader.dll
FriendlyEventName=Stopped working
ConsentKey=APPCRASH
AppName=Monochromia
AppPath=C:\Users\Admin1\Downloads\Release\Monochromia.exe
It seems my issue was that the target system although having the .NET Framework did not contain the XNA Framework from http://www.microsoft.com/en-us/download/confirmation.aspx?id=27598. The reason that I picked this up was that I was looking at other bug reports from other games and noticed people having issues with Terraria which was made with XNA. It made me realise the other target machines I had tested earlier had played Terraria at some point and thus would have had the XNA Framework installed when the game was first run.
I may have to look at bundling this in an installer or doing a check for the Framework first. Problem solved!
The code causing this exception is most likely linked to the disposal of the game object. Note that using an object calls IDispose.Dispose() after the using block, which would explain why this happens during shutdown. This should go away if you wrap the using statement in a try-catch block, but it may not help diagnose the problem.
For diagnosis, I would recommend debugging on the target machine so you can get the full stack trace of the exception, and barring that, make a release Console build, and wrap the using in a try-catch as above, but slam the Exception.StackTrace into the console window for viewing.
try
{
using (Game1 game = new Game1())
{
game.Run();
}
}
catch(Exception E)
{
Console.WriteLine(e.StackTrace);
}
Note that it might also be helpful to give your tester a debug build so that the stack trace or other exception data isn't optimized away.
I have to call a sample MFC view in C# application, using Visual Studio 2012. I use C++/CLI project and call C++ class from C#. To do this I have to use this line of code
AFX_MANAGE_STATE(AfxGetStaticModuleState());
This will call the resource handle of MFC DLL resource instead of default resource (exe file on C#). The MFC view runs OK, but it appears an exception (as C message box):
Debug Assertion Failed on \$InstallDir\VC\atlmfc\src\mfc\olelock.cpp line 62
Here is the source code I checked on install Dir:
void AFXAPI AfxOleUnlockApp()
{
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
ASSERT(pModuleState->m_nObjectCount != 0);
if (InterlockedDecrement(&pModuleState->m_nObjectCount) == 0)
{
// allow application to shut down when all the objects have
// been released
::AfxOleOnReleaseAllObjects();
}
}
How can I avoid this assertion? Thank you for your support.
This Assertion simply says that you called AfxOleUnlockApp more often than AfxOleLockApp as called.
Set breakpoints to the specific functions. Check who calls lock/unlock. Probably there are objects freed more than once...