DLL Import corrupting memory - c#

I am receiving this error while using a dllimport Attempted to read or write protected memory. This is often an indication that other memory is corrupt
private const string dir2 = #"C:\NBioBSP.dll";
[System.Runtime.InteropServices.DllImport(dir2, SetLastError = true, CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)]
public static extern uint NBioAPI_FreeFIRHandle(IntPtr hHandle, IntPtr hFIR);
I call it like this
uint resultado = NBioAPI_FreeFIRHandle(handle, handle);
Anyone know what the issue can be

Two problems.
First, the calling convention is wrong. Per the header file that defines the function (as well as the supporting file that defines NBioAPI as __stdcall on the Win32 platform), you should be using CallingConvention.StdCall.
Second, in the header that defines the types used by the API, NBioAPI_HANDLE and NBioAPI_FIR_HANDLE are typedef'd to UINT, which is always 32 bits (four bytes) long. You're using IntPtr, which has a platform-dependent size (it will be 64 bits in a 64-bit process.) Change the function parameters to uint.

Related

C# EXE w/ Unmanaged C++ Unicode DLL linking to unmanaged C++ ANSI DLL crash

I have a C# executable which loads in a DLL which is a unicode unmanaged C++ DLL. This unmanaged C++ DLL also links to another DLL, an unmanaged C++ DLL that happens to be ANSI.
When I run my C# executable, the program ends up crashing in the ANSI portion of the DLL calls (I haven't been able to pull the exception yet). However, by simply switching the ANSI DLL to Unicode, everything works except for the fact that there is a third DLL, which is from a SDK from another company, which has an apparent sensitivity to unicode/ANSI so it works best if the calling DLL is in ANSI.
So we have one executable calling functions in only one unmanaged unicode C++ DLL which serves as a wrapper for an unmanaged ANSI C++ DLL which is a wrapper for the final unmanaged DLL which we have no information about.
Switching the two intermediary DLL's to unicode corrects the crashing only to have it fail with the third separate vendor DLL (but not fail catastrophically with an exception, they just output incorrectly). We can't switch the first DLL to ANSI because we use Unicode in our C# application and that's our standard across the board.
I don't understand the sensitivity to a second-order DLL. Can someone shed some light on this for me?
I use this class to dynamically link to the DLL's:
static class NativeMethods
{
[DllImport("kernel32", SetLastError = true)]
public static extern bool FreeLibrary(IntPtr hModule);
[DllImport("kernel32", SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32", SetLastError = true)]
public static extern IntPtr LoadLibrary(string dllToLoad);
}
with delegates similar to:
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Auto)]
private delegate int ExampleFunction();
and switching the CharSet.Auto to .Ansi or .Unicode has no effect.
with function calls and such:
m_pDll = NativeMethods.LoadLibrary(#strDLLName);
if (m_pDll == IntPtr.Zero) this.Close();
IntPtr pAddressForExampleFunction = NativeMethods.GetProcAddress(m_pDll, "ExampleFunction");
if (pAddressForExampleFunction == IntPtr.Zero) this.Close();
m_ExampleFunction = (ExampleFunction)Marshal.GetDelegateForFunctionPointer(pAddressForExampleFunction, typeof(ExampleFunction));
with function call:
m_ExampleFunction();
elsewhere in code.
Edit:
As requested, the C++ EXE Counterpart:
In the .h file, defined as a member:
ExampleFunction pExampleFunction;
with
typedef BOOL __declspec(dllimport) (*ExampleFunction)();
The pExampleFunction being defined as:
pExampleFunction= (ExampleFunction) ::GetProcAddress(m_hDll,"ExampleFunction");
using this call, prior:
m_hDll = AfxLoadLibrary(m_DllName);
Most probably the problem happens between two unmanaged dlls because string data transfer between them is inconsistent.
ANSI/Unicode dll flag is a compile-time property. Compiler selects types and functions depending on this flag. TCHAR for Unicode compiled as wchar_t and for ANSI it's char. E.g. such difference could cause out of bound problem if one dll expects to get wchar_t* with length in symbols, but actual received value is char*. This is Undefined Behavior and could cause application crash.
Also many Win API functions have two versions xxxW for Unicode and xxxA for ANSI. E.g:
#ifdef UNICODE
#define MessageBox MessageBoxW
#else
#define MessageBox MessageBoxA
#endif.
On C# side CharSet attribute controls string marshaling and determines how platform invoke finds function names in a DLL. It doesn't affect further string manipulations inside unmanaged C++ dll. Method
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Auto)]
private delegate int ExampleFunction();
has no strings to marshal, so CharSet doesn't affect it. There can be a difference if you have two implementations of this method on your unmanaged C++ side: ExampleFunctionA for ANSI and ExampleFunctionW for Unicode.

