How to get legacy COM path from Interop assembly - c#

I have interop assembly from I wolud like to get path to orginal COM dll. How this can be done?
Edit:
Here is similar question with post marked as answer but it is so brief that I still don't know what to do.
I have created object from interop dll and used GetModuleHandle( "mycomserver.dll" ) and 0 results returned.
Code looks like that:
class Program
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string libname);
static void Main(string[] args)
{
IntPtr result = GetModuleHandle(typeof(InteropClass).Module.Name);
Console.WriteLine(result);
}
}
Regards,
jotbek

Related

P/Invoke runtime STD error not redirected to file

I am working with a C++ DLL that I access with P/Invokes from C# code. The problem is I cannot redirect the std error that happens in the unmanaged side to a file. This works well if the build is in DEBUG but when the build is in RELEASE the STD logfile-unmanaged does not contain the error but contains and does not close the application, it keeps running like there was no error:
Before Error
After Error
In C++ the STD error is redirected to a file like this:
extern "C" __declspec(dllexport) void RedirectStd()
{
int fileNO = _fileno(stderr);
_close(fileNO);
int file = _open("logfile-unmanaged", O_CREAT | O_RDWR, 0644);
_dup2(file, fileNO);
}
A runtime error in C++ is generated like this:
extern "C" __declspec(dllexport) void DoException()
{
fprintf(stderr, "Before Error\n");
int a = 0;
int b = 10 / a;
fprintf(stderr, "After Error\n");
}
In C# I'm calling both of those methods:
[DllImport("TestError.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
internal static extern void RedirectStd();
[DllImport("TestError.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
internal static extern void DoException();
My Main function:
[HandleProcessCorruptedStateExceptions]
[SecurityCritical]
static void Main(string[] args) {
Console.WriteLine("===== REDIRECT =====");
Console.WriteLine("Native/Unmanaged exception redirected to logfile-unmanaged.");
RedirectStd();
Console.WriteLine("Native/Unmanaged std error redirected.");
Console.WriteLine("");
Console.WriteLine("===== EXCEPTION =====");
DoException();
Console.WriteLine("Waiting for program to crash");
do {
} while (true);
}
EDIT:
C# console application:
program.cs
using System;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Security;
namespace ConsoleWithErrors {
class Program {
[DllImport("TestError.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
internal static extern void RedirectStd();
[DllImport("TestError.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
internal static extern void DoException();
[HandleProcessCorruptedStateExceptions]
[SecurityCritical]
static void Main(string[] args) {
RedirectStd();
DoException();
Console.WriteLine("Waiting for program to crash");
do {
} while (true);
}
}
}
The console application stays opened like there was no error on the unmanaged side.
This works well if the build is in DEBUG but when the build is in RELEASE the STD logfile-unmanaged does not contain the error
It's probably optimized out, since you don't use the result of the division by zero. Try something like this instead:
extern "C" __declspec(dllexport) int DoException()
{
fprintf(stderr, "Before Error\n");
int a = 0;
int b = 10 / a;
fprintf(stderr, "After Error\n");
return b;
}
This will break the result out of internal linkage and force the compiler to emit the code.
You seem to be new to C# P/Invoke however, so here's a few tips:
the SetLastError attribute instructs the marshaller that the function will use the Win32 API SetLastError to set its error state, and your functions absolutely do not do so. You should remove it, because lying to the marshaller is never a recipe for success.
the SecurityCritical attribute has to do with process elevation between trust levels. Again, your application has nothing to do with that and should be removed.
the HandleProcessCorruptedStateExceptions attribute is deprecated since .Net Core (and including .Net 5). So if you're relying on it, you're nearing the end-of-life of your program, and it seems you barely even started writing it. The good news is that division by 0 isn't one of the exceptions that require this attribute to be processed, so again you should remove it!

Using QPDF with C#

I am attempting to translate this qpdf command:
qpdf --qdf --object-streams=disable input.pdf editable.pdf
into the equivalent method calls I would need when using the qpdf dll (available from here: https://sourceforge.net/projects/qpdf/).
I ran the qpdf dll through dumpbin to get the function names, and by looking at the header files that were included for use with a c++ project I can see the parameters for the functions.
For example the function needed to impart the --object-streams option above would (from what I can tell) be this function:
void setObjectStreamMode(qpdf_object_stream_e);
from the c++ header file which becomes:
[DllImport("qpdf21.dll")]
static extern void _ZN10QPDFWriter19setObjectStreamModeE20qpdf_object_stream_e(int stateEnum);
in the C# file.
The problem is when I use the above function I get an
AccessViolationException: Attempted to read or write protected memory
error, which makes me think I need to create a QPDF object somehow, but I have never used object oriented pinvokes, so I'm at a loss of how to make the object accessible in c#.
If anyone is already familiar with using the dll in C#, or even in C++, and could tell me the correct functions to call to replicate the command I would appreciate it!
I've managed to figure it out, the below code replicates the command, turns out I was looking into the wrong header file:
[DllImport("qpdf21.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr qpdf_init();
[DllImport("qpdf21.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
static extern void qpdf_cleanup(ref IntPtr qpdfData);
[DllImport("qpdf21.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
static extern int qpdf_read(IntPtr qpdfdata, [MarshalAs(UnmanagedType.LPStr)] string fileName, IntPtr password);
[DllImport("qpdf21.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
static extern void qpdf_set_object_stream_mode(IntPtr qpdf, int mode);
[DllImport("qpdf21.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
static extern void qpdf_set_qdf_mode(IntPtr qpdf, int value);
[DllImport("qpdf21.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
static extern int qpdf_init_write(IntPtr qpdf, [MarshalAs(UnmanagedType.LPStr)] string fileName);
[DllImport("qpdf21.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
static extern int qpdf_write(IntPtr qpdf);
static void Main(string[] args)
{
//call init
IntPtr qpdfData = qpdf_init();
//call read (which gets and processes the input file)
//0 result == good
int result = qpdf_read(qpdfData, #"scan.pdf", IntPtr.Zero);
//call init_write
result = qpdf_init_write(qpdfData, #"scanEditable.pdf");
//set write options
//disable object stream mode
qpdf_set_qdf_mode(qpdfData, 1);
qpdf_set_object_stream_mode(qpdfData, 0);
//call write
result = qpdf_write(qpdfData);
//call cleanup
qpdf_cleanup(ref qpdfData);
}
Looks like you've figured out a good answer here. You've discovered the C API, which is intended for helping to use QPDF from languages other than C++ through the DLL. The C API is primarily documented in the qpdf-c.h header file. You can find some information in the Using Other Languages section of the manual as well. The C API does not expose the full functionality of qpdf's C++ library. If you find missing pieces, please feel free to create an issue at github. I try to update the C API when I add new interfaces, but I don't do it for every interface, and some of the functionality in the CLI is implemented directly in the tool and doesn't map to a single library function.
If the C API is not rich enough for your use case, it's also possible to write your own C++ class with some functions declared extern "C", export them, and build an additional DLL that you can use in the manner you have found above. You can look at qpdf-c.cc as an example of how this works.

How to implement a .dll in unity code

I wrote a code in unity to read some data from a measurement plate. Unfortunately the compiler gives the following error out:
Assets/Scribts/Initialize.cs(74,35): error CS0246: The type or namespace name `IDevice' could not be found. Are you missing an assembly reference?
After some research I found out that unity can't work with .dll's out of .NET languages. Thus you have to put it into a native plugin.
Do you know what to do or if there are some sample projects?
Thank you for your help.
There is an entire tutorial on this you can read here: http://www.alanzucconi.com/2015/10/11/how-to-write-native-plugins-for-unity/
The summary is:
1) Put the native plugin into the Assets/Plugins folder.
2) Define the api in a class, like:
[DllImport("TestDLL", EntryPoint = "TestSort")]
public static extern void TestSort(int [] a, int length);
There's an example of sqlite here to look at here: https://github.com/codecoding/SQLite4Unity3d
You'll see the C# code is along the lines of the above:
[DllImport("sqlite3", EntryPoint = "sqlite3_open", CallingConvention=CallingConvention.Cdecl)]
public static extern Result Open ([MarshalAs(UnmanagedType.LPStr)] string filename, out IntPtr db);
[DllImport("sqlite3", EntryPoint = "sqlite3_open_v2", CallingConvention=CallingConvention.Cdecl)]
public static extern Result Open ([MarshalAs(UnmanagedType.LPStr)] string filename, out IntPtr db, int flags, IntPtr zvfs);
[DllImport("sqlite3", EntryPoint = "sqlite3_open_v2", CallingConvention = CallingConvention.Cdecl)]
public static extern Result Open(byte[] filename, out IntPtr db, int flags, IntPtr zvfs);
[DllImport("sqlite3", EntryPoint = "sqlite3_open16", CallingConvention = CallingConvention.Cdecl)]
public static extern Result Open16([MarshalAs(UnmanagedType.LPWStr)] string filename, out IntPtr db);
[DllImport("sqlite3", EntryPoint = "sqlite3_enable_load_extension", CallingConvention=CallingConvention.Cdecl)]
public static extern Result EnableLoadExtension (IntPtr db, int onoff);
...but also notice how many #ifdef conditions there are.
Building cross platform native bindings is hard work.
Also note this only applies to C/C++ libraries; if you have an existing C# .Net library (eg. NHibernate), the answer is no, you just flat out can't use that DLL; you must get the C# source and recompile it specifically for unity.

libvlc_new always return null in vlc 2.1.3

libvlc_new always return null. I have copied libvlc.dll and libvlccore.dll in debug folder of my solution directory.
We have also tried calling libvlc_new(0,null) and set the environment variable "VLC_PLUGIN_PATH " to plugins directory, with same result.
Any pointer what is going wrong/ or what is the best way to access libVlc API programmitically in .net environment.
PLEASE FIND CODE SNIPPET BELOW deveopled in C#, VS2010.
IntPtr instance, player ;
string[] args = new string[] {
"-I", "dummy", "--ignore-config",
#"--plugin-path=D:\plugins",
"--vout-filter=deinterlace", "--deinterlace-mode=blend"
};
instance = LibVlc.libvlc_new(args.length, args);
IntPtr media = LibVlc.libvlc_media_new_location(instance, #"rtsp://username assword#IP_address/path");
player = LibVlc.libvlc_media_player_new_from_media(media);
LibVlc.libvlc_media_player_set_hwnd(player, panel1.Handle);
LibVlc.libvlc_media_player_play(player);
we have done P/Invoke for corresponding library calls as:
[DllImport("D:\\myvlc\\myvlc\\bin\\Debug\\libvlc", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr libvlc_new(int argc, [MarshalAs(UnmanagedType.LPArray,
ArraySubType = UnmanagedType.LPStr)] string[] argv);
[DllImport("D:\\myvlc\\myvlc\\bin\\Debug\\libvlc", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr libvlc_media_new_location(IntPtr p_instance,
[MarshalAs(UnmanagedType.LPStr)] string psz_mrl);
[DllImport("D:\\myvlc\\myvlc\\bin\\Debug\\libvlc", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr libvlc_media_player_new_from_media(IntPtr media);
[DllImport("D:\\myvlc\\myvlc\\bin\\Debug\\libvlc", CallingConvention = CallingConvention.Cdecl)]
public static extern void libvlc_media_player_set_hwnd(IntPtr player, IntPtr drawable);
[DllImport("D:\\myvlc\\myvlc\\bin\\Debug\\libvlc", CallingConvention = CallingConvention.Cdecl)]
public static extern void libvlc_media_player_play(IntPtr player);
The param --plugin-path" was ignored.
By copying the whole plugin directory works with 2.1.3.
Found solution, all you need to do is to copy plugins folder to the debug directory of your visual studio solution folder. Hope this would save some time for others trying the same thing. I have been trying this for almost 1 day.

Can't find SDL_LoadBMP() entry point in 'SDL.DLL' with PInvoke

I'm trying to marshal data between SDL and my C# .NET program. The first few calls that I make into SDL.DLL work fine, inasmuch as I get no error and my Windows console app does open an empty application window:
My_SDL_Funcs.SDL_Init(0x0000FFFF); // SDL_INIT_EVERYTHING
IntPtr scrn = My_SDL_Funcs.SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, 0x00000000); // SDL_SWSURFACE
screen = (SDL_Surface)Marshal.PtrToStructure(scrn, typeof(SDL_Surface));
My_SDL_Funcs.SDL_WM_SetCaption("Hello World", null);
// ...
When I try to call SDL_LoadBMP() however, I get this runtime error:
Unable to find an entry point named 'SDL_LoadBMP' in DLL 'SDL'.
The SDL doc says that SDL_LoadBMP takes a const char* file name and returns a pointer to a SDL_Surface struct.
I first tried declaring the PInvoke as:
[DllImport("SDL", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr SDL_LoadBMP([MarshalAs(UnmanagedType.LPWStr)] string file);
When this didn't work, I tried:
public static extern IntPtr SDL_LoadBMP(IntPtr file);
and used:
IntPtr fn = Marshal.StringToHGlobalAnsi(filename);
IntPtr loadedImage = My_SDL_Funcs.SDL_LoadBMP(fn);
Assuming that that the function actuall does exist in this library (SDL.DLL version 1.2.14), am I using the wrong invocation for a const char*?
I downloaded the DLL version you are using, and could not find an export for SDL_LoadBMP.
There is a SDL_LoadBMP_RW, though, so you could rig up your own helper call like so:
private const string SDL = "SDL.dll";
[DllImport(SDL, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr SDL_LoadBMP_RW(IntPtr src, int freesrc);
[DllImport(SDL, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr SDL_RWFromFile(string file, string mode);
public static IntPtr SDL_LoadBMP(string file)
{
return SDL_LoadBMP_RW(SDL_RWFromFile(file, "rb"), 1);
}
UPDATE:
I had a look through the code, and the call you are looking for is defined as a macro, so that is why you can't call it directly. Using the above code basically does the same thing as the macro defintion:
#define SDL_LoadBMP(file) SDL_LoadBMP_RW(SDL_RWFromFile(file, "rb"), 1)

Categories