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
Related
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);
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 -.-;
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.
HI all,
I would like to call from my C# code, unamanaged library functions like presented below. There are two options and the both works. In this moment "Beep" function is simple and have no input/output parameters, pointers, references... I am wondering in more complex cases what would be adventages and disadvantage of both approches ?
Thanks,
Milan.
[DllImport("kernel32.dll")]
public static extern bool Beep(uint iFreq, uint iDuration);
public void TestBeep()
{
Beep(300, 3000);
}
internal delegate bool DelegBeep(uint iFreq, uint iDuration);
[DllImport("kernel32.dll")]
internal static extern IntPtr LoadLibrary(String dllname);
[DllImport("kernel32.dll")]
internal static extern IntPtr GetProcAddress(IntPtr hModule, String procName);
public void BeepIt()
{
IntPtr kernel32 = LoadLibrary("Kernel32.dll");
IntPtr procBeep = GetProcAddress(kernel32, "Beep");
DelegBeep delegBeep = Marshal.GetDelegateForFunctionPointer(procBeep, typeof(DelegBeep)) as DelegBeep;
delegBeep(50, 1000);//Hz,ms
}
Your second one is much more complicated than the first but achieves the same thing in this case.
If the name of the DLL and the name of the function are known at compile time, then stick with the first approach. If you don't know the name of the DLL and/or function until run time then the LoadLibary/GetProcAddress approach is your only option.
The P/Invoke marshaller finds an entrypoint in a DLL by using LoadLibrary() and GetProcAddress(). And knows how to convert a C# declaration to the equivalent of a delegate declaration.
Doing this yourself has no advantage beyond maybe a wee bit of efficiency. Which you'd better measure, it is no slamdunk.
I have a window to use for editing. The editor should load a dll (which I have full control of) in response to the user's selection to know how to display the information visually.
(They're dll's, as a user will not necessarily want or need every single display model, and also allow new ones to be added without messing around with the main project)
They will all simply be stored in a subdirectory (for now anyway)
I'm pretty sure I can enumerate the available dlls but I need to do 2 more things that I'm not sure on
1) Some way to get metadata from\on the dll, so I can build the lists of possible display selections...
2) Load the selected dll, and unload it as necessary
Any suggestions would be greatly appreciated.
If you are using raw dll's and not .NET assemblies then here are some handy P/Invokes for you:
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern void SetDllDirectory(string lpPathName);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
privatestatic extern int GetModuleFileName(IntPtr module, [Out] StringBuilder fileName, int size);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static bool FreeLibrary(IntPtr module);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
Note that SetDllDirectory may need some protection as it is not available on all versions of windows (Windows 2000, in particular doesn't have it).
And in use:
SetDllDirectory(candidateFolder);
IntPtr dllHandle = LoadLibrary(dllName);
if (dllHandle != IntPtr.Zero)
{
_dllHandle = dllHandle;
_location = candidateFolder;
_fullPath = Path.Combine(candidateFolder, dllName);
IntPtr p = GetProcAddress(_dllHandle, procName);
if (p == IntPtr.Zero)
throw new ArgumentException("procName");
SomeDelegateType d = (SomeDelegateType)Marshal.GetDelegateForFunctionPointer(p, typeof(SomeDelegateType));
d(/* args */);
}
otherwise, you will be using Assembly methods. Looking at assembly level attributes or object level attributes is a good way to get extra information, although if what you want is a plug-in system, you should use a plug-in system, like the Managed Add-In Framework at CodePlex. See also this SO question and answer.
Take a look at the Castle Windsor framework. It is designed to handle all of your requirements including DLL unloading. It's also free and open source.
I don't know if changing how your program works is an option, but, you could use dependency injection for this, as long as they adhere to a certain interface.
The user selects, you dynamically set class to be loaded, and then just get an instance of the class.
I am not dealing with the unloading, I am just thinking about how you could possibly get classes, and since plinth already gave links to the functions for actually handling the dll, I think I will just end here.
For a native module, the simplest way to get "metadata" would be to define some C-exported (non-name-mangled) functions that return the information you want. At their simplest, these would return pointers to static data within the modules, e.g.:
extern "C" const char* GetModuleDescription();
...
const char* GetModuleDescription() { return "Dummy Module"; }
You would then load each ".dll" file in the directory using LoadLibrary, load and call your known exports from it using GetProcAddress. If you can't load a file or find the exports, then it's not a valid plugin module, so skip it.
Once you're done with a module, you can call FreeLibrary. Windows will then unload the module from your address space.
OK, I;ve figured out I need to use a second AppDomain, load the dll into that, and then I can unload the AppDomain as required.
string SignalSystemDLLPath = AppDomain.CurrentDomain.BaseDirectory + MyApp.Properties.Resources.SystemModuleFolder;
AppDomainSetup info = new AppDomainSetup();
info.ApplicationBase = DLLPath;
DLLDomain = AppDomain.CreateDomain("EditorDomain", null, info);
DLLPath is set to the subdir that holds the dll's.
I then foreach on all the dll's to get the AssemblyName, then later
I use
DLLDomain.Load(SelectedAssemblyName)
to load the DLL. I keep getting FileNotFound exceptions though.
After much googling I've decided its to much work at the moment, and I can refactor it later If I really need to do it...
Thank you for your replies though!
Found out how to do this very easy using MEF, simply use a DirectoryCatalog pointed at your plugin dir, and as long as you have matching [Export]s and [Import]s it works great.