Passing pointers from unmanaged code with out modifier

I have a (C/C++) DLL which I am calling by DLLImport to a C# project.
This DLL has this method:
int __stdcall Connect(OUT int *p_sessionID, IN BYTE mode, IN BYTE comport, IN char *servername, IN DWORD serverport);
I tried several ways to "translate" it to C# but one that I find is closer is:
[DllImport("UnmanagedDLL.dll", EntryPoint = "Connect", CallingConvention = CallingConvention.StdCall)]
private static extern unsafe int CS1_Connect(out IntPtr p_sessionID, byte mode, byte comport, string servername, int serverport);
I am trying to invoke like this:
IntPtr connection;
var i = Connect(out connection, 1, 0, "192.0.0.1", 1982);
But I always get the following error:
Additional information: A call to PInvoke function 'DllImportTest!DllImportTest.Program::Connect' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
I know I can reach the DLL because I have another method that worked fine.
What am I doing wrong?
Thanks.
Your first parameter is translated incorrectly.
OUT int *p_sessionID
Here OUT is a macro that indicates semantics to the reader. The macro expands it to nothing. And so after pre-processing you have:
int *p_sessionID
That translates as
out int sessionID
in your C#.
You don't need to declare the function as unsafe, remove that. And the final parameter is unsigned. You might want to switch to uint.
The correct translation would therefore be:
[DllImport("UnmanagedDLL.dll", EntryPoint = "Connect",
CallingConvention = CallingConvention.StdCall)]
private static extern int CS1_Connect(
out int sessionID,
byte mode,
byte comport,
string servername,
uint serverport
);
If you still receive the stack imbalanced message then you would know that the unmanaged function does not have the signature that you have quoted in the question.

How to fix Ntdll.dll APPCRASH with Hardware ID Extractor?

