Platform Invoke for Newland barcode scanner - c#

I am attempting to access a Newlands scanner using Platform Invoke from a c# program.
It should be relatively straight forward.
I set up my P/Invoke and and call it.
[DllImport("NLcpfw.dll", EntryPoint = "cpfw_open", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr cpfw_open(string pwStrPort,
string pwStrParam,
int nMode);
public static void CallFromHere(){
IntPtr hDev = cpfw_open("udp", "", CPFW_OM_NORMAL);
//GCHandle handle = GCHandle.Alloc(HNLCPFW, GCHandleType.Pinned);
System.Diagnostics.Debug.Assert(hDev != null);
NewlandInterface.cpfw_close(hDev);
}
Some how it is not picking it up.
I get a BadImageFormatException was unhandled
Make sure it is a valid managed assembly
Make sure you have supplied a correct path for the assembly
The C++ header reads
__declspec(dllimport) HNLCPFW WINAPI cpfw_open(WCHAR *pwStrPort, WCHAR *pwStrParam, int nMode = CPFW_OM_NORMAL);
typedef struct
{
void* hDev;
int nMode;
PNLCPFW_PLUG_API DevAPI;
HINSTANCE hPlugDll;
void *exData;
}NLCPFW,*HNLCPFW;
I'm assuming it is ok just to take a IntPtr in my p\Invoke code.
Any ideas as to why this is happening would be much appreciated.
I have copied all of the dll's in with the exe. In this case these are
NLcpfw.dll, cpfw_udp.dll, cpfw_tcp.dll,cpfw_hidpos.dll etc
Thanks leppie I need to change the platform to X86

Related

C# WPF passing UTF16 string to a function that accepts char *

I've created a wpf project which has a helper static class that contains all my c++ backend code. One such function is defined as:
public static unsafe class Backend {
[DllImport("Mandel.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static void write(void* ptr, char* path);
}
public partial class MainWindow : Window
{
public MainWindow()
{
string path = "mypath";
InitializeComponent();
unsafe
{
char *p; //convert
void* myObj = Backend.init_obj(1920, 1080);
Backend.gen(myObj);
Backend.write(myObj, p);
}
}
}
The void* ptr is actually my object that is casted in order to marshall it onto the C# side. The problem I face is that whenever I try to invoke this with a string literal in wpf, I get that Visual C# cannot convert this because string literals are encoded in UTF16. Naturally I tried many things other than manually copying the relevant bytes to a char array. Any tips?
One of the things the CLR can do pretty well for interop with C/C++ code is marshalling data structures between managed and unmanaged code. Since strings are pretty important, a lot of work went into making strings marshal as well as possible.
As a side note, you're using void* for the context object that's created by init and passed to write. Since you're just handing it back, you can replace it with IntPtr and avoid unsafe blocks altogether. IntPtr is always the size of a pointer in the current architecture.
First, let's change the declaration of the imported functions. CharSet.Ansi tells it to marshal strings as ANSI. The ptr parameter becomes IntPtr
[DllImport("Mandel.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static IntPtr init(int width, int height);
[DllImport("Mandel.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static void gen(IntPtr ptr);
[DllImport("Mandel.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static void write(IntPtr ptr, string path);
And from there, you can figure out how to modify the function to deallocate ptr and any others you have to call.
Using those functions becomes a lot easier and a lot cleaner. You don't need the unsafe block and you can pass path directly to write.
public MainWindow()
{
string path = "mypath";
InitializeComponent();
IntPtr myObj = Backend.init_obj(1920, 1080);
Backend.gen(myObj);
Backend.write(myObj, path);
}
Original comment that got it working:
Instead of trying to create the char* parameter yourself, change the declaration so the second parameter is string and let the Runtime marshal it for you. Because it's an ANSI string, you're never going to get full unicode fidelity but that's a problem created by the C++ code.

Windows Defender Antivirus scan from C# [AccessViolation exception]

We are writing a code to do on-demand scan of a file from C# using Windows Defender APIs.
[DllImport(#"C:\Program Files\Windows Defender\MpClient.dll")]
public static extern int WDStatus(out bool pfEnabled);
[DllImport(#"C:\Program Files\Windows Defender\MpClient.dll")]
public static extern int MpManagerOpen(uint dwReserved, out IntPtr phMpHandle);
[DllImport(#"C:\Program Files\Windows Defender\MpClient.dll")]
public static extern int MpScanStart(IntPtr hMpHandle, uint ScanType, uint dwScanOptions, IntPtr pScanResources, IntPtr pCallbackInfo, out IntPtr phScanHandle);
[DllImport(#"C:\Program Files\Windows Defender\MpClient.dll")]
public static extern int MpHandleClose(IntPtr hMpHandle);
private void DoDefenderScan_Click(object sender, EventArgs e)
{
try
{
bool pfEnabled;
int result = WDStatus(out pfEnabled); //Returns the defender status - It's working properly.
ErrorHandler.ThrowOnFailure(result, VSConstants.S_OK);
IntPtr phMpHandle;
uint dwReserved = 0;
IntPtr phScanHandle;
MpManagerOpen(dwReserved, out phMpHandle); //Opens Defender and returns the handle in phMpHandle.
tagMPRESOURCE_INFO mpResourceInfo = new tagMPRESOURCE_INFO();
mpResourceInfo.Path = "eicar.com";
mpResourceInfo.Scheme = "file";
mpResourceInfo.Class = IntPtr.Zero;
tagMPRESOURCE_INFO[] pResourceList = new tagMPRESOURCE_INFO[1];
pResourceList.SetValue(mpResourceInfo, 0);
tagMPSCAN_RESOURCES scanResource = new tagMPSCAN_RESOURCES();
scanResource.dwResourceCount = 1;
scanResource.pResourceList = pResourceList;
IntPtr resourcePointer = StructToPtr(scanResource);
result = MpScanStart(phMpHandle, 3, 0, resourcePointer, IntPtr.Zero, out phScanHandle); **//Getting Access violation exception here**.
MpHandleClose(phMpHandle);
MpHandleClose(phScanHandle);
Marshal.FreeHGlobal(resourcePointer);
}
catch (Exception)
{ }
}
And the structure is defined here.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct tagMPSCAN_RESOURCES
{
public uint dwResourceCount;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 1)]
public tagMPRESOURCE_INFO[] pResourceList;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct tagMPRESOURCE_INFO
{
[MarshalAs(UnmanagedType.LPWStr)]
public String Scheme;
[MarshalAs(UnmanagedType.LPWStr)]
public String Path;
public IntPtr Class;
}
public class MPRESOURCE_CLASS
{
public uint Value;
}
private static IntPtr StructToPtr(object obj)
{
var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(obj));
Marshal.StructureToPtr(obj, ptr, false);
return ptr;
}
The code is written based on the documentation available at
https://msdn.microsoft.com/en-us/library/vs/alm/dn920144(v=vs.85).aspx
We are getting this exception
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at
result = MpScanStart(phMpHandle, 3, 0, resourcePointer, IntPtr.Zero, out phScanHandle); **//Getting Access violation exception here**.
What could be the problem? Is the format of struct is correct?
P.S - No information about MPRESOURCE_CLASS is available in msdn.
I'm not sure, whether this line of code is correct.
mpResourceInfo.Class = IntPtr.Zero;
Update:
Quick scan is working fine with this code:
result = MpScanStart(phMpHandle, 1, 0, IntPtr.Zero, IntPtr.Zero, out phScanHandle);
Defender logs in the event viewer [ Applications and Services Logs-Microsoft-Windows-Windows Defender/Operational ] as
Windows Defender scan has started.
Scan ID:{CDC2AC0D-7648-4313-851C-4D8B7B5EB5CD}
Scan Type:AntiSpyware
Scan Parameters:Quick Scan
I couldn't identify the problem here. So I ended up with Antimalware Scan Interface (AMSI) available starting from Windows 10.
I have written a sample C# code here.
One thing I found is AMSI requires Windows defender/any antivirus to be turned on to verify the file passed to API. But triggering a scan through MpClient.dllwill trigger a defender scan even if defender is turned off.
Also ensure your project targets x64 platform.
public enum AMSI_RESULT
{
AMSI_RESULT_CLEAN = 0,
AMSI_RESULT_NOT_DETECTED = 1,
AMSI_RESULT_DETECTED = 32768
}
[DllImport("Amsi.dll", EntryPoint = "AmsiInitialize", CallingConvention = CallingConvention.StdCall)]
public static extern int AmsiInitialize([MarshalAs(UnmanagedType.LPWStr)]string appName, out IntPtr amsiContext);
[DllImport("Amsi.dll", EntryPoint = "AmsiUninitialize", CallingConvention = CallingConvention.StdCall)]
public static extern void AmsiUninitialize(IntPtr amsiContext);
[DllImport("Amsi.dll", EntryPoint = "AmsiOpenSession", CallingConvention = CallingConvention.StdCall)]
public static extern int AmsiOpenSession(IntPtr amsiContext, out IntPtr session);
[DllImport("Amsi.dll", EntryPoint = "AmsiCloseSession", CallingConvention = CallingConvention.StdCall)]
public static extern void AmsiCloseSession(IntPtr amsiContext, IntPtr session);
[DllImport("Amsi.dll", EntryPoint = "AmsiScanString", CallingConvention = CallingConvention.StdCall)]
public static extern int AmsiScanString(IntPtr amsiContext, [InAttribute()] [MarshalAsAttribute(UnmanagedType.LPWStr)]string #string, [InAttribute()] [MarshalAsAttribute(UnmanagedType.LPWStr)]string contentName, IntPtr session, out AMSI_RESULT result);
[DllImport("Amsi.dll", EntryPoint = "AmsiScanBuffer", CallingConvention = CallingConvention.StdCall)]
public static extern int AmsiScanBuffer(IntPtr amsiContext, [In] [MarshalAs(UnmanagedType.LPArray)] byte[] buffer, uint length, [In()] [MarshalAs(UnmanagedType.LPWStr)] string contentName, IntPtr session, out AMSI_RESULT result);
//This method apparently exists on MSDN but not in AMSI.dll (version 4.9.10586.0)
[DllImport("Amsi.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern bool AmsiResultIsMalware(AMSI_RESULT result);
private void CallAntimalwareScanInterface()
{
IntPtr amsiContext;
IntPtr session;
AMSI_RESULT result = 0;
int returnValue;
returnValue = AmsiInitialize("VirusScanAPI", out amsiContext); //appName is the name of the application consuming the Amsi.dll. Here my project name is VirusScanAPI.
returnValue = AmsiOpenSession(amsiContext, out session);
returnValue = AmsiScanString(amsiContext, #"X5O!P%#AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*", "EICAR", session, out result); //I've used EICAR test string.
AmsiCloseSession(amsiContext, session);
AmsiUninitialize(amsiContext);
}
I've been searching about problem and I've read this as one of the possible causes:
"You often see differences between debug and release builds because
debug builds contain extra metadata to assist in debugging."
here: https://social.msdn.microsoft.com/Forums/vstudio/en-US/4f48c152-68cd-45ec-a11e-baa7de7f79c3/attempted-to-read-or-write-protected-memory?forum=csharpgeneral
Also you should check this answer to "Is it possible to catch an access violation exception in .NET?" and the further details that are explained in the article Handling Corrupted State Exceptions in MSDN magazine
...
So, according to that answers and articles I'd try:
1st Double check signatures and COM interop thunks for all unmanaged code to verify that they're correct.
2nd Set Visual Studio Debugger to bypass this exception:
Tools menu ->Options -> Debugging -> General -> Uncheck this option "Suppress JIT optimization on module load"
3rd Try-Catch the exception
(note: if you are using .Net 4 then in App.config, within the tag modify runtime to include legacyCorruptedStateExceptionsPolicy enabled="true"like:
<runtime>
<legacyCorruptedStateExceptionsPolicy enabled="true"/>
</runtime>
)
In addition, here, I've found that some .net framework versions (latest comment point to 4.6.1 in one of the answer's comments) has a bug related with this exception and the solution, in the past, has been upgrading the framework.
Also, in the one of that answers I've read:
Hi There are two possible reasons.
1.We have un-managed code and we are calling it from managed code. that is preventing to run this code. try running these commands and
restart your pc
cmd: netsh winsock reset
open cmd.exe and run command "netsh winsock reset catalog"
2.Anti-virus is considering un-managed code as harmful and restricting to run this code disable anti-virus and then check
I'd like to know if some of these approaches helps you to solve your issue.
I really hope this helps.
KR,
Juan
You may use Antimalware Scan Interface to check file for malware.
The Antimalware Scan Interface (AMSI) is a generic interface standard that allows applications and services to integrate with any antimalware product present on a machine. It provides enhanced malware protection for users and their data, applications, and workloads.
It's available starting from Windows 10.
Windows Defender comes with CLI tool 'MpCmdRun' - it's not a full-sized antivirus app, but an API interface to the actual Windows Defender that's always (?) running in background.
Saving to a temporary file via Path.GetTempFileName() and then running a scan like this
MpCmdRun.exe -Scan -ScanType 3 -File "c:\path\to\temp\file" -DisableRemediation
works fine even in an ASP.NET (Core) app, that runs under app-pool identity
I've actually written a small (40 lines of code) C# helper that does everything for you (saves temp file, runs a scan, cleans up)
https://github.com/jitbit/WinDefender/blob/main/WinDefender.cs

Calling Pocketsphinx in C# AccesViolationException

I'm trying to do the pocketsphinx tutorial in C# using pinvoke but get an AccessViolationException when I try to decode using ps_decode_raw().
IntPtr ps = PocketSphinx.ps_init(config);
IntPtr fh = Win32Util.fopen(#"goforward.raw", "rb");
int rv = PocketSphinx.ps_decode_raw(ps, fh, "goforward", -1);
The functions are wrapped as follows
//ps_decoder_t* ps_init(cmd_ln_t* config)
[DllImport("pocketsphinx.dll",
SetLastError = true,
CallingConvention = CallingConvention.Cdecl)]
public extern static IntPtr ps_init(
IntPtr config);
//int ps_decode_raw(ps_decoder_t *ps, FILE *rawfh, char const *uttid, long maxsamps);
[DllImport("pocketsphinx.dll",
SetLastError = true,
CallingConvention = CallingConvention.Cdecl)]
public extern static int ps_decode_raw(
IntPtr ps,
IntPtr rawfh,
[MarshalAs(UnmanagedType.LPStr)] string uttid,
int maxsamps);
[DllImport("msvcrt.dll",
SetLastError = true,
CallingConvention = CallingConvention.Cdecl)]
public extern static IntPtr fopen(
[MarshalAs(UnmanagedType.LPStr)] string _Filename,
[MarshalAs(UnmanagedType.LPStr)] string _Mode);
I wrapped C's fopen as well just because it was the quickest way I can think of implementing the tutorial.
I tried calling cmd_ln_retain on ps to make sure that ps wasn't causing the problem. (it wasn't). I also removed my debug code in the above.
I'm pretty sure something is up with the fopen but I'm not sure what.
Someone asked for the pocketsphinx log. https://justpaste.it/h52t
You don't check for errors anywhere. And it's wrong to set SetLastError to true for these functions. They won't call SetLastError.
Your big problem though is that the library uses a particular instance of the C runtime, depending on how you built it. And your fopen import is from a different instance of the C runtime.
You'll need to add some code to the library that exposes functions to create and destroy FILE* objects. By doing that you'll get a FILE* made by the correct runtime.

C# Using VB6-Dll - AccessViolationException

I try to use a VB6 DLL in a C# Program. But I allways get a AccessViolationException. Maybe you can tell me what Im doing wrong.
I created a Test-VB6-DLL like in this tutorial:
http://oreilly.com/pub/a/windows/2005/04/26/create_dll.html
Then I tried to use this DLL dynamically like in this Post:
http://blogs.msdn.com/b/jonathanswift/archive/2006/10/03/dynamically-calling-an-unmanaged-dll-from-.net-_2800_c_23002900_.aspx?PageIndex=3#comments
But also if I try it by using [DLLImport]. I allways run into the AccessViolationException.
Maybe someone can give me a hint.
regards
viktor
P.S.: What I was able to do is to create a reference to an existing DLL. But this approach has the disadvantage, that I have to update all the references if the DLL is updated. And this will happen (more or less) open because to dlls are part of a softwareproject that is under developmen. Maybe there is a possibility to update the references without to need to recompile the C# program?
#MarkJ: No - binary compatibility brought no success.
Here are the sources:
The VB6-Dll:
Option Explicit
Public Function Increment(var As Integer) As Integer
If Not IsNumeric(var) Then Err.Raise 5
Increment = var + 1
End Function
And here the C# code that tries to use the VB6 Dll:
class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr LoadLibrary(String DllName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, byte[] procedureName);
static void Main(string[] args)
{
IntPtr pDll = LoadLibrary(#"P:\dev\Path\to\TestProjekt.dll");
string x = "Increment";
Encoding e = Encoding.GetEncoding("ISO-8859-1");
byte[] b = e.GetBytes(x);
IntPtr pAddressOfFunctionToCall = GetProcAddress(pDll, b);
Increment inc = Increment)Marshal.
GetDelegateForFunctionPointer(pAddressOfFunctionToCall,
typeof(Increment));
int a = inc(5); // <---- Here the AccessViolationException is thrown
return;
}
}
In the meantime I have read any doc I could find but still I don't habe any idea why this ist not working grgrgrgrgr
regards
viktor
Your byte[] b has no terminating null, so isn't a valid unmanaged LPCSTR. I don't understand why you are fiddling about trying to encode the method name by hand, instead of declaring GetProcAddress like this and having the Framework interop code take care of the marshalling for you:
public static extern IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procedureName);
You must check the return value (pAddressOfFunctionToCall). When it isIntPtr.Zero as I believe you are getting, because your lpProcName argument to GetProcAddress is wrong, then attempting to call through its Delegate wrapper will always give an AccessViolationException.
Also, don't omit to call FreeLibrary on the module handle when you are done.

Entry Point Not Found Exception

I'm trying to use a C++ unmanaged dll in a C# project and I'm getting an error when trying to call a function that says that entry point cannot be found.
public class Program
{
static void Main(string[] args)
{
IntPtr testIntPtr = aaeonAPIOpen(0);
Console.WriteLine(testIntPtr.ToString());
}
[DllImport("aonAPI.dll")]
public static extern unsafe IntPtr aaeonAPIOpen(uint reserved);
}
Here is the dumpbin for the function:
5 4 00001020 ?aaeonAPIOpen##YAPAXK#Z
I changed the dll import to [DllImport("aonAPI.dll", EntryPoint="?aaeonAPIOpen")] and [DllImport("aonAPI.dll", EntryPoint="_aaeonAPIOpen")] and no luck.
Using the undname.exe utility, that symbol demangles to
void * __cdecl aaeonAPIOpen(unsigned long)
Which makes the proper declaration:
[DllImport("aonAPI.dll", EntryPoint="?aaeonAPIOpen##YAPAXK#Z",
ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr aaeonAPIOpen(uint reserved);
It looks like the function you're trying to call is compiled as a C++ function and hence has it's name mangled. PInvoke does not support mangled name. You need to add an extern "C" block around the function definition to prevent name mangling
extern "C" {
void* aaeonAPIOpen(uint reserved);
}

Categories

Resources