DllImport user32 vs user32.dll - c#

What is the difference between the usages of DllImport here? Specifically, does "user32" just mean "user32.dll", or does it mean "user32.lib" or something else?
[DllImport("user32")]
protected static extern int GetKeyboardState(byte[] pbKeyState);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
protected static extern short GetKeyState(int vKey);
You can probably ignore the CharSet and CallingConvention.
If they are the same, I can rewrite this to be more consistent, but if not, I don't want to have a bunch of problems with it.

In this example, there is no difference. The .dll extension will automatically be appended to "user32" to create "user32.dll". However, this is not always the case. If the library file name contains a period, the .dll extension will not be automatically appended.
Some examples:
[DllImport("user32")] --> Resolves "User32.dll". Correct.
[DllImport("user32.dll")] --> Resolves "User32.dll". Correct.
[DllImport("mylib.version5")] --> Resolves "mylib.version5". Incorrect
[DllImport("mylib.version5.dll")] --> Resolves "mylib.version5.dll". Correct.

On Windows there is no difference, the import will be performed successfully if you omit the extension. Normally omitting the extension is desired when running Mono with the <dllmap> configuration section, where the P/Invoke runtime will look for aliases.

Related

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);

Writing a lite-weight libVLC wrapper. Need help (Newish to P/Invoke)

