I know that, AvailableFreeSpace is possible to use for local drives such as "C:/", "D:/" etc.
It also works on network drives.
But now my question is:
Is it possible to view the AvailableFreeSpace of a "Folder" on another IP?
I connect to the local drives with this code:
System.IO.DriveInfo _DriveInfo = new DriveInfo(SaveLocation);
When "SaveLocation" is a local drive like "C:\Temp\Folder", than it works fine.
But when there is an IP inside "SaveLocation" it doesn't work. SaveLocation looks like this in that case: "192.168.200.10\c\Data"
This doesn't work and that is the reason for my question. The Exceptionmessage is: {"Object must be a root directory (\"C:\\") or a drive letter (\"C\")."}
I hope you can help me.
As seen in Get available disk free space for a given path on Windows :
Use the winapi function GetDiskFreeSpaceEx to determine free space on a UNC (network) path. For example, create a new VS Project called FreeSpace and paste this as Program.cs:
using System;
using System.Runtime.InteropServices;
namespace FreeSpace
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetDiskFreeSpaceEx(string lpDirectoryName,
out ulong lpFreeBytesAvailable,
out ulong lpTotalNumberOfBytes,
out ulong lpTotalNumberOfFreeBytes);
static void Main(string[] args)
{
ulong FreeBytesAvailable;
ulong TotalNumberOfBytes;
ulong TotalNumberOfFreeBytes;
bool success = GetDiskFreeSpaceEx(#"\\NETSHARE\folder",
out FreeBytesAvailable,
out TotalNumberOfBytes,
out TotalNumberOfFreeBytes);
if (!success)
throw new System.ComponentModel.Win32Exception();
Console.WriteLine("Free Bytes Available: {0,15:D}", FreeBytesAvailable);
Console.WriteLine("Total Number Of Bytes: {0,15:D}", TotalNumberOfBytes);
Console.WriteLine("Total Number Of FreeBytes: {0,15:D}", TotalNumberOfFreeBytes);
Console.ReadKey();
}
}
}
As you can see, this is the exact same code as in the Question linked above, just factored into a class plus the correct using directives to compile without error. All credits go to https://stackoverflow.com/users/995926/rekire
WMI doesn't seem to handle free space on network shares.
But for local disks, Windows Management Interface is the way to go:
https://msdn.microsoft.com/en-us/library/aa394592(v=vs.85).aspx
Related
Is there an analog of the SetFileSecurity function?
I need to re-write some tests from Python and I'm stuck on this part. In Python I can freely edit a DACL with pywin32 (modules with a C++ implementation to work with Windows API).
I can edit any ACE with win32security.
Change owner to Everyone? Okay.
win32security.SetNamedSecurityInfo("somefile.txt", win32security.SE_FILE_OBJECT,
win32security.OWNER_SECURITY_INFORMATION,
win32security.ConvertStringSidToSid("S-1-1-0"))
sd.SetSecurityDescriptorDacl(1, dacl, 0)
win32security.SetFileSecurity(filename, win32security.DACL_SECURITY_INFORMATION, sd)
Remove an inherited ACE? Easy.
sd = win32security.GetFileSecurity("", win32security.DACL_SECURITY_INFORMATION)
dacl = SECURITY_DESCRIPTOR.GetSecurityDescriptorDacl()
dacl.DeleteAce(0)
sd.SetSecurityDescriptorDacl(1, dacl, 0) # may not be necessary
win32security.SetFileSecurity(filename, win32security.DACL_SECURITY_INFORMATION, sd)
And all of those without some special permissions.
But if I want to do something like this in C#. One way I found is changing a security descriptor with pure SDDL, but using System.Security.File.SetAccessControl() with FileSecurity doesn't work if SetSecurityDescriptorSddlForm was called without the SeSecurityPrivilege privilege. Also, even using an administrator token with nearly all privileges, if I want to change something in a "wrong" way (delete some inherited ACEs), the security descriptor doesn't apply. If I try to do something "very wrong", like set the owner to Everyone, an exception will be thrown.
var sddl_everyone_owner = #"O:S-1-1-0G:DUD:P";
var path = #"C:\Users\someuser\test.txt";
FileSecurity fs_edit = new FileSecurity();
fs_edit.SetSecurityDescriptorSddlForm(sddl_everyone_owner);
File.SetAccessControl(path, fs_edit);
Run with administrator token:
Unhandled Exception: System.InvalidOperationException: The security identifier is not
allowed to be the owner of this object.
at System.Security.AccessControl.NativeObjectSecurity.Persist(String name, SafeHandle
handle,
AccessControlSections includeSections, Object exceptionContext)
at System.Security.AccessControl.NativeObjectSecurity.Persist(String name,
AccessControlSections includeSections, Object exceptionContext)
at System.Security.AccessControl.NativeObjectSecurity.Persist(String name,
AccessControlSections includeSections)
at System.Security.AccessControl.FileSystemSecurity.Persist(String fullPath)
at System.IO.File.SetAccessControl(String path, FileSecurity fileSecurity)
at rtest.Program.Main(String[] args) in C:\somepath\Program.cs:line 52
After 11 hours of googling, then trying to write some woking code i have this:
// changes SDDL of file:
using System;
using System.Runtime.InteropServices; // DllImport
public class SomeClass
{
[DllImport("Advapi32.dll", SetLastError = true)]
static extern void SetFileSecurity(string path, int type_of_sd, IntPtr sd);
[DllImport("Advapi32.dll", SetLastError = true)]
static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor(string StringSecurityDescriptor, uint StringSDRevision, out IntPtr SecurityDescriptor, out UIntPtr SecurityDescriptorSize);
private static void Main()
{
string path = #"C:\Some\path\to\file";
string sddl = "D:AI(A;ID;FA;;;S-1-1-0)"; // set only one ACE: inherited full access to Everyone
uint sd_revision = 1; // the only revision of SECURITY_DESCRIPTOR
int DACL_SECURITY_INFORMATION = 4; // can be changed to change other properties, not DACL, relying on SECURITY_DESCRIPTOR_CONTROL parameters https://msdn.microsoft.com/ru-ru/library/windows/desktop/aa379566%28v=vs.85%29.aspx
IntPtr sd_ptr = new IntPtr();
UIntPtr sd_size_ptr = new UIntPtr();
ConvertStringSecurityDescriptorToSecurityDescriptor(sddl, sd_revision, out sd_ptr, out sd_size_ptr);
SetFileSecurity(path, DACL_SECURITY_INFORMATION, sd_ptr);
}
}
This code import functions from Advapi32.dll right to C# code.
Special thanks to PInvoke.net!
Added this code to code samples.
You can get the sddl of a file or folder (symlink/junction) using the powershell command: get-acl -path "c:\some\file_or_folder" | fl.
Piping the output to fl translates the acl to both verbose list and ssdl form.
For the folder "C:\Users\someuser\Application Data" the sddl is
O:SYG:SYD:AI(D;;CC;;;WD)(A;OICIID;FA;;;SY)(A;OICIID;FA;;;BA)(A;OICIID;FA;;;S-1-5-21-2614944367-2017529714-1376493066-1XXX)
or
O:SY Owner:NT Authority/System
G:SY Group:NT Authority/System
D:AI(D;;CC;;;WD)(A;OICIID;FA;;;SY)(A;OICIID;FA;;;BA)(A;OICIID;FA;;;S-1-5-21-2614944367-2017529714-1376493066-1XXX)
"D:" means DACL
"AI" means something like Allow Inheritance
Each substring within parentheses is an Access Control Entry (ACE). Each ACE contains six fields delimited by semicolons that indicate the actual permissions. The first ACE, (D;;CC;;;WD), corresponds to the verbose list line: Everyone Deny ReadData. That is, D means Deny, CC means ReadData, and WD means Everyone. Note that the CC code as shown in Microsoft documentation is synonymous with SDDL_CREATE_CHILD in Sddl.h and the access right value ADS_RIGHT_DS_CREATE_CHILD. How CC is interpreted to mean "ReadData" isn't clear. Note also that specifying "Everyone" is done with the code WD (probably derived from "World"), not with a SID.
For those who wish to delve deeper please see https://learn.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format
https://learn.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-definition-language-for-conditional-aces-
https://learn.microsoft.com/en-us/windows/win32/secauthz/ace-strings
Good luck!
I found a script (http://www.codeproject.com/Articles/28209/Outlook-Drag-and-Drop-in-C) that makes it possible to drag images to a c# application. (especially from outlook) The fileDrop format is used to copy (drag) images from my Hard disk to c# app.
This works well when the images are stored on my hard disk, but when i try to drag the images directly from my storage card (from Camera or smartphone (like a Samsung S3)) it won't work.
These are the drag formats i'm getting from those image(s):
(0): "Shell IDList Array"
(1): "FileContents"
(2): "FileGroupDescriptorW"
(3): "WPD Storage Attributes"
(4): "Preferred DropEffect"
(5): "WPD NSE"
(6): "WPD NSE PnPDevicePath"
(7): "WPD NSE StoragePUID"
(8): "UsingDefaultDragImage"
(9): "DragImageBits"
(10): "DragContext"
(11): "DragSourceHelperFlags"
(12): "InShellDragLoop"
(13): "IsShowingLayered"
(14): "DragWindow"
(15): "IsComputingImage"
(16): "DataObjectAttributes"
(17): "DisableDragText"
(18): "IsShowingText"
(19): "DropDescription"
(20): "ComputedDragImage"
(21): "Logical Performed DropEffect"
(22): "Performed DropEffect"
(23): "Paste Succeeded"
When i try to access the 'FileGroupDescriptorW' i'm receiving an Illegal access violation error. Also, 'FileGroupDescriptor' seems to be missing here?
Could anyone help me resolve this issue? I searched this site and Google, but didn't find anything useful.
The solution was posted by John Schroedl and was hidden in the many reactions on the Topic.
These two 'fixes' fixed my problem:
http://www.codeproject.com/Articles/28209/Outlook-Drag-and-Drop-in-C?msg=3535951#xx3535951xx
OLD C#:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public sealed class FILEGROUPDESCRIPTORA
{
public uint cItems;
public FILEDESCRIPTORA[] fgd;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public sealed class FILEGROUPDESCRIPTORW
{
public uint cItems;
public FILEDESCRIPTORW[] fgd;
}
FIXED C#:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public sealed class FILEGROUPDESCRIPTORA
{
public uint cItems;
public FILEDESCRIPTORA fgd;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public sealed class FILEGROUPDESCRIPTORW
{
public uint cItems;
public FILEDESCRIPTORW fgd;
}
And this fix: http://www.codeproject.com/Articles/28209/Outlook-Drag-and-Drop-in-C?msg=3551197#xx3551197xx
Old:
case "FileContents":
//override the default handling of FileContents which returns the
//contents of the first file as a memory stream and instead return
//a array of MemoryStreams containing the data to each file dropped
//get the array of filenames which lets us know how many file contents exist
string[] fileContentNames = (string[])this.GetData("FileGroupDescriptor");
Fix:
case "FileContents":
//override the default handling of FileContents which returns the
//contents of the first file as a memory stream and instead return
//a array of MemoryStreams containing the data to each file dropped
//
// FILECONTENTS requires a companion FILEGROUPDESCRIPTOR to be
// available so we bail out if we don't find one in the data object.
string fgdFormatName;
if (GetDataPresent("FileGroupDescriptorW"))
fgdFormatName = "FileGroupDescriptorW";
else if (GetDataPresent("FileGroupDescriptor"))
fgdFormatName = "FileGroupDescriptor";
else
return null;
//get the array of filenames which lets us know how many file contents exist
string[] fileContentNames = (string[])this.GetData(fgdFormatName);
In case anyone needs it...
When I was searching on Google I found a useful class which let us change the icon of any .exe file using the following line of code :
WindowsFormsApplication1.IconInjector.InjectIcon("myfile.exe", "myicon.ico", 200, 1);
Where 200 and 1 are respectively icon GroupID and icon BaseID which I can determine using Resource Hacker. In this case the file's icon changes successfully without corrupting the file.
So i planned to use this class on my program which is a SFX / Software protector, the output file always hasn't an icon, all what I can see on Resource hacker is the below :
i can't see icon group id nor the base id, anyway, (I don't know what to put instead of 200 and 1 in this case) So I tried to change the icon using the same line of code mentioned above, I used the following line of code (same as above):
WindowsFormsApplication1.IconInjector.InjectIcon("myfile.exe", "myicon.ico", 200, 1);
The file icon was successfully changed but the file doesn't work anymore!
When I tried to reopen the file using ResourceHacker, I found the below:
It seems that the icon resources were successfully added, but i can't figure out why the file doesn't work anymore, it seems that is corrupted.
Any help would be appreciated.
Note : I tried using this class with unprotected file and it works like a charm!
The class I am using is the below:
// IconInjector.cs
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace WindowsFormsApplication1
{
/// <summary>
/// IconInjectorクラスの定義
/// </summary>
public class IconInjector
{
[DllImport("kernel32.dll", SetLastError = true)]
//static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, ushort wLanguage, IntPtr lpData, uint cbData);
static extern int UpdateResource(IntPtr hUpdate, uint lpType, uint lpName, ushort wLanguage, byte[] lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr BeginUpdateResource(string pFileName,
[MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
public static void InjectIcon(string execFileName, string iconFileName, uint iconGroupID, uint iconBaseID)
{
const uint RT_ICON = 3;
const uint RT_GROUP_ICON = 14;
// アイコンファイルの読み込み
IconFile iconFile = new IconFile();
iconFile.Load(iconFileName);
// リソースの更新開始
IntPtr hUpdate = BeginUpdateResource(execFileName, false);
Debug.Assert(hUpdate != IntPtr.Zero);
// RT_GROUP_ICON 書き込み
byte[] data = iconFile.CreateIconGroupData(iconBaseID);
UpdateResource(hUpdate, RT_GROUP_ICON, iconGroupID, 0, data, (uint)data.Length);
// RT_ICON書き込み
for (int i = 0; i < iconFile.GetImageCount(); i++)
{
byte[] image = iconFile.GetImageData(i);
UpdateResource(hUpdate, RT_ICON, (uint)(iconBaseID + i), 0, image, (uint)image.Length);
}
// リソースの更新終了
EndUpdateResource(hUpdate, false);
}
}
}
Any help or suggestion on adding the icon to the protected file without corrupting it?
It sounds like the protection application is verifying that the contents of the file haven't been tampered with. Injecting an icon is definitely a form of tampering, and unless the protection software is updated to ignore it, it will always fail. Alternatively if you own the protection software you could update it to not strip the icons.
I just experienced the same issue with a 7zip Self-Extractor exe.
Updating the icon of the 7zS.sfx (instead of the exe) before creating the Self-Extractor exe does the trick and the exe is not corrupted.
Your application's icon can be added to this executable with a tool like Resource Hacker.
and visit http://georezo.net/jparis/MI_Enviro/Icons/adding_w_RH.htm
How to get path of Users folder from windows service on MS Vista?
I think about path of C:\Users directory, but it may be different location depend on system localization.
Take a look at the Environment.SpecialFolder Enumeration, e.g.
Environment.GetFolderPath(Environment.SpecialFolder.CommonDesktopDirectory);
Adjust for the special folder you want. However, in reading another post found here, it looks like you may need to do a little manipulation of the string if you want exactly c:\users instead of c:\users\public, for example.
System.Environment.SpecialFolder will give you access to all these folders that you want, such as My Documents, Etc..
If you use the UserProfile SpecialFolder, that should give you the path to your profile under Users.
string userPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
The best way as #Neil pointed out is to use SHGetKnownFolderPath() with the FOLDERID_UserProfiles. However, c# doesn't have that. But, it's not that hard to invoke it:
using System;
using System.Runtime.InteropServices;
namespace SOExample
{
public class Main
{
[DllImport("shell32.dll")]
static extern int SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags, IntPtr hToken, out IntPtr pszPath);
private static string getUserProfilesPath()
{
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx#folderid_userprofiles
Guid UserProfilesGuid = new Guid("0762D272-C50A-4BB0-A382-697DCD729B80");
IntPtr pPath;
SHGetKnownFolderPath(UserProfilesGuid, 0, IntPtr.Zero, out pPath);
string path = System.Runtime.InteropServices.Marshal.PtrToStringUni(pPath);
System.Runtime.InteropServices.Marshal.FreeCoTaskMem(pPath);
return path;
}
static void Main(string[] args)
{
string path = getUserProfilesPath(); // C:\Users
}
}
}
I can't see that function exposed to .NET, but in C(++) it would be
SHGetKnownFolderPath(FOLDERID_UserProfiles, ...)
System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal)
How to find available COM ports in my PC? I am using framework v1.1. Is it possible to find all COM ports? If possible, help me solve the problem.
Framework v1.1 AFAIK doesn't allow you to do this.
In 2.0 there is a static function
SerialPort.GetPortNames()
http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.getportnames.aspx
As others suggested, you can use WMI. You can find a sample in CodeProject
try
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\WMI",
"SELECT * FROM MSSerial_PortName");
foreach (ManagementObject queryObj in searcher.Get())
{
Console.WriteLine("-----------------------------------");
Console.WriteLine("MSSerial_PortName instance");
Console.WriteLine("-----------------------------------");
Console.WriteLine("InstanceName: {0}", queryObj["InstanceName"]);
Console.WriteLine("-----------------------------------");
Console.WriteLine("MSSerial_PortName instance");
Console.WriteLine("-----------------------------------");
Console.WriteLine("PortName: {0}", queryObj["PortName"]);
//If the serial port's instance name contains USB
//it must be a USB to serial device
if (queryObj["InstanceName"].ToString().Contains("USB"))
{
Console.WriteLine(queryObj["PortName"] + "
is a USB to SERIAL adapter/converter");
}
}
}
catch (ManagementException e)
{
Console.WriteLine("An error occurred while querying for WMI data: " + e.Message);
}
The available serial ports can also be found at the values at the HKEY_LOCAL_MACHINE\hardware\devicemap\serialcomm key in the registry.
How about asking a straight question from operating system:
using System;
using System.Collections.Generic;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
public class MyClass
{
private const uint GENERIC_ALL = 0x10000000;
private const uint GENERIC_READ = 0x80000000;
private const uint GENERIC_WRITE = 0x40000000;
private const uint GENERIC_EXECUTE = 0x20000000;
private const int OPEN_EXISTING = 3;
public const int INVALID_HANDLE_VALUE = -1;
public static void Main()
{
for (int i = 1; i <= 32; i++)
Console.WriteLine ("Port {0}: {1}", i, PortExists (i));
}
private static bool PortExists (int number) {
SafeFileHandle h = CreateFile (#"\\.\COM" + number.ToString (), GENERIC_READ + GENERIC_WRITE,
0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
bool portExists = !h.IsInvalid;
if (portExists)
h.Close ();
return portExists;
}
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern SafeFileHandle CreateFile (string lpFileName, System.UInt32 dwDesiredAccess,
System.UInt32 dwShareMode, IntPtr pSecurityAttributes, System.UInt32 dwCreationDisposition,
System.UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile);
}
WMI contains a lot of hardware information. Query for instances of Win32_SerialPort.
(OTOH I can't recall how much WMI query support was in .NET 1.1.)
There is no support for SerialPort communication in .net v1.1. The most common solution for this was to use the MSCOMMCTL active X control from a VB6.0 installation (import into your .net project as a COM component from the add reference dialog box).
In later versions the Serial Port support is available through the System.IO.Ports name space. Also please note there is no API which will get you the list of free ports.
You can get a list of all the port names and then try opening a connection. An exception occurs if the port is already in use.
Since you are using .net 1.1 one option is to use the AxMSCommLib control.
Here is a web page that assisted me in starting to use AxMSCommLib control. There is even a FindDevicePort() method listed that can be easily modified.
I have since switched to System.IO.Ports which appears to be much more robust.
http://www.devhood.com/tutorials/tutorial_details.aspx?tutorial_id=320
Thanks
Joe
Use QueryDosDevice API function. This is a VB6 snippet:
ReDim vRet(0 To 255)
sBuffer = String(100000, 1)
Call QueryDosDevice(0, sBuffer, Len(sBuffer))
sBuffer = Chr$(0) & sBuffer
For lIdx = 1 To 255
If InStr(1, sBuffer, Chr$(0) & "COM" & lIdx & Chr$(0), vbTextCompare) > 0 Then
vRet(lCount) = "COM" & lIdx
lCount = lCount + 1
End If
Next
Maybe you will find this useful?
I am showing you a simple way to check all the COM ports in you PC. To get started follow these steps:
Create a WinForms application in Visual Studio.
Darg and drop a comboBox in your form and name it comboBoxCOMPORT
Copy the following code and paste after the public Form1() method (autogenerated).
private void Form1_Load(object sender, EventArgs e)
{
string[] ports = SerialPort.GetPortNames();
comboBoxCOMPORT.Items.AddRange(ports);
}
Run the app and click on drop down arrow on the comboBox to reveal all the available COM PORTS.
The above method works for Edgeport USB-to-serial converters as well as virtual ports. I implemented this in my project and works smoothly. Let me know if I can provide any further assistance.