LibTiff.NET ReadDirectory is giving System.ObjectDisposedException Only During Unit Tests - c#

Edit: FYI for future readers, this issue has been fixed as of version 2.3.606.0 of BitMiracle's LibTiff.NET.
I'm using BitMiracle's LibTiff.NET (version 2.3.605.0 and below) in my C# library (compiled at .NET 3.5 | x86) and keep getting this exception when I call ReadDirectory: System.ObjectDisposedException: Cannot write to a closed TextWriter
I realize that this seems to indicate that I have already disposed of my image before making the call...but I have not specifically done so. Is this a bug in the library or am I really missing something here?
Here is my code:
public static bool IsTiffBiTonal(String tiffFilePath)
{
VerifyFileExistence(tiffFilePath);
using (Tiff tiff = Tiff.Open(tiffFilePath, "r"))
{
do
{
if (tiff.GetField(TiffTag.BITSPERSAMPLE)[0].ToInt() == 1)
{
continue;
}
return false;
}
while (tiff.ReadDirectory()); //Error occurs here
}
return true;
}
EDIT: Ok, I have more information after some further testing, this is only happening when I'm running my unit tests! Don't know why that would change anything though.

Because of other threads talking about unit testing and getting this same error when trying to write to the console (ObjectDisposedException when outputting to console) I realized that the LibTiff.NET library was trying to write to the error console. After looking through the source code, I found that this code:
using (TextWriter stderr = Console.Error)
{
...
}
Because they were wrapping all of the writes to the error out in a using, it was disposing of the Console.Error object after the first write to the error out. This caused my error on the second time around (ReadDirectory does what calling Next on a linked list does). So I removed the using and the problem was fixed!
TextWriter stderr = Console.Error;
...
So, the lesson here: don't dispose of your standard outputs :)
I've asked another question regarding why they were ever allowed to dispose of the standard output in unit tests but not in other situations here: .NET - Why is disposing of standard output only allowed during unit tests?. If you have any answers to the question...please post it there.

Related

Runtime casting of COM objects in C#

I am working on a application which needs to communicate via COM interface with multiple CAD applications (not in the same time). I want to have nice and reusable code, but I came across problems with type casting of COM objects when I made generic application handle getter method.
What I tried so far:
This is the attempt I would like the most if it worked.
public static TCadAppType CadApp<TCadAppType>()
{
dynamic cadApp = default(TCadAppType);
//Here under Dynamic View/Message there is already an error
// Message = "Element not found. (Exception from HRESULT: 0x8002802B (TYPE_E_ELEMENTNOTFOUND))"
// cadVersion.Value evaluates to "SldWorks.Application"
cadApp = (TCadAppType)Marshal.GetActiveObject(cadVersion.Value);
//Following 2 lines of code are for testing purposes only, i am testing with Solidworks API
AssemblyDoc Assembly;
//The exception is thrown when I try to access some method from the Solidworks API
Assembly = (AssemblyDoc)cadApp.OpenDoc6("some parametras...");
}
Attempt using Convert class
// Another attempt using Convert class
public static TCadAppType CadApp<TCadAppType>()
{
dynamic cadApp = default(TCadAppType);
// cadVersion.Value evaluates to "SldWorks.Application"
cadApp = Marshal.GetActiveObject(cadVersion.Value);
cadApp = Convert.ChangeType(cadApp, typeof(SldWorks.SldWorks));
// Exception is thrown with the following message:
// Message = "Object must implement IConvertible."
}
I really thought that I am on the right track, since there is an article on Microsoft Docs website explaining how dynamic can help you with com interopt: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic#com-interop
Any ideas how I can do this runtime casting a keep my code as reusable as possible?
My software setup:
Win 10
Project is targeted for .NET 4.7.2
First Tests are with Solidworks 2019
Turns out that the my coding attempt 1 was valid c# code indeed.
I tried it using with Autodesk Inventor, and it works.
So the only thing left for me is to conclude that this is some bug from Solidworks and their COM interfacing.
Thank you Optional Option for your interest in the topic.

how to solve RDotNet REngine nullreference exception