I'm writing a super-simple ultra-lite weight .Net wrapper for the LibVLC media library since the only things I need access to are the ability to play, pause and stop media files. I've posted a couple of questions on this and gotten some answers but unfortunately I'm just left with more questions.
We'll start from the top and work down.
The documentation first states I have to initialize VLC with a call to the function with this specification:
libvlc_instance_t* libvlc_new (int argc, const char *const *argv)
for which I have the defined the following method:
[DllImport("libvlc", EntryPoint = "libvlc_new",
CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr NewCore(int argc, IntPtr argv);
And I'm calling the function like this:
private IntPtr Instance;
this.Instance = DGLibVLC.NewCore(0, IntPtr.Zero);
I have tried it several different ways. Initially I did not know about the CallingConvention which was leading to an unbalanced stack which brought me here in the first place. That issue was resolved and the method has gone through several iterations, none of which have proved successful, by which I mean IntPtr is always 0 after the method call. I've tried it like it is above, with the second argument being String[] argc, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[],
I've tried having it return to a Long (which actually resulted in the Long having a value in it), but nothing so far has worked correctly.
Does anyone know the correct way to call this function from the LibVLC DLL Library?
EDIT: On a suggestion I tried calling the error message function of the library:
Specification:
const char* libvlc_errmsg (void)
Implementation:
[DllImport("libvlc", EntryPoint = "libvlc_errmsg",
CallingConvention = CallingConvention.Cdcel)]
public static extern string GetLastError();
Call:
Console.WriteLine(DGLibVLC.GetLastError());
Result:
Null
The documentation states it will return Null if there is no error. This must indicate that the initial function call NewCore was working correctly but something is still going wrong somehow.
To be cover all bases I checked that the DLLs match the documentation, they do. 2.0.6.0. The documentation I am referencing is here.
EDIT: I can confirm there is no error. When using an initialized to zero long variable to store the result of NewCore I can see it returning something. What I am doing wrong here is where I am trying to store the pointer being returned by the unmanaged function that returns the pointer to the object. How do I store the pointer to the opaque structure reference being passed back?
It doesn't have anything to do with the way you call the function. You cannot get anywhere when you get IntPtr.Zero back from libvlc_new(). It means "there was an error". You'll need to focus on error reporting first, call libvlc_errmsg() to try to get a description for the problem.
So after much looking around and asking questions I've come full circle.
I looked deeply into LibVLC.Net and found how they were importing the DLL functions and adapted what they did to my own wrapper and it worked.
To summarize:
There are some Win32 API functions declared in the code at the start:
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetDllDirectory(string lpPathName);
[DllImport("kernel32", SetLastError = true)]
private static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FreeLibrary(IntPtr hModule);
that handle providing a handle to a dll and setting a directory search path.
I don't know exactly what it all means but when you initialize the LibVLC.Net library (the primary object) it loads pretty much EVERY function like so:
m_libvlc_media_player_new = (libvlc_media_player_new_signature)LoadDelegate<libvlc_media_player_new_signature>("libvlc_media_player_new");
That delegate is defined here like so:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate IntPtr libvlc_media_player_new_signature(IntPtr p_instance);
//==========================================================================
private readonly libvlc_media_player_new_signature m_libvlc_media_player_new;
//==========================================================================
public IntPtr libvlc_media_player_new(IntPtr p_instance)
{
VerifyAccess();
return m_libvlc_media_player_new(p_instance);
}
And it has a public function that calls the delegate once defined.
I simply stripped down the function that defines the library instance and imported only the functionality I needed.
Thanks very much to everyone who was so patient in helping me along. I likely wouldn't have been able to come to a solution without your help.
EDIT: Okay so it wasn't that. It was the location of the LibVLC Plugin Directory. So it was something stupid -.-;

How to hack Win32 API to get character limit to 32K

I want to use prefix \\\?\ as stated in this msdn BCL Team Blog, Long Paths in .NET, Part 2 of 3: Long Path Workarounds [Kim Hamilton]
Even after going through it again and again, I couldn't figure out how to actually use this feature, wondering if anyone can tell me simplest way to use it and how.
Note: I want to use it for creating a directory
You have to use Win32 functions and P/Invoke to achieve this. Use the Unicode version of the API.
Here's what you're looking for:
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CreateDirectory(string lpPathName, IntPtr lpSecurityAttributes);
public static void CreateDir(string dirPath)
{
if (!CreateDirectory(#"\\?\" + dirPath, IntPtr.Zero))
{
throw new IOException("Could not create dir");
}
}
CreateDirectory method
More information about how naming works in Windows

MoveFileWithProgress throws "The system cannot move the file to a different disk drive" – why?

I have:
[SuppressUnmanagedCodeSecurity]
[DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool MoveFileWithProgress(
string lpExistingFileName, string lpNewFileName,
CopyProgressRoutine lpProgressRoutine,
int dwFlags);
public enum MoveFileOptions
{
MOVEFILE_COPY_ALLOWED = 0x2
}
And calling it with:
if (!MoveFileWithProgress(source.FullName, destination.FullName, cpr, (int)options)) {
throw new IOException(new Win32Exception().Message);
}
Where: options is MoveFileOptions.MOVEFILE_COPY_ALLOWED
It works fine when moving in the hard drive. But when I try moving to a Flash-drive, I get: The system cannot move the file to a different disk drive.
Why?
Your DllImport is incorrect. Your function has only 4 parameters, but the real function has 5. Presumably what is happening is that MOVEFILE_COPY_ALLOWED is being passed to lpData and is ignored. The dwFlags parameter is just whatever happens to be sitting on the stack.
Fixing your p/invoke will probably solve the problem. Also, dwFlags should be unsigned.
[DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool MoveFileWithProgress(
string lpExistingFileName,
string lpNewFileName,
CopyProgressRoutine lpProgressRoutine,
IntPtr lpData,
uint dwFlags
);
With this correct you need to decide what to pass to lpData. Since you appear not to be using it at the moment, it doesn't really matter and IntPtr.Zero seems the obvious choice.
From this Microsoft | Technet page, it says:
The file cannot be moved to a different disk drive at the same time you rename it using the Rename command.
Try renaming the file before moving it.
Are you perhaps moving a directory?
According to the documentation for MoveFileWithProgress at MSDN (emphasis added):
When moving a file, lpNewFileName can be on a different file system or volume. If lpNewFileName is on another drive, you must set the MOVEFILE_COPY_ALLOWED flag in dwFlags.
When moving a directory, lpExistingFileName and lpNewFileName must be on the same drive.

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.

Categories