Suppress Console prints from imported DLL - c#

Inside a C# Console application, I'm importing a native C++ DLL methods. for example:
[DllImport("MyDll.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern int MyMethod(IntPtr somePointer);
When executed, MyMethod() is printing output to the Console, which I would like to be hidden.
Assuming I can't change the DLL, how can I still suppress it's output?

Modified from http://social.msdn.microsoft.com/Forums/vstudio/en-US/31a93b8b-3289-4a7e-9acc-71554ab8fca4/net-gui-application-native-library-console-stdout-redirection-via-anonymous-pipes
I removed the part where they try to redirect it because if you read further, it says they were having issues when it was called more than once.
public static class ConsoleOutRedirector
{
#region Constants
private const Int32 STD_OUTPUT_HANDLE = -11;
#endregion
#region Externals
[DllImport("Kernel32.dll")]
extern static Boolean SetStdHandle(Int32 nStdHandle, SafeHandleZeroOrMinusOneIsInvalid handle);
[DllImport("Kernel32.dll")]
extern static SafeFileHandle GetStdHandle(Int32 nStdHandle);
#endregion
#region Methods
public static void GetOutput(Action action)
{
Debug.Assert(action != null);
using (var server = new AnonymousPipeServerStream(PipeDirection.Out))
{
var defaultHandle = GetStdHandle(STD_OUTPUT_HANDLE);
Debug.Assert(!defaultHandle.IsInvalid);
Debug.Assert(SetStdHandle(STD_OUTPUT_HANDLE, server.SafePipeHandle));
try
{
action();
}
finally
{
Debug.Assert(SetStdHandle(STD_OUTPUT_HANDLE, defaultHandle));
}
}
}
#endregion
}
and usage sample:
[DllImport("SampleLibrary.dll")]
extern static void LetterList();
private void button1_Click(object sender, EventArgs e)
{
ConsoleOutRedirector.GetOutput(() => LetterList());
}

The only way you can hope to do this is to redirect the standard output whenever you call into the DLL. I've never attempted this and have no idea whether or not it works.
Use SetStdHandle to direct standard output to some other place. For example a handle to the nul device would do. If you need to restore the original standard output handle after calls to the DLL return, that takes another call to SetStdHandle.
You'll need to jump through these hoops for each and every call to the DLL. Things would get even more complex if you have threads and/or callbacks.

Related

DLLImport fails to find the DLL file

I have a C# application which needs to import a function from a C++ dll. I use DLLImport to load the function. It works fine in English and Chinese environment, but it always raise 'Module not found' exception in French operating system.
The code snapshot:
[DllImport("abcdef.dll", CallingConvention = CallingConvention.StdCall)]
public static extern string Version();
Note that letters in the name of module have been replaced but the name itself is in the same format and the same length.
And a screenshot:
Any ideas?
I have tried all methods you proposed, however the problem still exists.
Here is an alternative way which could avoid that error. It uses Win32 APIs to load the library and find the address of the function, then invoke it. Demo code follows:
class Caller
{
[DllImport("kernel32.dll")]
private extern static IntPtr LoadLibrary(String path);
[DllImport("kernel32.dll")]
private extern static IntPtr GetProcAddress(IntPtr lib, String funcName);
[DllImport("kernel32.dll")]
private extern static bool FreeLibrary(IntPtr lib);
private IntPtr _hModule;
public Caller(string dllFile)
{
_hModule = LoadLibrary(dllFile);
}
~Caller()
{
FreeLibrary(_hModule);
}
delegate string VersionFun();
int main()
{
Caller caller = new Caller("abcdef.dll");
IntPtr hFun = GetProcAddress(_hModule, "Version");
VersionFun fun = Marshal.GetDelegateForFunctionPointer(hFun, typeof(VersionFun)) as VersionFun;
Console.WriteLine(fun());
return 0;
}
}

DLLImport a variable MFC dll

So I created the following test project:
[DllImportAttribute("TestMFCDLL.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int test(int number);
private void button1_Click(object sender, EventArgs e)
{
int x = test(5);
}
Which works fine for my MFC dll that has the function test defined, however what I actually have is many MFC dlls that all share a common entry function and run differently based on my inputs. So basically I have tons of dlls that I cannot know at compile time what the name is, I just know that they have a function similar to how this program is setup, is there a way to import a dll based on run-time knowledge? Simply doing this returns an error:
static string myDLLName = "TestMFCDLL.dll";
[DllImportAttribute(myDLLName, CallingConvention = CallingConvention.Cdecl)]
An attribute argument must be a constant expression, typeof expression
or array creation expression of an attribute parameter type
If you want to dynamically load a DLL and use the functions in the DLL, then you'll need to do a little bit more. First you need to load the DLL dynamically. You can use LoadLibrary and FreeLibrary for that.
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
Second you need to get the address of the function in the DLL and call it.
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string functionName);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int Test(int number);
Putting that all together:
IntPtr pLib = LoadLibrary(#"PathToYourDll.DLL");
IntPtr pAddress = GetProcAddress(pLib, "test");
Test test = (Test)Marshal.GetDelegateForFunctionPointer(pAddress, typeof(Test));
int iRresult = test(0);
bool bResult = FreeLibrary(pLib);

Correct way to call a C DLL method from C#

I'm trying to execute some methods (in this particular case, rdOnAllDone) from a third party DLL, written in C, and looking trough the headers files, I found this:
#ifndef TDECLSDONE
#ifdef STDCALL
#define CCON __stdcall
#else
#define CCON __cdecl
#endif
#define TDECLSDONE
#endif
#define DLLIMP __declspec (dllimport)
DLLIMP int CCON rdOnAllDone (void(CCON *)(int));
After goggling for a way to call this method, I made this:
[DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int rdOnAllDone(Delegate d);
public delegate void rdOnAllDoneCallbackDelegate();
private static void rdOnAllDoneCallback()
{
Console.WriteLine("rdOnAllDoneCallback invoked");
}
The method was called correctly except that I couldn't get the int parameter. So I tried adding the input parameter int like this
[DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int rdOnAllDone(Delegate d);
public delegate void rdOnAllDoneCallbackDelegate(int number);
private static void rdOnAllDoneCallback(int number)
{
Console.WriteLine("rdOnAllDoneCallback invoked " + number);
}
But now delegate is called twice and and it crashes the program with the following error " vshosts32.exe has stopped working"
What's the correct way to call this DLL method?
EDIT: Forgot to add the Main method:
public static void Main()
{
rdOnAllDoneCallbackDelegate del3 = new rdOnAllDoneCallbackDelegate(rdOnAllDoneCallback);
rdOnAllDone(del3);
while (true)
{
Thread.Sleep(1000);
}
}
Three things you need to do to make this work right:
you need to tell the pinvoke marshaller about the actual delegate type, using Delegate isn't good enough. That will create the wrong thunk that won't properly marshal the argument. Which is what you saw happening.
you need to tell the marshaller about the calling convention if it isn't __stdcall with the [UnmanagedFunctionPointer] attribute. Getting this wrong imbalances the stack with good odds for a hard crash.
you need to store a reference to the delegate object so that the garbage collector won't collect it. It cannot see references held by native code. Getting this wrong makes the native code fail with a hard crash after the next garbage collection.
So this ought to work better, tweak as necessary:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void rdOnAllDoneCallbackDelegate(int parameter);
[DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int rdOnAllDone(rdOnAllDoneCallbackDelegate d);
class Foo {
private static rdOnAllDoneCallbackDelegate callback; // Keeps it referenced
public static void SetupCallback() {
callback = new rdOnAllDoneCallbackDelegate(rdOnAllDoneCallback);
rdOnAllDone(callback);
}
private static void rdOnAllDoneCallback(int parameter) {
Console.WriteLine("rdOnAllDoneCallback invoked, parameter={0}", parameter);
}
}
Your delegates signature has to match that of the native callback, also it has to have the UnmanagedFunctionPointerAttribute set appropriately.
In your case like so:
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public delegate void rdOnAllDoneCallbackDelegate(int parameter);
[DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int rdOnAllDone(rdOnAllDoneCallbackDelegate callback);
Usage:
{
rdOnAllDone(rdOnAllDoneCallback);
}
private static void rdOnAllDoneCallback(int parameter)
{
Console.WriteLine("rdOnAllDoneCallback invoked, parameter={0}", parameter);
}

Create an API in C# which can be called from it's DLL

I know the title is bit confusing for my question.
Let me explain:-
There are some DLLs written by my seniors and I use them in C# as follows:
Say, Existing DLL name is SeniorDLL and I want to use function SeniorFunc from that DLL.
What I do is:-
private delegate int SeniorFunc(IntPtr Blah);
[DllImport("kernel32")]
public extern static IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi)]
public extern static IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
SeniorFunc fp_Senior;
and in function where I want to use this function, Before first function call I write:
IntPtr handle;
handle = IntPtr.Zero;
handle = LoadLibrary("<DLL Path>");
IntPtr fPtr = GetProcAddress(handle, "SeniorFunc");
fp_Senior = (SeniorFunc)Marshal.GetDelegateForFunctionPointer(fPtr, typeof(SeniorFunc));
and then I use this function via fp_Senior(<Parameter>);
Now I want to create such DLL for me in C# by which I'll be able to call functions from DLL.
Currently I created a DLL but I have create an instance of class in DLL and then have to access like ClassInstance.MyFunction(<Parameters>);
How can I get directly function calls without creating an instance?
In other words, (I don't know I am correct or wrong) How can I create APIs??
Thanks!!
You don't need an instance here, everything can be static. Something like this, with the necessary error checking added:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
internal static class NativeMethods {
public static void SeniorFunc(IntPtr arg) {
if (fp_Senior == null) lookUpSenior();
fp_Senior(arg);
}
private static void lookUpSenior() {
loadSenior();
IntPtr addr = GetProcAddress(SeniorModule, "seniorfunc");
if (addr == IntPtr.Zero) throw new Win32Exception();
fp_Senior = (SeniorFuncDelegate)Marshal.GetDelegateForFunctionPointer(addr, typeof(SeniorFuncDelegate));
}
private static void loadSenior() {
if (SeniorModule == IntPtr.Zero) {
SeniorModule = LoadLibrary("mumble.dll");
if (SeniorModule == IntPtr.Zero) throw new Win32Exception();
}
}
private static IntPtr SeniorModule;
private delegate int SeniorFuncDelegate(IntPtr Blah);
private static SeniorFuncDelegate fp_Senior;
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
private extern static IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true)]
public extern static IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
}
The point of keeping lookupSenior in a separate method is to allow SeniorFunc() to get inlined so it is fast. If you know you'll always use these functions in your program then you can also write a static constructor for the class and do the lookup there. Saves the null check but makes an exception a bit harder to interpret.
There is no such a thing as a method outside a class in C#. So if you must call a method, you have to specify the class name.
The difference with the DLLs you are currently using is that those DLLs are written in C/C++ or other non-.NET language which does not enforce a strict object-oriented approach like C# does.
Thus, nothing forces you to create an instance of a class when calling a method from a .NET library. If a method is declared as static, you can call it directly through ClassName.MethodName().

Suppress 3rd party library console output?

I need to call a 3rd party library that happens to spew a bunch of stuff to the console. The code simply like this...
int MyMethod(int a)
{
int b = ThirdPartyLibrary.Transform(a); // spews unwanted console output
return b;
}
Is there an easy way to suppress the unwanted console output from ThirdPartyLibrary? For performance reasons, new processes or threads cannot be used in the solution.
Well you can use Console.SetOut to an implementation of TextWriter which doesn't write anywhere:
Console.SetOut(TextWriter.Null);
That will suppress all console output though. You could always maintain a reference to the original Console.Out writer and use that for your own output.
Here's one way to do it (which also usually covers managed C++ applications that you P/Invoke from C# or otherwise):
internal class OutputSink : IDisposable
{
[DllImport("kernel32.dll")]
public static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll")]
public static extern int SetStdHandle(int nStdHandle, IntPtr hHandle);
private readonly TextWriter _oldOut;
private readonly TextWriter _oldError;
private readonly IntPtr _oldOutHandle;
private readonly IntPtr _oldErrorHandle;
public OutputSink()
{
_oldOutHandle = GetStdHandle(-11);
_oldErrorHandle = GetStdHandle(-12);
_oldOut = Console.Out;
_oldError = Console.Error;
Console.SetOut(TextWriter.Null);
Console.SetError(TextWriter.Null);
SetStdHandle(-11, IntPtr.Zero);
SetStdHandle(-12, IntPtr.Zero);
}
public void Dispose()
{
SetStdHandle(-11, _oldOutHandle);
SetStdHandle(-12, _oldErrorHandle);
Console.SetOut(_oldOut);
Console.SetError(_oldError);
}
}
This class can be called as follows:
using (new OutputSink())
{
/* Call 3rd party library here... */
}
This will have an impact. Any application logic that tries to use the console from another thread during the time you are using the OutputSink will not function correctly to write to the standard output, standard error, console output, or console error.

Categories

Resources