I am trying to use the REngine.GetInstance() function but I keep getting a null reference exception.
I have tried using another function in REngine just in case the getInstance method was at fault, like REngine.SetEnvironmentVariables(), yet they all return the null reference exception.
I have tried reinstalling the package. I have tried checking the installation path but I couldn't find how the rdotnetlibrary accesses it. I am not even sure the path is related to the problem.
Please help.
Make sure your startupparameters are set up correctly. Since you do not provide us enough information; this is a correct way to get r.net's REngine running:
//...
StartupParameter rinit = new StartupParameter();
rinit.Quiet = true;
rinit.RHome = "C:/Program Files/R/R-3.4.3";
rinit.Interactive = true;
REngine.SetEnvironmentVariables();
rMain = REngine.GetInstance(null, true, rinit);
//...
Make sure you setup RHome to the correct installed R path.
EDIT (thanks to #David M.): In usual cases you only need to pass StartupParameter to GetInstance() if you don't want to have default initialization settings. However, according to the source code comments for the first parameter:
The file name of the library to load, e.g. "R.dll" for Windows. You usually do not need need to provide this optional parameter
In rare cases you need to provide the path of R.dll:
//...
rMain = REngine.GetInstance("C:/Program Files/R/R-3.4.3/bin/x64/R.dll", true, rinit);
//...
I've had the same issue using version 3.5.0
a call to "REngine.GetInstance" would result in 'Object reference not set to an instance of an object'
I downgraded to 3.4.0 and I'm not getting that error anymore.
When we upgraded R from 3.4 to 3.5, we got that exact error. We downgraded back to 3.4 and moved on.
As other answers have pointed out, this appears to be an issue relating to R 3.5 and above. I also managed to work around this by downloading R 3.4.4 and having both versions run concurrently, using Shique's solution.
For those unable to downgrade their R, it looks like jmp75 has been working on a fix, and there is a WIP branch available at https://github.com/StatTag/rdotnet/tree/r_3_5_0

Error: 0x80004005 in HookManager. Why? [duplicate]

This question already has answers here:
SetWindowsHookEx failing in .NET 4.0 on 32-bit machine with "module not found"?
(3 answers)
Closed 5 years ago.
This question is a follow on from: How do you disable system hotkeys in user32.dll? . I have not added it to chat because after googling, this appears to be an issue and I haven't found a solution which works. The error code seems to have multiple causes, one of which being a possibly corrupt dll. The fact that I can't figure out whether or not this is the case is a problem.
The code from this question comes from:
https://www.codeproject.com/articles/7294/processing-global-mouse-and-keyboard-hooks-in-c Look for the file "HookManager.Callbacks.cs"
Useful: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
I keep getting the following error:
Error: System.ComponentModel.Win32Exception (0x80004005): The
specified module could not be found at
Gma.UserActivityMonitor.HookManager.EnsureSubscribedToGlobalKeyboardEvents()
in [REDACTED DIRECTORY]HookManager.Callbacks.cs:line 401
The code causing this:
private static void EnsureSubscribedToGlobalKeyboardEvents()
{
// install Keyboard hook only if it is not installed and must be installed
if (s_KeyboardHookHandle == 0)
{
//See comment of this field. To avoid GC to clean it up.
s_KeyboardDelegate = KeyboardHookProc;
//install hook
s_KeyboardHookHandle = SetWindowsHookEx(
WH_KEYBOARD_LL,
s_KeyboardDelegate,
Marshal.GetHINSTANCE(
Assembly.GetExecutingAssembly().GetModules()[0]),
0);
//If SetWindowsHookEx fails.
if (s_KeyboardHookHandle == 0)
{
//Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set.
int errorCode = Marshal.GetLastWin32Error();
//do cleanup
//Initializes and throws a new instance of the Win32Exception class with the specified error.
throw new Win32Exception(errorCode); // this line is causing this
}
}
}
Unless I am mistaken, the culprit from the above code is:
s_KeyboardHookHandle = SetWindowsHookEx(
WH_KEYBOARD_LL,
s_KeyboardDelegate,
Marshal.GetHINSTANCE(
Assembly.GetExecutingAssembly().GetModules()[0]),
0);
So does anyone understand what the problem here is?
What have I tried?
I have tried previously re-creating the entire project and copy+pasting code in case any of the program's other files were corrupted (from copying to/from USB). I had believed the problem was fixed (though I might be mistaken). The problem is now back and what I previously thought would work is not working (re-creating the project).
I will try other solutions I find online, which relate to problems with Windows. If anyone can see anything wrong with the code, please let me know. Though the code came from a very reliable source and loads of people have used it so this seems unlikely.
https://social.msdn.microsoft.com/Forums/en-US/b7d1a35f-3759-4217-91ba-e4416ac19d78/how-do-you-fix-error-code-0x80004005?forum=jscript
I tried the solution which involved "regsvr32 jscript.dll" and "regsvr32 vbscript.dll". It didn't work.
You exchange last two parameters of SetWindowsHookEx(): third parameter should be set to IntPtr.Zero for same process and last one is thread.
You can as well pinvoke the thread id:
[DllImport("kernel32.dll")]
public static extern int GetCurrentThreadId();
SetWindowsHookEx(WH_KEYBOARD_LL, s_KeyboardDelegate, IntPtr.Zero, GetCurrentThreadId());

Does VBA support Task.Wait() from a C# class import?

I wrote a C# class which connects to Dropbox and lets you upload, download, delete and generate link files.
It's working with a Windows Forms but I have to access it from VBA (Microsoft Access). The problem comes when it goes to task.Wait(). I've ""debugged" this throwing Exceptions and after that, doesn't go through.
public DropBox()
{
//Empty constructor because VBA doesn't support constructors with args
}
public void Connect(string tokenUser)
{
try
{
dropbox = new DropboxClient(tokenUser);
var taskInicio = Task.Run(async () => await dropbox.Users.GetCurrentAccountAsync());
//throw new Exception("Arriving?"); //ARRIVES
taskInicio.Wait();
throw new Exception("Arriving?"); //Throws "one or more errors"
}
catch (AggregateException ex)
when (ex.InnerException is BadInputException
|| ex.InnerException is AuthException)
{
throw new Exception("Incorrect Token or without access", ex.InnerException);
}
}
On VBA
Option Compare Database
Private Sub btActivar_Click()
Call test
End Sub
Public Function test()
Dim objDrop As CloudFiles.DropBox
Set objDrop = New CloudFiles.DropBox
MsgBox (objDrop.HolaMundo)
objDrop.Connect("TokenLongChicken")
'objDrop.DeleteFile("https://www.dropbox.com/s...?dl=0")
End Function
The "One or more errors produced" sounds like it comes from the "mscorlib" or so...
Any ideas? This is getting quite messy :/
Thanks.
VBA does have Application.Wait, I think you can give it a try. I have a code to wait for an IE connection which you can use as example:
Do While IE.Busy ' Need to wait until the page has loaded
Application.Wait (Now + TimeValue("00:00:01")) ' Wait one second
Loop
Tell me if it helps you.
I was having headaches thinking that it could be something related with the Tasks, asyncs, awaits... and it was something related with the Newtonsoft json library.
I updated the library through the NuGet to the 9.0 version and everything worked fine on Windows Forms, but looks like something is wrong when I use it through the .TLB because when I escaped the exception I got at some point in my deletion method, it said the Newtonsoft Json 7.0.0.0 library was missing (it was at the same directory anyway).
I finally removed that Newtonsoft Json version I was using and the Dropbox API, downloaded box again but I declined applying any updates. I couldn't even try to apply a downgrade or so.
Good ending, but I don't really get why did it search for the 7.0.0.0 when I was using the 9.x on my Windows Form project, which works and exported the .DLL and the .TLB.
Thanks to everybody.
EDIT: And yes, I guess this answers the question: VBA supports Task.Wait (at least coming from a C# .dll import)

How do I use the Mono.CSharp interpreter in Microsoft.NET

I was under the impression Mono's compiler was usable in Microsoft.NET
edit: updated blog posting here that I originally missed that explains some of it (is consistent with Justin's answers)
I created a simple class to try to use it
[TestFixture]
class Class1
{
[Test]
public void EXPR()
{
Evaluator.Run("using System;");
int sum = (int)Evaluator.Evaluate("1+2");
}
}
And a project in Visual Studio 2010 that references C:\Program Files (x86)\Mono-2.10.1\lib\mono\4.0\Mono.CSharp.dll.
However when I try to run this task I get the following exception, thrown at the Evaluator.Run call:
System.TypeInitializationException was unhandled by user code
Message=The type initializer for 'Mono.CSharp.Evaluator' threw an exception.
Source=Mono.CSharp
TypeName=Mono.CSharp.Evaluator
StackTrace:
at Mono.CSharp.Evaluator.Run(String statement)
at Experiments.Class1.EXPR() in W:\Experiments\Class1.cs:line 16
InnerException: System.TypeLoadException
Message=Method 'Mono.CSharp.Location.ToString()' is security transparent, but is a member of a security critical type.
Source=Mono.CSharp
TypeName=Mono.CSharp.Location.ToString()
StackTrace:
at Mono.CSharp.Evaluator..cctor()
InnerException:
A google confirms one other person asking this question but no answer. I tried to start reading the microsoft article on security transparent code but got confused quite quickly. Would someone be able to suggest a quick workaround to allow me to use this? And possibly summarise the security implications, if any, to me (in the context of my situation - in the future I hope to package it with a thick client application, to be used both internally and by end-users)
It has worked under .NET since April of last year.
Small point but I notice you are missing a semi-colon in your expression for sum.
int sum = (int)Evaluator.Evaluate("1+2;");
I only have Mono 2.11 (from git) at the moment and they have changed to using a multi-instance version of the compiler instead of the static version. So, my code looks a little different:
using System;
using Mono.CSharp;
namespace REPLtest
{
class MainClass
{
public static void Main (string[] args)
{
var r = new Report (new ConsoleReportPrinter ());
var cmd = new CommandLineParser (r);
var settings = cmd.ParseArguments (args);
if (settings == null || r.Errors > 0)
Environment.Exit (1);
var evaluator = new Evaluator (settings, r);
evaluator.Run("using System;");
int sum = (int) evaluator.Evaluate("1+2;");
Console.WriteLine ("The sum of 1 + 2 is {0}", sum);
}
}
}
EDIT: I guess I should confirm that I did in fact successfully execute this on .NET 4 (using Visual C# Express 2010 on Windows XP)
EDIT AGAIN: If you have Visual Studio, you can download the latest version of Mono.CSharp and compile it yourself. There is a .sln (solution file) included with the source so you can build it on Windows without Mono. The resulting assembly would run the code above. Miguel has a post explaining the new Mono.CSharp here.
FINAL EDIT: I uploaded the compiled Mono.CSharp.dll assembly that I actually used here. Include it as a reference to compile the code above.
It looks like this is a bug in Mono.
.NET 4 abandoned Code Access Security but kept the concept of Security Transparent Code. In a nutshell, low-level code that does stuff, like call unmanaged code, must be "security critical". Application level code is marked "transparent". "Transparent" code cannot call into "security critical" code.
It sounds like Mono.CSharp.Location.ToString() needs to be marked with the [SecuritySafeCritical] attribute if you want the Mono 2.10 code to work with .NET 4. Maybe even better would be marking all of Mono.CSharp as SecuritySafeCritical.
http://msdn.microsoft.com/en-us/library/system.security.securitycriticalattribute.aspx
PS. Sorry to have multiple answers for one question. After I realized that 2.11 would work, I became more curious about what the error with 2.10 meant. I cannot really combine this answer with the others.
I decided I should have kept the code more like the question but I did not want to overwrite my previous answer:
The code below works with version 2.11 of Mono.CSharp (available here including a solution file for building with Visual Studio/.NET). It was tested with .NET 4 on Windows XP. I do not have access to Mono 2.10 at the moment.
[TestFixture]
class Class1
{
private Evaluator evaluator;
public Class1()
{
var report = new Report(new ConsoleReportPrinter());
evaluator = new Evaluator(new CompilerSettings(), report);
}
[Test]
public void EXPR()
{
evaluator.Run("using System;");
int sum = (int)evaluator.Evaluate("1+2;");
}
}
EDIT: I uploaded the Mono.CSharp.dll assembly that I actually used here. Include it as a reference to compile the code above.

Categories