I am using the Hardware ID Extractor library (written in Delphi) from http://www.soft.tahionic.com/download-hdd_id/index.html with the purpose of generating unique system fingerprints.
The library is really good and unlike anything else I have seen on the market, but the main issue with it is that it's unstable when running with .NET applications, meaning that it sometimes works, other times it works for a few function calls then the main application crashes, or most of the time the application instantly crashes when a dll function is being called.
As the developer of the library pointed out (in the last support e-mail that I have received), the fault is with ntdll.dll, as I have seen that for myself:
Following is a link to a demo project I have created with the purpose of testing the dll functions (so to make sure that nothing else interferes, the demo app does that and only that- it calls the dll functions).
http://www.mediafire.com/download/1jws7zh9218v88a/HardwareIdExtractDllTest.zip
The archive contains the Visual Studio 2013 project with source code and a compiled demo application which looks like this:
The list of functions contained by the dll can be found here:
http://www.soft.tahionic.com/download-hdd_id/hardware%20id%20programming%20source%20code/exported%20functions%20for%20non-Delphi.html
If anyone has the knowledge and is willing to test the demo project/application to make tests or personal opinions in regard to the issue, and then share a possible solution with me, I would be grateful.
Please let me know if there's anything I can do to further assist in solving this issue if you think there's anything that can be done about it.
EDIT: This is how I am declaring the dll functions
[DllImport("HardwareIDExtractorC.dll")]
private static extern bool EnterKey(int key);
[DllImport("HardwareIDExtractorC.dll")]
private static extern bool IsCPUIDAvailable();
[DllImport("HardwareIDExtractorC.dll")]
private static extern int GetCPUCount();
[DllImport("HardwareIDExtractorC.dll")]
private static extern byte CoreNumber2CoreMask(byte cpuCore);
[DllImport("HardwareIDExtractorC.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "GetCPUID")]
[return: MarshalAs(UnmanagedType.LPStr)]
private static extern string GetCPUID(byte cpuCore);
[DllImport("HardwareIDExtractorC.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "GetCpuIdNow")]
[return: MarshalAs(UnmanagedType.LPStr)]
private static extern string GetCpuIdNow();
[DllImport("HardwareIDExtractorC.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "GetIDESerialNumber")]
[return: MarshalAs(UnmanagedType.LPStr)]
private static extern string GetIDESerialNumber(byte driveNumber);
The functions that fail are the ones that return string. Such a p/invoke marshals the return value as a pointer to null terminated character array, and then calls CoTaskMemFree on the raw pointer returned by the unmanaged code.
With probability close to 1 that string was not allocated on the COM heap and so the error is likely in the C# p/invoke declarations. That an access violation then arises in ntdll is quite plausible.
So, to make progress you need to fix the p/invoke calls. I cannot tell you how to do so because you have not shown the unmanaged function declarations. Or, more importantly, how the memory is allocated.
There are some clues at the documentation
procedure ReleaseMemory (P: PAnsiChar); stdcall;
I think this tells us that the strings returned by the DLL must be deallocated by the DLL, by calling this function. Presumably because they were allocated by the DLL's heap allocator.
So, use IntPtr for the return type of the functions that return text. Call Marshal.PtrToStringAnsi to convert to a C# string. And then pass the pointer to ReleaseMemory.
For example:
[DllImport(DllPath, CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetCPUID(ushort CoreMask);
[DllImport(DllPath, CallingConvention = CallingConvention.StdCall)]
private static extern void ReleaseMemory(IntPtr P);
....
IntPtr ptr = GetCPUID(CoreMask);
string cpuid = Marshal.PtrToStringAnsi(ptr);
ReleaseMemory(ptr);

ERROR_FILE_NOT_FOUND unexpectedly returned for OpenBackupEventLog function

I'm trying to open an .evtx file on a Windows 7 x64 machine using the OpenBackupEventLog function however I keep on getting ERROR_FILE_NOT_FOUND (error code 2) even though the file does exist.
My P/Invoke declaration / point where I call the file is:
[DllImport("advapi32.dll", SetLastError = true, ExactSpelling = false, EntryPoint = "OpenBackupEventLog")]
public static extern IntPtr OpenBackupEventLog(
[MarshalAs(UnmanagedType.LPTStr)]string uncServerName,
[MarshalAs(UnmanagedType.LPTStr)]string fileName);
IntPtr ptr = NativeMethods.OpenBackupEventLog(null, filename);
if (ptr == IntPtr.Zero && File.Exists(filename))
{
// This exception is thrown and so the file does exist
throw new Win32Exception(string.Format("Failed to open event log archive '{0}'", filename));
}
Note that this is inside an x86 process.
The only thing that I can think of is that the problem is down to Unicode / ANSI marshalling (previously I recall getting ERROR_INVALID_PARAMETER instead), however I've double checked and playing around with the marshalling has no effect.
Why is this failing to open the file / how can I diagnose this?
[DllImport("advapi32.dll", ..., EntryPoint = "OpenBackupEventLog")]
The EntryPoint property is the source of your problem here. The exported function names are OpenBackupEventLogA and OpenBackupEventLogW. Respectively the ANSI and the Unicode versions of this function. Your declaration would use the ANSI version since you didn't specify the CharSet property.
The pinvoke marshaller can find the A and W versions automatically when ExactSpelling = false (the default). But not when you specify the name explicitly.
There's no point in using the ANSI version, use CharSet.Auto and omit EntryPoint. MarshalAs is unnecessary as well, strings already are marshaled as LPTStr. Thus:
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr OpenBackupEventLog(string uncServerName, string fileName);
Since this is a 64-bit OS and you are accessing the files using a 32-bit app, the most likely cause of this exception is that the OS very "helpfully" automatically redirects requests for the System directory (C:\Windows\system, e.g.) to the SysWOW64 directory C:\Windows\SysWOW64.
Fortunately, there is a builtin workaround: the sysnative directory.
When you generate the path to the file name, use something similar to the following:
string filePath = #"%WINDIR%\sysnative\winevt\logs\mylog.evtx";
However, only do this if you retain the app as a 32-bit app. It will not resolve correctly as a 64-bit app.
This was a encoding Unicode vs ANSI issue - I seemed to manage to get this to start working again somehow, but later realised that it was returning ANSI strings instead of UNICODE strings - obviously I had accidentally started using the ANSI versions of these functions which is no good.
Its now working with the following PInvoke declaration
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "OpenBackupEventLogW")]
public static extern EventLogHandle OpenBackupEventLog(
string uncServerName,
string fileName);
The key points being that I:
Removed the MarshalAs attributes
Added the CharSet = CharSet.Unicdoe paramter to my DllImport declaration
Added W to the end of the entry point name
Note that it also seems to work if I remove the W from the end of the entry point name as long s the CharSet = CharSet.Unicdoe paramter is there.

How to open a file when file handle number is known?

I open a file in C# with FileStream, and I got the file handle number with this line:
IntPtr file_handle = fs.SafeFileHandle.DangerousGetHandle();
Now I want to pass this handle to C++ code and use this handle value to access the file. Is this possible? How to open a file with merely a file handle in C++?
Thanks.
Update
I use C# to P/Invoke into a C++ Win32 DLL(not a COM DLL). I open the file in C# as FileStream, and pass the handle to the C++. Here is some of my code in the C++ DLL:
extern "C" __declspec(dllexport)void read_file(HANDLE file_handle)
{
char buffer[64];
::printf("\nfile = %d\n",file_handle);
if(::ReadFile(file_handle,buffer,32,NULL,NULL))
{
for(int i=0;i<32;i++)
cout<<buffer[i]<<endl;
}
else
cout<<"error"<<endl;
}
And here is my C# code:
[DllImport("...",EntryPoint = "read_file", CharSet = CharSet.Auto)]
public static extern void read_file(IntPtr file_handle_arg);
But I get this error:
Unhandled Exception: System.AccessViolationException: Attempted to read or write
protected memory. This is often an indication that other memory is corrupt.
Thanks.
You can use win32 calls, the same way the filestream/file constructors do (via p/invoke).
Cracking it open in .NET Reflector, it looks like it is using this function:
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern SafeFileHandle CreateFile(
string lpFileName,
int dwDesiredAccess,
FileShare dwShareMode,
SECURITY_ATTRIBUTES securityAttrs,
FileMode dwCreationDisposition,
int dwFlagsAndAttributes,
IntPtr hTemplateFile);
Here is an official reference:
http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx
This is just to open the file, though, as you asked when you said:
How to open a file with merely a file handle in C++
If you want to read an already open file, you might have more trouble. I'm not sure. You might be able to use this function:
[DllImport("kernel32.dll", SetLastError=true)]
internal static extern unsafe int ReadFile(
SafeFileHandle handle,
byte* bytes,
int numBytesToRead,
IntPtr numBytesRead_mustBeZero,
NativeOverlapped* overlapped
);
http://msdn.microsoft.com/en-us/library/aa365467(v=VS.85).aspx
That entirely depends -- but it's unlikely that you will be able to do this. I'm assuming that your C# code and C++ code are running in different processes -- if you're in the same process you should just be able to marshall over the IntPtr over as a HANDLE.
The problem is that file handles are specific to a process -- you won't be able to use that handle in another process.
That said, you're probably better off:
Passing the name of the file to the C++ code and opening it there
Passing the data actually contained whithin the file to the C++ and dealing with it there.
If the C++ code is C++/CLI, then don't bother with the handle at all. Just pass the FileStream object directly to your C++ code.
If the C++ is native code, then you can use the file handle anywhere you'd normally use a Windows HANDLE value for files, such as ReadFile and WriteFile. You wouldn't use the handle to open a file because it's already open. If you want another copy of the handle, or if you want to give the handle to another process, then use DuplicateHandle. If you need to the value with POSIX-like functions like _read and _write, then call _open_osfhandle to get a file descriptor. You can wrap the file descriptor into a C FILE* stream with _fdopen.
Turns out the title isn't really what the OP was after.
But if someone ever really needs to do this (say: Re-opening a file with different permissions), you can probably use a combination of GetFileInformationByHandle to get the File ID and OpenFileById.
FWIW.

Categories