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.
Related
I'm using Visual Studio 2010 and coding in c#.
public partial class App : Application
{
[DllImport("ewfapi.dll")]
public static extern IntPtr EwfMgrOpenProtected(string lpVolume);
[DllImport("ewfapi.dll")]
public static extern bool EwfMgrCommit(IntPtr hDevice);
public static bool EWFcommit()
{
temp = true;
string strVolumeName = "C:";
hProVol = EwfMgrOpenProtected(strVolumeName);
temp = EwfMgrCommit(hProVol);
return temp;
}
}
The problem I'm having is that these commands do not work on the machine with the EWF enabled.
I've attempted to get the Volume Name from ewfmanager instead of hardcoding it to "C:". However, I'm still learning and I'm having trouble using the command "EwfMgrGetProtectedVolumeList". This api command will return the VolumeName I need to run the other ewfapi commands. However, this command returns "PEWF_VOLUME_NAME_ENTRY " variable which I need to define. This is where I get stuck.
In C++, the header file defines this variable, but in c# header files are non existent. Would I have to convert C++ code to c# code in order to use structures defined in the header file?
Currently, I'm using a work around by executing the commands via command prompt which works flawlessly. But, I'm curious and want to learn the "right"/best way to do this in c#.
Please let me know of any experience using api commands in C#. Thank you.
This is the code I'm trying to convert to C#. I'm unsure how to convert the Declarators in C++ to C#.
typedef struct _EWF_VOLUME_NAME_ENTRY
{
struct _EWF_VOLUME_NAME_ENTRY* Next;
WCHAR Name[1];
} EWF_VOLUME_NAME_ENTRY, * PEWF_VOLUME_NAME_ENTRY;
This is the converted C# code without the declarators:
public struct EWF_VOLUME_NAME_ENTRY
{
/// _EWF_VOLUME_NAME_ENTRY*
public System.IntPtr Next;
/// WCHAR[1]
public string Name;
}
Your attempt was actually really close, it just needed some attributes to help the compiler along (in fact it may have worked without them)
[StructLayout(LayoutKind.Sequential)]
public struct EWF_VOLUME_NAME_ENTRY
{
/// _EWF_VOLUME_NAME_ENTRY*
public System.IntPtr Next;
/// WCHAR[1]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=1)]
public string Name;
}
To use it, the P/Invoke signature of your method would be.
[DllImport("ewfapi.dll")]
public static extern IntPtr EwfMgrGetProtectedVolumeList();
You also need a few more functions
[DllImport("ewfapi.dll")]
public static extern void EwfMgrVolumeNameListDelete(IntPtr list);
[DllImport("ewfapi.dll")]
public static extern bool EwfMgrVolumeNameListIsEmpty(IntPtr list);
[DllImport("ewfapi.dll")]
public static extern void EwfMgrVolumeNameEntryPop(ref IntPtr list);
You could then get the list of protected volumes like so.
public IEnumerable<string> GetProtectedVolumeNames()
{
var listptr = EwfMgrGetProtectedVolumeList();
if(listptr == IntPtr.Zero)
throw new Win32Exception(); //the default constuctor calls Marshal.GetLastWin32Error() for you.
try
{
while(!EwfMgrVolumeNameListIsEmpty(listPtr))
{
var currentStruct = Marshal.PtrToStructure<EWF_VOLUME_NAME_ENTRY>(listPtr);
// Pre .NET 4.5.1 version
// var currentStruct = (EWF_VOLUME_NAME_ENTRY)Marshal.PtrToStructure(listPtr, typeof(EWF_VOLUME_NAME_ENTRY));
yield return currentStruct.Name;
EwfMgrVolumeNameEntryPop(ref listPtr);
}
}
finally
{
if(listptr != IntPtr.Zero)
EwfMgrVolumeNameListDelete(listptr);
}
}
Note this code was written in the browser and is untested, but I think it should work.
EDIT: Important note, if you use this function outside of a foreach and instead manually go through the IEnumerable be sure to dispose of it, otherwise the finally block will not execute and you will have a memory leak (a foreach automatically calls dispose for you when you leave the scope of the loop).
On a side note you may want to check out this old MSDN Magazine article: "Making PInvoke Easy". It includes a link to a program that you can give it the C/C++ signature and it will give you back a rough version of the .NET P/Invoke signature.
Minor tweak to Scotts answer. The name is a null terminated string, so increase the SizeConst to get the rest of the characters of the name:
[StructLayout(LayoutKind.Sequential)]
public struct EWF_VOLUME_NAME_ENTRY
{
/// _EWF_VOLUME_NAME_ENTRY*
public System.IntPtr Next;
/// WCHAR[1]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=300)]
public string Name;
}
I'm trying to make a non-static vendor C++ DLL accessible via C#. In order to do this, I'm writing a managed C++ wrapper DLL which basically creates static variables for the vendor DLL and makes those accessible to the C# application.
Here's an example:
typedef void(__stdcall *LPLISTENER_FUNC)(VENDORHANDLE hModule, VENDORWPARAM wParam, VENDORLPARAM lParam);
public delegate void VENDOR_Delegate(VENDORHANDLE hModule,
VENDORWPARAM wParam, VENDORLPARAM lParam);
public class VENDORWrapper
{
private:
static VENDORHSTORAGE _hStorage;
static VENDOR_Delegate^ _hOpenCallback;
void static Initialize()
{
_hStorage=storage_initialize();
}
void static registerCallback(unsigned int type, VENDOR_Delegate^ callback)
{
if (type == 2)
{
_hOpenCallback = callback;
::storage_register_callback(_hStorage, type, (LPLISTENER_FUNC)&_hOpenCallback);
}
}
bool static Open(String^ file)
{
bool retval=false;
filePath = file;
IntPtr ip = Marshal::StringToHGlobalAuto(filePath);
LPCWSTR str = static_cast<LPCWSTR>(ip.ToPointer());
//ERROR OCCURS HERE
retval = storage_open(_hStorage, str);
Marshal::FreeHGlobal( ip );
return retval;
}
void static Close()
{
storage_close(_hStorage);
}
}
The C# is skeletal:
public static VENDORStorageWrapper.VENDOR_Delegate openCallback
= new VENDORStorageWrapper.VENDOR_Delegate(fileOpened);
static void Main(string[] args)
{
VENDORStorageWrapper.VENDORStorageWrapper.Initialize();
Debug.WriteLine("DLL initalized");
VENDORStorageWrapper.VENDORStorageWrapper.registerCallback(2,
openCallback);
Debug.WriteLine("Callback registered");
VENDORStorageWrapper.VENDORStorageWrapper.Open("blah_file");
Debug.WriteLine("File opened");
}
public static void fileOpened(System.Int32 hstorage, System.UInt32 wParam, System.Int32 lParam)
{
Debug.WriteLine("file opened");
}
The vendor DLL's functions are specified as __stdcall, so I think I'm compliant on that front. The vendor's initialize call (_storage_initialize above) seems to be properly setting the handle, which is statically scoped. The storage_open call that's leading into the exception accepts a VENDORHANDLE (really a long) and an LPCWSTR, which I'm trying to convert the string passed from C# to. I think that's where the problem is...
When run, the app throws an unhandled exception "System.Runtime.InteropServices.SEHException" at the commented line above. The exception's coming from inside the vendor DLL, which I have no source code for. The vendor library works perfectly when called in an unmanaged C++ context and the file is known to be good. I think I'm missing something obvious in how I'm handling the parameters, but I can't see what it is.
I also don't think I have the callback set up properly, but I'm not the point where I can test that yet. Any ideas?
I'm not sure of the true big picture, but my experience using native DLLs with .net c# or vb, create a simple c# wrapper (just declarations) to the native DLL, instead of a c++ wrapper. Maybe this will help if the vendor DLL is really a vanilla DLL, as most are, like Windows api calls.
namespace MyNameSpace
{
public class MyWrapper
{
// passing an int to the native DLL
[DllImport("Vendor.DLL")]
public static extern int DllFunc1(int hModule, int nData);
// passing a string to a native DLL expecting null terminated raw wide characters //
[DllImport("Vendor.DLL", CharSet=CharSet.Unicode )]
public static extern int Dllszset(int hModule, string text);
}
}
Then .net will handle it for you and you call your vendor function as...
MyNameSpace.MyWrapper.Dllszset(h, "hello");
Hope this helps you or someone.
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.
I have a ServerCom DLL that comes from Fortran. I generate automatically using tlbimp a MyFortran.dll from the ServerCom.dll that can be referenced directly from C#.
In a C# Class Library I have referenced MyFortran.dll.
I created a console application that use the MyFortran.dll and generated the correct manifest (in order to have a free-interopt COM environment).
It works perfectly in the console application.
Now, I wrote a simple NUnit test and I got a COM Exception.
System.Runtime.InteropServices.COMException
: Retrieving the COM class factory for
component with CLSID
{0FB0F699-4EF8-4732-B98E-C088825E3912}
failed due to the following error:
80040154 Class not registered
(Exception from HRESULT: 0x80040154
(REGDB_E_CLASSNOTREG)).
How can I solve this?
Thanks,
Adrien.
You can use Activation Context API's to achieve this. This blog post gives all the details.
Here's a summary.
Paste the following code into your project (thanks to Spike McLarty for this):
/// <remarks>
/// Code from http://www.atalasoft.com/blogs/spikemclarty/february-2012/dynamically-testing-an-activex-control-from-c-and
/// </remarks>
class ActivationContext
{
static public void UsingManifestDo(string manifest, Action action)
{
UnsafeNativeMethods.ACTCTX context = new UnsafeNativeMethods.ACTCTX();
context.cbSize = Marshal.SizeOf(typeof(UnsafeNativeMethods.ACTCTX));
if (context.cbSize != 0x20)
{
throw new Exception("ACTCTX.cbSize is wrong");
}
context.lpSource = manifest;
IntPtr hActCtx = UnsafeNativeMethods.CreateActCtx(ref context);
if (hActCtx == (IntPtr)(-1))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
try // with valid hActCtx
{
IntPtr cookie = IntPtr.Zero;
if (!UnsafeNativeMethods.ActivateActCtx(hActCtx, out cookie))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
try // with activated context
{
action();
}
finally
{
UnsafeNativeMethods.DeactivateActCtx(0, cookie);
}
}
finally
{
UnsafeNativeMethods.ReleaseActCtx(hActCtx);
}
}
[SuppressUnmanagedCodeSecurity]
internal static class UnsafeNativeMethods
{
// Activation Context API Functions
[DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "CreateActCtxW")]
internal extern static IntPtr CreateActCtx(ref ACTCTX actctx);
[DllImport("Kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ActivateActCtx(IntPtr hActCtx, out IntPtr lpCookie);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeactivateActCtx(int dwFlags, IntPtr lpCookie);
[DllImport("Kernel32.dll", SetLastError = true)]
internal static extern void ReleaseActCtx(IntPtr hActCtx);
// Activation context structure
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
internal struct ACTCTX
{
public Int32 cbSize;
public UInt32 dwFlags;
public string lpSource;
public UInt16 wProcessorArchitecture;
public UInt16 wLangId;
public string lpAssemblyDirectory;
public string lpResourceName;
public string lpApplicationName;
public IntPtr hModule;
}
}
}
Every time you need to create a COM object (COMObject in this example), wrap the call that creates it in a lambda function, and pass that to UsingManifestDo, like this:
object CreateManifestDependantCOMObject()
{
object myCOMObject = null;
ActivationContext.UsingManifestDo(pathToManifestFile, () => myCOMObject = new COMObject());
return myCOMObject;
}
Yes, this doesn't work. The registry-free COM manifest needs to be embedded in the EXE that uses the COM server. Easy enough for your console app. Not easy when you use NUnit because the EXE is now the unit test runner. You can't/shouldn't mess with it. Hard to do anyway because there are a bunch of them.
Just don't bother, this is a deployment detail that's not relevant for the testing you want to do. Just register the server with regsvr32.exe on the machine that executes the tests and be done with it.
Check out this answer:
How to do registration-free COM in a plug-in architecture
Eugene indicates that this is possible in one of two ways:
1. embed the manifest in the dll and compile with ISOLATION_AWARE_ENABLED
2. use context activation APIs
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().