I was looking for a short way to eject USB-devices via C#-code, so I coded a little class myself, yet it simply doesn't work. Since there's no popup that says "Lock success!" I assume that the problem relies within the "LockVolume"-function, but I don't know where.
Does anybody see the mistake I made?
class USBEject
{
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr SecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile
);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped
);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
byte[] lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped
);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
private IntPtr handle = IntPtr.Zero;
const int GENERIC_READ = 0x80000000;
const int GENERIC_WRITE = 0x40000000;
const int FILE_SHARE_READ = 0x1;
const int FILE_SHARE_WRITE = 0x2;
const int FSCTL_LOCK_VOLUME = 0x00090018;
const int FSCTL_DISMOUNT_VOLUME = 0x00090020;
const int IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808;
const int IOCTL_STORAGE_MEDIA_REMOVAL = 0x002D4804;
/// <summary>
/// Constructor for the USBEject class
/// </summary>
/// <param name="driveLetter">This should be the drive letter. Format: F:/, C:/..</param>
public USBEject(string driveLetter)
{
string filename = #"\\.\" + driveLetter[0] + ":";
handle = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, 0x3, 0, IntPtr.Zero);
}
public bool Eject()
{
if (LockVolume(handle) && DismountVolume(handle))
{
PreventRemovalOfVolume(handle, false);
return AutoEjectVolume(handle);
}
return false;
}
private bool LockVolume(IntPtr handle)
{
uint byteReturned;
for (int i = 0; i < 10; i++)
{
if (DeviceIoControl(handle, FSCTL_LOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero))
{
System.Windows.Forms.MessageBox.Show("Lock success!");
return true;
}
Thread.Sleep(500);
}
return false;
}
private bool PreventRemovalOfVolume(IntPtr handle, bool prevent)
{
byte[] buf = new byte[1];
uint retVal;
buf[0] = (prevent) ? (byte)1 : (byte)0;
return DeviceIoControl(handle, IOCTL_STORAGE_MEDIA_REMOVAL, buf, 1, IntPtr.Zero, 0, out retVal, IntPtr.Zero);
}
private bool DismountVolume(IntPtr handle)
{
uint byteReturned;
return DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
}
private bool AutoEjectVolume(IntPtr handle)
{
uint byteReturned;
return DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
}
private bool CloseVolume(IntPtr handle)
{
return CloseHandle(handle);
}
}
Changed just a little bit your code and it goes as follows:
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr SecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile
);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped
);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
byte[] lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped
);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
private IntPtr handle = IntPtr.Zero;
const uint GENERIC_READ = 0x80000000;
const uint GENERIC_WRITE = 0x40000000;
const int FILE_SHARE_READ = 0x1;
const int FILE_SHARE_WRITE = 0x2;
const int FSCTL_LOCK_VOLUME = 0x00090018;
const int FSCTL_DISMOUNT_VOLUME = 0x00090020;
const int IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808;
const int IOCTL_STORAGE_MEDIA_REMOVAL = 0x002D4804;
/// <summary>
/// Constructor for the USBEject class
/// </summary>
/// <param name="driveLetter">This should be the drive letter. Format: F:/, C:/..</param>
public IntPtr USBEject(string driveLetter)
{
string filename = #"\\.\" + driveLetter[0] + ":";
return CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, 0x3, 0, IntPtr.Zero);
}
public bool Eject(IntPtr handle)
{
bool result = false;
if (LockVolume(handle) && DismountVolume(handle))
{
PreventRemovalOfVolume(handle, false);
result = AutoEjectVolume(handle);
}
CloseHandle(handle);
return result;
}
private bool LockVolume(IntPtr handle)
{
uint byteReturned;
for (int i = 0; i < 10; i++)
{
if (DeviceIoControl(handle, FSCTL_LOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero))
{
System.Windows.Forms.MessageBox.Show("Lock success!");
return true;
}
Thread.Sleep(500);
}
return false;
}
private bool PreventRemovalOfVolume(IntPtr handle, bool prevent)
{
byte[] buf = new byte[1];
uint retVal;
buf[0] = (prevent) ? (byte)1 : (byte)0;
return DeviceIoControl(handle, IOCTL_STORAGE_MEDIA_REMOVAL, buf, 1, IntPtr.Zero, 0, out retVal, IntPtr.Zero);
}
private bool DismountVolume(IntPtr handle)
{
uint byteReturned;
return DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
}
private bool AutoEjectVolume(IntPtr handle)
{
uint byteReturned;
return DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);
}
private bool CloseVolume(IntPtr handle)
{
return CloseHandle(handle);
}
So you can use it in two ways:
handle = USBEject("D:");
Eject(handle);
or directly:
Eject(USBEject("D:"));
It works for me on my Windows 10 machine (preview 14291)
Found the answer for my issue by using some of Roger Deep's code for the CreateFile call.
My code to remove a USB drive inside WPF Window:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
EjectDrive('K');
}
void EjectDrive(char driveLetter)
{
string path = #"\\.\" + driveLetter + #":";
IntPtr handle = CreateFile(path, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, 0x3, 0, IntPtr.Zero);
if ((long)handle == -1)
{
MessageBox.Show("Unable to open drive " + driveLetter);
return;
}
int dummy = 0;
DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0,
IntPtr.Zero, 0, ref dummy, IntPtr.Zero);
CloseHandle(handle);
MessageBox.Show("OK to remove drive.");
}
[DllImport("kernel32", SetLastError = true)]
private static extern IntPtr CreateFile
(string filename, uint desiredAccess,
uint shareMode, IntPtr securityAttributes,
int creationDisposition, int flagsAndAttributes,
IntPtr templateFile);
[DllImport("kernel32")]
private static extern int DeviceIoControl
(IntPtr deviceHandle, uint ioControlCode,
IntPtr inBuffer, int inBufferSize,
IntPtr outBuffer, int outBufferSize,
ref int bytesReturned, IntPtr overlapped);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
Here's some code that I converted from a powershell script. You need to run with admin privileges and It works to "unmount" the USB drive. However, when you try to unplug the USB drive and plug it in again, it doesn't show up as a drive letter. (To get around that you need to type "WindowsKey-X" and select Disk-Manager to reassign the drive less to the USB device. (If anybody knows how to fix that problem please post to commits.) Here's the Code:
// Right click Project and Add Reference to System.Management.dll
using System.Management;
string mq = "SELECT * FROM Win32_Volume Where Name = 'E:\\'";
ManagementObjectSearcher ms = new ManagementObjectSearcher(mq);
foreach (ManagementObject mo in ms.Get())
{
mo["DriveLetter"] = null;
mo.Put();
ManagementBaseObject inParams = mo.GetMethodParameters("Dismount");
inParams["Force"] = false;
inParams["Permanent"] = false;
mo.InvokeMethod("Dismount", inParams, null);
}
Note that the powershell script also has the same problem of reattaching the USB device after ejecting. Here's the powershell script for your reference:
$vol = get-wmiobject -Class Win32_Volume |
where{$_.Name -eq 'E:\'}
$vol.DriveLetter = $null
$vol.Put()
$vol.Dismount($false, $false)
Here's a class that I just wrote to Manage Mounting and Unmounting of Removable USB Drives using WMI:
using System;
using System.IO;
using System.Text;
using System.Windows;
using System.Management; //<-- right-click on project and add reference
using System.Collections.Generic;
using System.Text.RegularExpressions;
// This Class implements Mount/Unmount for USB Removable Drives
// in a way similar to "Disk Manager" in the Control Panel.
//
// Currently, It doesn't implement "Eject" like when you right
// right-click on the USB icon on lower right of screen.
// The "Unmount" is similar to "Eject" except it dosn't
// cleanup the registry so that the USB drive can be automatically
// recognized again without manually mounting it from "Disk Manager"
// If somebody knows how to fix this class to gain this function...
// please post it to their thread. Thanks.
namespace WPM {
public struct UsbDriveItem_t {
public int Index;
public string DeviceId;
public char DriveLetter;
public string Label;
public override string ToString() {
if (Index < 0)
return "<none>";
else
return String.Format("{0}: {1}", DriveLetter, Label);
}
};
delegate void UsbEvent();
class UsbDriveRemovable {
public static int Unmount(char DriveLetter) {
bool success = ValidateAdmin("UsbDriveRemovable.Unmount()");
if (!success) return -1;
string Name = "'" + DriveLetter + ":\\\\'";
string mq = "SELECT * FROM Win32_Volume Where Name = " + Name;
ManagementObjectSearcher ms = new ManagementObjectSearcher(mq);
ManagementObjectCollection mc = ms.Get();
foreach (ManagementObject mo in mc) {
var DriveLetterI = mo["DriveLetter"].ToString();
mo["DriveLetter"] = null;
mo.Put();
ManagementBaseObject inParams = mo.GetMethodParameters("Dismount");
inParams["Force"] = false;
inParams["Permanent"] = false;
ManagementBaseObject outParams = mo.InvokeMethod("Dismount", inParams, null);
string rc = outParams["ReturnValue"].ToString();
mo.Dispose();
}
mc.Dispose();
ms.Dispose();
return 0;
}
public static int Mount(string DeviceId, char Letter = '?') {
bool success = ValidateAdmin("UsbDriveRemovable.Mount()");
if (!success) return -1;
if (Letter == '?' || Letter == '#') {
GetFirstUnsedLetter(out Letter);
}
string FixDeviceId = Regex.Replace(DeviceId, #"\\", #"\\");
string mq = "SELECT * FROM Win32_Volume WHERE DeviceId = '"
+ FixDeviceId
+ "'";
ManagementObjectSearcher ms = new ManagementObjectSearcher(mq);
ManagementObjectCollection mc = ms.Get();
foreach (ManagementObject mo in mc) {
ManagementBaseObject inParams = mo.GetMethodParameters("AddMountPoint");
inParams["Directory"] = Letter + ":\\";
ManagementBaseObject outParams = mo.InvokeMethod("AddMountPoint", inParams, null);
string rc = outParams["ReturnValue"].ToString();
mo.Dispose();
}
mc.Dispose();
ms.Dispose();
return 0;
}
/*List<UsbDriveItem_t>*/
public static int ListDrives(ref List<UsbDriveItem_t> DriveList) {
DriveList.Clear();
string mq = "SELECT * FROM Win32_Volume Where DriveType = '2'";
ManagementObjectSearcher ms = new ManagementObjectSearcher(mq);
ManagementObjectCollection mc = ms.Get();
int count = 0;
foreach (ManagementObject mo in mc) {
UsbDriveItem_t item = new UsbDriveItem_t();
item.Index = count;
item.Label = (mo["Label"] == null) ? "<none>" : mo["Label"].ToString();
item.DriveLetter = (mo["DriveLetter"] == null) ? '#' : mo["DriveLetter"].ToString()[0];
item.DeviceId = (mo["DeviceId"] == null) ? "<none>" : mo["DeviceId"].ToString();
DriveList.Add(item);
mo.Dispose();
}
count++;
mc.Dispose();
ms.Dispose();
return 0;
}
public static void MountItem(UsbDriveItem_t DriveItem) {
char DriveLetter = DriveItem.DriveLetter;
string DriveLabel = DriveItem.Label;
string DeviceId = DriveItem.DeviceId;
// Mount Drive if its not already Mounted
if (DriveLetter == '#') {
UsbDriveRemovable.GetFirstUnsedLetter(out DriveLetter);
UsbDriveRemovable.Mount(DeviceId, DriveLetter);
}
return;
}
public static void UnmountItem(UsbDriveItem_t DriveItem) {
char DriveLetter = DriveItem.DriveLetter;
UsbDriveRemovable.Unmount(DriveLetter);
return;
}
public static int GetFirstUnsedLetter(out char Letter) {
bool[] alphabet = new bool[26];
for (int i=0; i < 26; i++) {
alphabet[i] = false;
}
string mq = "SELECT * FROM Win32_Volume";
ManagementObjectSearcher ms = new ManagementObjectSearcher(mq);
ManagementObjectCollection mc = ms.Get();
foreach (ManagementObject mo in mc) {
if (mo["DriveLetter"] != null) {
char cc = mo["DriveLetter"].ToString()[0];
int ci = char.ToUpper(cc) - 65;
alphabet[ci] = true;
}
mo.Dispose();
}
mc.Dispose();
ms.Dispose();
int found = -1;
for (int i=3; i < 26; i++) {
if (alphabet[i] == false) {
found = i;
break;
}
}
if (found >= 0) {
Letter = (char)(found + 65);
return 0;
}
else {
Letter = '?';
return -1;
}
}
public static object
RegisterInsertEvent(UsbEvent InsertEvent) {
var insertQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
var insertWatcher = new ManagementEventWatcher(insertQuery);
insertWatcher.EventArrived += delegate(object sender, EventArrivedEventArgs e) {
// string driveName = e.NewEvent.Properties["DriveName"].Value.ToString();
Action action = delegate {
InsertEvent();
};
Application.Current.Dispatcher.BeginInvoke(action);
};
insertWatcher.Start();
return (object)insertWatcher;
}
public static object RegisterRemoveEvent(UsbEvent RemoveEvent) {
var removeQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
var removeWatcher = new ManagementEventWatcher(removeQuery);
removeWatcher.EventArrived += delegate(object sender, EventArrivedEventArgs e) {
// string driveName = e.NewEvent.Properties["DriveName"].Value.ToString();
Action action = delegate {
RemoveEvent();
};
Application.Current.Dispatcher.BeginInvoke(action);
};
removeWatcher.Start();
return (object)removeWatcher;
}
// Mount all UsbRemovable Drives that are not currently mounted
public static int MountAll() {
List<UsbDriveItem_t> DriveList = new List<UsbDriveItem_t>();
ListDrives(ref DriveList);
foreach (UsbDriveItem_t item in DriveList) {
if (item.DriveLetter == '?') {
Mount(item.DeviceId);
}
}
return 0;
}
// Unmount all UsbRemovable Drives
public static int UnmountAll() {
List<UsbDriveItem_t> DriveList = new List<UsbDriveItem_t>();
ListDrives(ref DriveList);
foreach (UsbDriveItem_t item in DriveList) {
if (item.DriveLetter != '?') {
Unmount(item.DriveLetter);
}
}
return 0;
}
public static bool IsAdministrator()
{
var id = System.Security.Principal.WindowsIdentity.GetCurrent();
var prin = new System.Security.Principal.WindowsPrincipal(id);
return prin.IsInRole(
System.Security.Principal.WindowsBuiltInRole.Administrator);
}
public static bool ValidateAdmin(string CalledFrom = null) {
if (CalledFrom == null) {
CalledFrom = "";
}
if (!IsAdministrator()) {
string msg = "Please rerun this application with admin privileges.\r\n\r\n"
+ "Access denied to call " + CalledFrom + "\r\n\r\n";
MessageBox.Show(msg, "ERROR");
return false;
}
return true;
}
public static void StartExplorer(char DriveLetter)
{
var proc1 = new System.Diagnostics.Process();
proc1.StartInfo.FileName = #"C:\\Windows\\System32\\explorer.exe";
proc1.StartInfo.Arguments = DriveLetter.ToString();
proc1.StartInfo.CreateNoWindow = true;
proc1.StartInfo.UseShellExecute = false;
proc1.StartInfo.RedirectStandardOutput = true;
proc1.StartInfo.RedirectStandardError = true;
proc1.Start();
proc1.WaitForExit();
string proc1out = proc1.StandardOutput.ReadToEnd();
string proc1err = proc1.StandardError.ReadToEnd();
//if (proc1.ExitCode != 0) {
// string msg = proc1out + "\r\n\r\n" + proc1err;
// MessageBox.Show(msg, "Error: Mountvol /R");
//}
proc1.Close();
}
} //class
} //namespace
/* DOESN'T WORK WELL...
// Kludge to get USB Drive to be recognized again
void UsbCleanup() {
var proc1 = new System.Diagnostics.Process();
proc1.StartInfo.FileName = #"C:\\Windows\\System32\\mountvol.exe";
proc1.StartInfo.Arguments = #"/R";
proc1.StartInfo.CreateNoWindow = true;
proc1.StartInfo.UseShellExecute = false;
proc1.StartInfo.RedirectStandardOutput = true;
proc1.StartInfo.RedirectStandardError = true;
proc1.Start();
proc1.WaitForExit();
string proc1out = proc1.StandardOutput.ReadToEnd();
string proc1err = proc1.StandardError.ReadToEnd();
if (proc1.ExitCode != 0) {
string msg = proc1out + "\r\n\r\n" + proc1err;
MessageBox.Show(msg, "Error: Mountvol /R");
}
proc1.Close();
var proc2 = new System.Diagnostics.Process();
proc2.StartInfo.FileName = #"C:\\Windows\\System32\\mountvol.exe";
proc2.StartInfo.Arguments = #"/E";
proc2.StartInfo.CreateNoWindow = true;
proc2.StartInfo.UseShellExecute = false;
proc2.StartInfo.RedirectStandardOutput = true;
proc2.StartInfo.RedirectStandardError = true;
proc2.Start();
proc2.WaitForExit();
string proc2out = proc2.StandardOutput.ReadToEnd();
string proc2err = proc2.StandardError.ReadToEnd();
if (proc2.ExitCode != 0) {
string msg = proc1out + "\r\n\r\n" + proc1err;
MessageBox.Show(msg, "Error: Mountvol /E");
}
proc2.Close();
return;
}
*/
You could convert the following PowerShell into C#:
$Eject = New-Object -comObject Shell.Application
$Eject.NameSpace(17).ParseName($usbDrvLetter+“:”).InvokeVerb(“Eject”)
Related
I am developing an automation interface program and I looking to enhance capability with a machine software which uses a COPYDATA API aimed at C++. The goal is to control and report status of the machine through my own software.
The method uses pointers and memory allocation which I have not had any experience with thus far.
I have looked at a number of other sources, such as this with no luck at the moment. I have tried the following code to try and run a program on the machine software.
class Program
{
[DllImport("User32.dll", SetLastError = true, EntryPoint = "FindWindow")]
public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);
[DllImport("User32.dll", SetLastError = true, EntryPoint = "SendMessage")]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData; // Any value the sender chooses. Perhaps its main window handle?
public int cbData; // The count of bytes in the message.
public IntPtr lpData; // The address of the message.
}
const int WM_COPYDATA = 0x004A;
const int EXTERNAL_CD_COMMAND_RUN_ASYNC = 0x8001;
static void Main(string[] args)
{
Console.WriteLine("{0} bit process.", (IntPtr.Size == 4) ? "32" : "64");
Console.Write("Press ENTER to run test.");
Console.ReadLine();
IntPtr hwnd = FindWindow(null, "InSpecAppFrame");
Console.WriteLine("hwnd = {0:X}", hwnd.ToInt64());
var cds = new COPYDATASTRUCT();
byte[] buff = Encoding.ASCII.GetBytes("C:\\Users\\Desktop\\COPYDATATEST.iwp");
cds.dwData = (IntPtr)EXTERNAL_CD_COMMAND_RUN_ASYNC;
cds.lpData = Marshal.AllocHGlobal(buff.Length);
Marshal.Copy(buff, 0, cds.lpData, buff.Length);
cds.cbData = buff.Length;
var ret = SendMessage(hwnd, WM_COPYDATA, 0, ref cds);
Console.WriteLine("Return value is {0}", ret);
Marshal.FreeHGlobal(cds.lpData);
Console.ReadLine();
}
}
Running this code returns 0 for both hwnd and ret and the machine software does not react.
Sending a command is the first step, the next will be to try and get a response so I can monitor machine statuses etc.
As a sidenote to what Alejandro wrote (and that I think is correct), you can simplify a little the code, removing a copy of the data. You can directly "pin" your byte[]. It is important that you remember to "unpin" it (for this reason the try/finally block)
There is another potential problem in your code (a problem that I saw only on a second pass of the code): C strings must be \0 terminated (so "Foo" must be "Foo\0"). Your Encoding.ASCII doesn't guarantee a \0 termination. The classical way to do it is to make the byte[] "a little larger" than necessary. I've done the changes necessary.
[DllImport("User32.dll", SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData; // Any value the sender chooses. Perhaps its main window handle?
public int cbData; // The count of bytes in the message.
public IntPtr lpData; // The address of the message.
}
[StructLayout(LayoutKind.Sequential)]
public struct ExternalGetPositionType
{
public double X;
public double Y;
public double Z;
public double W;
}
const int WM_COPYDATA = 0x004A;
const int EXTERNAL_CD_COMMAND_RUN_ASYNC = 0x8001;
const int EXTERNAL_CD_GET_POSITION_PCS = 0x8011;
const int EXTERNAL_CD_GET_POSITION_MCS = 0x8012;
static void Main(string[] args)
{
Console.WriteLine("{0} bit process.", (IntPtr.Size == 4) ? "32" : "64");
Console.Write("Press ENTER to run test.");
Console.ReadLine();
IntPtr hwnd = FindWindow(null, "Form1");
Console.WriteLine("hwnd = {0:X}", hwnd.ToInt64());
if (hwnd == IntPtr.Zero)
{
throw new Exception("hwnd not found");
}
IntPtr ret = RunAsync(hwnd, #"C:\Users\Desktop\COPYDATATEST.iwp");
Console.WriteLine($"Return value for EXTERNAL_CD_COMMAND_RUN_ASYNC is {ret}");
ret = GetPosition(hwnd, true, new ExternalGetPositionType { X = 1, Y = 2, Z = 3, W = 4 });
Console.WriteLine($"Return value for EXTERNAL_CD_GET_POSITION_PCS is {ret}");
ret = GetPosition(hwnd, false, new ExternalGetPositionType { X = 10, Y = 20, Z = 30, W = 40 });
Console.WriteLine($"Return value for EXTERNAL_CD_GET_POSITION_MCS is {ret}");
Console.ReadLine();
}
public static IntPtr RunAsync(IntPtr hwnd, string str)
{
// We have to add a \0 terminator, so len + 1 / len + 2 for Unicode
int len = Encoding.Default.GetByteCount(str);
var buff = new byte[len + 1]; // len + 2 for Unicode
Encoding.Default.GetBytes(str, 0, str.Length, buff, 0);
IntPtr ret;
GCHandle h = default(GCHandle);
try
{
h = GCHandle.Alloc(buff, GCHandleType.Pinned);
var cds = new COPYDATASTRUCT();
cds.dwData = (IntPtr)EXTERNAL_CD_COMMAND_RUN_ASYNC;
cds.lpData = h.AddrOfPinnedObject();
cds.cbData = buff.Length;
ret = SendMessage(hwnd, WM_COPYDATA, 0, ref cds);
}
finally
{
if (h.IsAllocated)
{
h.Free();
}
}
return ret;
}
public static IntPtr GetPosition(IntPtr hwnd, bool pcs, ExternalGetPositionType position)
{
// We cheat here... It is much easier to pin an array than to copy around a struct
var positions = new[]
{
position
};
IntPtr ret;
GCHandle h = default(GCHandle);
try
{
h = GCHandle.Alloc(positions, GCHandleType.Pinned);
var cds = new COPYDATASTRUCT();
cds.dwData = pcs ? (IntPtr)EXTERNAL_CD_GET_POSITION_PCS : (IntPtr)EXTERNAL_CD_GET_POSITION_MCS;
cds.lpData = h.AddrOfPinnedObject();
cds.cbData = Marshal.SizeOf<ExternalGetPositionType>();
ret = SendMessage(hwnd, WM_COPYDATA, 0, ref cds);
}
finally
{
if (h.IsAllocated)
{
h.Free();
}
}
return ret;
}
Note even that instead of ASCII you can use the Default encoding, that is a little better.
If you want to receive the messages, in your Winforms do:
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_COPYDATA)
{
COPYDATASTRUCT cds = Marshal.PtrToStructure<COPYDATASTRUCT>(m.LParam);
if (cds.dwData == (IntPtr)EXTERNAL_CD_COMMAND_RUN_ASYNC)
{
string str = Marshal.PtrToStringAnsi(cds.lpData);
Debug.WriteLine($"EXTERNAL_CD_COMMAND_RUN_ASYNC: {str}");
m.Result = (IntPtr)100; // If you want to return a value
}
else if (cds.dwData == (IntPtr)EXTERNAL_CD_GET_POSITION_PCS)
{
if (cds.cbData >= Marshal.SizeOf<ExternalGetPositionType>())
{
var position = Marshal.PtrToStructure<ExternalGetPositionType>(cds.lpData);
Debug.WriteLine($"EXTERNAL_CD_GET_POSITION_PCS: X = {position.X}, Y = {position.Y}, Z = {position.Z}, W = {position.W}");
m.Result = (IntPtr)200;
}
else
{
m.Result = (IntPtr)0;
}
}
else if (cds.dwData == (IntPtr)EXTERNAL_CD_GET_POSITION_MCS)
{
if (cds.cbData >= Marshal.SizeOf<ExternalGetPositionType>())
{
var position = Marshal.PtrToStructure<ExternalGetPositionType>(cds.lpData);
Debug.WriteLine($"EXTERNAL_CD_GET_POSITION_MCS: X = {position.X}, Y = {position.Y}, Z = {position.Z}, W = {position.W}");
m.Result = (IntPtr)300;
}
else
{
m.Result = (IntPtr)0;
}
}
return;
}
base.WndProc(ref m);
}
Note that if you control both the sender AND the receiver, it is better much better to use Unicode for the string parameter. You'll have to modify both the sender and the receiver: Encoding.Unicode.GetByteCount/Encoding.Unicode.GetBytes, the +2 instead of +1 and Marshal.PtrToStringUni.
I'm trying to read a string "845120" from a process memory but I have some trouble...
I know "845120" is a numeric value, but in some cases it can be alphanumeric, that's why it's a string and not a 4 byte int.
Here is my Memory class, where I have all functions that deal with memory:
private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead);
public static IntPtr FindDMAAddy(IntPtr hProc, IntPtr ptr, int[] offsets)
{
var buffer = new byte[IntPtr.Size];
foreach (int i in offsets)
{
ReadProcessMemory(hProc, ptr, buffer, buffer.Length, out var read);
ptr = (IntPtr.Size == 4)
? IntPtr.Add(new IntPtr(BitConverter.ToInt32(buffer, 0)), i)
: ptr = IntPtr.Add(new IntPtr(BitConverter.ToInt64(buffer, 0)), i);
}
return ptr;
}
public static IntPtr GetModuleBaseAddress(Process proc, string modName)
{
IntPtr addr = IntPtr.Zero;
foreach (ProcessModule m in proc.Modules)
{
if (m.ModuleName == modName)
{
addr = m.BaseAddress;
break;
}
}
return addr;
}
public static string ReadStringUntilNULL(string EXENAME, int Address)
{
string value = "";
bool endOfString = false;
int counter = 0;
while (!endOfString)
{
if (ReadInt8(EXENAME, Address + counter) > (byte)0)
{
value += (char)ReadInt8(EXENAME, Address + counter);
}
else
{
return value;
}
counter++;
}
return value;
}
And here's the code that I'm using to invoke that functions:
Process process = null;
while(process == null)
{
process = Process.GetProcessesByName("client_dx").FirstOrDefault();
}
var hProc = Memory.OpenProcess(0x00000010, false, process.Id);
var modBase = Memory.GetModuleBaseAddress(process, "client_dx.exe");
var addr = Memory.FindDMAAddy(hProc, (IntPtr)(modBase + 0x003393AC), new int[] { 0x30, 0x374, 0x2C, 0x0, 0x14, 0x48, 0x10 });
var acc = Memory.ReadStringUntilNULL("client_dx.exe", addr);
Debug.WriteLine(acc);
It's working perfectly until this line:
var acc = Memory.ReadStringUntilNULL("client_dx.exe", addr);
So var addr have the correct address but var acc it's not getting the expected results.
Here I'm getting this error: cannot convert from 'System.IntPtr' to 'int'
Ok, so it expects an integer where I'm giving a pointer... so I tested with ToInt32()
var acc = Memory.ReadStringUntilNULL("client_dx.exe", addr.ToInt32());
The addr.ToInt32() operation returns 262959880 and as far as I know that's not even an address
I'm getting an empty string, the ReadStringUntilNULL function from Memory class it's only looping once..
Values are: addr 0x0fac7308 System.IntPtr and acc "" string
How can I read that string from memory? Or how can I pass the parameter correctly?
I finally wrote a class that lets me read strings until null:
public class NewMem
{
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(int hProcess, int lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead);
public Process Process { get; set; }
public static IntPtr GetModuleBaseAddress(Process proc, string modName)
{
IntPtr addr = IntPtr.Zero;
foreach (ProcessModule m in proc.Modules)
{
if (m.ModuleName == modName)
{
addr = m.BaseAddress;
break;
}
}
return addr;
}
public static IntPtr FindDMAAddy(IntPtr hProc, IntPtr ptr, int[] offsets)
{
var buffer = new byte[IntPtr.Size];
foreach (int i in offsets)
{
ReadProcessMemory(hProc, ptr, buffer, buffer.Length, out var read);
ptr = (IntPtr.Size == 4)
? IntPtr.Add(new IntPtr(BitConverter.ToInt32(buffer, 0)), i)
: ptr = IntPtr.Add(new IntPtr(BitConverter.ToInt64(buffer, 0)), i);
}
return ptr;
}
public string ReadStringASCII(IntPtr address)
{
var myString = "";
for (int i = 1; i < 50; i++)
{
var bytes = ReadMemory(address, i);
if (bytes[(i-1)] == 0)
{
return myString;
}
myString = Encoding.ASCII.GetString(bytes);
}
return myString;
}
public byte[] ReadMemory(IntPtr address, int size)
{
var buffer = new byte[size];
var bytesRead = 0;
ReadProcessMemory((int)Process.Handle, (int)address, buffer, buffer.Length, ref bytesRead);
return buffer;
}
}
This is my code:
NewMem MClass = new NewMem();
var client = Process.GetProcessesByName("client_dx").FirstOrDefault();
MClass.Process = client;
// Get handle to process
var hProc = NewMem.OpenProcess(0x00000010, false, client.Id);
// Get base module
var modBase = NewMem.GetModuleBaseAddress(client, "client_dx.exe");
// Get relative base address
var vBasePointer = NewMem.FindDMAAddy(hProc, (IntPtr)(modBase + 0x55F870), new int[] { 0 });
// Get string
if (vBasePointer != IntPtr.Zero)
{
var vNameAddress = vBasePointer + 0x20;
var vName = MClass.ReadStringASCII(vNameAddress);
}
It's stopping reading when finds a '0', but you can always set up some exceptions or tricks, I didn't find a cleaner way to do this but it's working :)
I've a problem trying to call SetupDiGetDeviceInterfaceDetail from C#. It always returns 1784 error code ("The supplied user buffer is not valid for the requested operation"). This is my C# code:
Guid GUID_DEVINTERFACE_DFU = new Guid(0x3fe809ab, 0xfb91, 0x4cb5, 0xa6, 0x43, 0x69, 0x67, 0x0d, 0x52,0x36,0x6e);
Guid classGuid = GUID_DEVINTERFACE_DFU;
IntPtr hDevInfo = Win32.SetupDiGetClassDevs(ref classGuid, IntPtr.Zero, IntPtr.Zero, Win32.DIGCF_DEVICEINTERFACE | Win32.DIGCF_PRESENT);
if (hDevInfo.ToInt32() == Win32.INVALID_HANDLE_VALUE)
{
Console.WriteLine("read hardware information error");
}
else
{
SP_DEVINFO_DATA devInfoData = new SP_DEVINFO_DATA();
devInfoData.cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
devInfoData.classGuid = Guid.Empty;
devInfoData.devInst = 0;
devInfoData.reserved = IntPtr.Zero;
bool result = Win32.SetupDiEnumDeviceInfo(hDevInfo, i, devInfoData);
if (false == result)
{
int error = Marshal.GetLastWin32Error();
if (error != Win32.ERROR_NO_MORE_ITEMS)
throw new Win32Exception(error);
}
SP_DEVICE_INTERFACE_DATA ifData = new SP_DEVICE_INTERFACE_DATA();
ifData.cbSize = (uint)Marshal.SizeOf(ifData);
ifData.Flags = 0;
ifData.InterfaceClassGuid = Guid.Empty;
ifData.Reserved = IntPtr.Zero;
bool result2 = Win32.SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref classGuid, i, ifData);
if(result2 == false)
{
int error = Marshal.GetLastWin32Error();
if (error != Win32.ERROR_NO_MORE_ITEMS)
throw new Win32Exception(error);
}
uint needed;
// This returns: needed=160, result3=false and error=122 ("The data area passed to a system call is too small")
bool result3 = Win32.SetupDiGetDeviceInterfaceDetail(hDevInfo, ifData, null, 0, out needed, null);
if(result3 == false)
{
int error = Marshal.GetLastWin32Error();
}
IntPtr detailDataBuffer = IntPtr.Zero;
SP_DEVICE_INTERFACE_DETAIL_DATA ifDetailsData = new SP_DEVICE_INTERFACE_DETAIL_DATA();
ifDetailsData.devicePath = new byte[needed - 4];
ifDetailsData.cbSize = (uint)Marshal.SizeOf(ifDetailsData);
uint nBytes = needed;
// This returns always: error = 1784
bool result4 = Win32.SetupDiGetDeviceInterfaceDetail(hDevInfo, ifData, ifDetailsData, nBytes, out needed, null);
if (result4 == false)
{
int error = Marshal.GetLastWin32Error();
if (error != Win32.ERROR_NO_MORE_ITEMS)
throw new Win32Exception(error);
}
}
Classe Win32:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace USB_test
{
[StructLayout(LayoutKind.Sequential)]
public class SP_DEVINFO_DATA
{
public uint cbSize;
public Guid classGuid;
public uint devInst;
public IntPtr reserved;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class SP_DEVICE_INTERFACE_DETAIL_DATA
{
public uint cbSize;
public byte[] devicePath;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public class SP_DEVICE_INTERFACE_DATA
{
public uint cbSize;
public Guid InterfaceClassGuid;
public uint Flags;
public IntPtr Reserved;
}
public class Win32
{
public static uint ANYSIZE_ARRAY = 1000;
[DllImport("setupapi.dll", SetLastError = true)]
public static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, IntPtr Enumerator, IntPtr hwndParent, uint Flags);
[DllImport("setupapi.dll", SetLastError = true)]
public static extern Boolean SetupDiEnumDeviceInfo(IntPtr lpInfoSet, UInt32 dwIndex, SP_DEVINFO_DATA devInfoData);
[DllImport(#"setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr hDevInfo, IntPtr devInfo, ref Guid interfaceClassGuid, uint memberIndex, SP_DEVICE_INTERFACE_DATA deviceInterfaceData);
[DllImport(#"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr hDevInfo, SP_DEVICE_INTERFACE_DATA deviceInterfaceData, SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData, uint deviceInterfaceDetailDataSize, out uint requiredSize, SP_DEVINFO_DATA deviceInfoData);
public const int DIGCF_PRESENT = 0x02;
public const int DIGCF_DEVICEINTERFACE = 0x10;
public const int SPDRP_DEVICEDESC = (0x00000000);
public const long ERROR_NO_MORE_ITEMS = 259L;
}
}
If it can help someone, this is the solution:
IntPtr detailDataBuffer = Marshal.AllocHGlobal((int)needed);
Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8);
uint nBytes = needed;
bool result4 = Win32.SetupDiGetDeviceInterfaceDetail(hDevInfo, ifData, detailDataBuffer, nBytes, out needed, null);
if (result4 == false)
{
int error = Marshal.GetLastWin32Error();
if (error != Win32.ERROR_NO_MORE_ITEMS)
throw new Win32Exception(error);
}
IntPtr pDevicePathName = new IntPtr(detailDataBuffer.ToInt32() + 4);
String devicePathName = Marshal.PtrToStringAuto(pDevicePathName);
Additional Note: If running on a 64-bit machine, or forced 64-bit mode, the above line for the pointer to pDevicePathName would reference a 64-bit pointer, not 32
IntPtr pDevicePathName = new IntPtr(detailDataBuffer.ToInt64() + 8);
The struct is a variable sized structure which cannot be marshalled automatically. You'll need to do so yourself.
You'll need to remove the SP_DEVICE_INTERFACE_DETAIL_DATA type. It's no use to you. Change the declaration of SetupDiGetDeviceInterfaceDetail to:
[DllImport(#"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean SetupDiGetDeviceInterfaceDetail(
IntPtr hDevInfo,
SP_DEVICE_INTERFACE_DATA deviceInterfaceData,
IntPtr deviceInterfaceDetailData,
uint deviceInterfaceDetailDataSize,
out uint requiredSize,
SP_DEVINFO_DATA deviceInfoData
);
Pass IntPtr.Zero in the first call to SetupDiGetDeviceInterfaceDetail. Then allocate a buffer of the required size by calling Marshal.AllocHGlobal. Then write the size into the first 4 bytes of that buffer. Then call SetupDiGetDeviceInterfaceDetail again.
Something along these lines:
bool result3 = Win32.SetupDiGetDeviceInterfaceDetail(hDevInfo, ifData, IntPtr.Zero, 0,
out needed, null);
if(!result3)
{
int error = Marshal.GetLastWin32Error();
}
// expect that result3 is false and that error is ERROR_INSUFFICIENT_BUFFER = 122,
// and needed is the required size
IntPtr DeviceInterfaceDetailData = Marshal.AllocHGlobal((int)needed);
try
{
uint size = needed;
Marshal.WriteInt32(DeviceInterfaceDetailData, (int)size);
bool result4 = Win32.SetupDiGetDeviceInterfaceDetail(hDevInfo, ifData,
DeviceInterfaceDetailData, size, out needed, null);
if(!result4)
{
int error = Marshal.GetLastWin32Error();
}
// do whatever you need with DeviceInterfaceDetailData
}
finally
{
Marshal.FreeHGlobal(DeviceInterfaceDetailData);
}
For me, the answer of David Hoffmann doesn't work. But he inspired me to this solution:
IntPtr buffer = Marshal.AllocHGlobal((int)requiredSize);
int cbSize = sizeof(DWORD) + 2 * sizeof(CHAR); // cbSize + empty DevicePath
Marshal.WriteInt32(buffer, cbSize);
deviceInterfaceInfoData.cbSize = (DWORD)Marshal.SizeOf(deviceInterfaceInfoData);
if (!SetupDiGetDeviceInterfaceDetail(
deviceInfoSet,
ref deviceInterfaceData,
buffer,
requiredSize,
out requiredSize,
ref deviceInterfaceInfoData))
throw new Win32Exception(error);
int devicePathSize = (int)requiredSize - sizeof(DWORD); // cbSize
char[] devicePathChars = new char[devicePathSize / sizeof(char)];
int offset = sizeof(DWORD); // cbSize
Marshal.Copy(IntPtr.Add(buffer, offset), devicePathChars, 0, devicePathChars.Length);
string devicePath = new(devicePathChars, 0, devicePathChars.Length - 1); // Remove NULL terminator
Marshal.FreeHGlobal(buffer);
I am applying a proxy for my application's WebBrowser control using WinInet and the good thing about that method is that it doesn't affect the system's proxy and only applies the proxy to my application. However it only works with proxies that have no username and password.
Here is the code
private const int INTERNET_OPEN_TYPE_DIRECT = 1;
private const int INTERNET_OPEN_TYPE_PRECONFIG = 0;
public static string ApplicationName;
[DllImport("user32.dll", SetLastError = true)]
public static IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static bool ShowWindow(IntPtr hwnd, User32.WindowShowStyle nCmdShow);
[DllImport("user32.dll")]
public static bool EnableWindow(IntPtr hwnd, bool enabled);
[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static IntPtr InternetOpen(string lpszAgent, int dwAccessType, string lpszProxyName, string lpszProxyBypass, int dwFlags);
[DllImport("wininet.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static bool InternetCloseHandle(IntPtr hInternet);
[DllImport("wininet.dll", CharSet = CharSet.Ansi, SetLastError = true)]
private static bool InternetSetOption(IntPtr hInternet, User32.InternetOption dwOption, IntPtr lpBuffer, int lpdwBufferLength);
[DllImport("wininet.dll", EntryPoint = "InternetQueryOption", CharSet = CharSet.Ansi, SetLastError = true)]
private static bool InternetQueryOptionList(IntPtr handle, User32.InternetOption optionFlag, ref User32.InternetPerConnOptionList optionList, ref int size);
public static bool SetConnectionProxy(string proxyServer)
{
IntPtr hInternet = User32.InternetOpen(User32.ApplicationName, 1, (string) null, (string) null, 0);
User32.InternetPerConnOption[] internetPerConnOptionArray = new User32.InternetPerConnOption[2]
{
new User32.InternetPerConnOption()
{
dwOption = 1,
Value = {
dwValue = 2
}
},
new User32.InternetPerConnOption()
{
dwOption = 2,
Value = {
pszValue = Marshal.StringToHGlobalAnsi(proxyServer)
}
}
};
IntPtr ptr1 = Marshal.AllocCoTaskMem(Marshal.SizeOf((object) internetPerConnOptionArray[0]) + Marshal.SizeOf((object) internetPerConnOptionArray[1]));
IntPtr ptr2 = ptr1;
foreach (User32.InternetPerConnOption internetPerConnOption in internetPerConnOptionArray)
{
Marshal.StructureToPtr((object) internetPerConnOption, ptr2, false);
ptr2 = (IntPtr) ((int) ptr2 + Marshal.SizeOf((object) internetPerConnOption));
}
User32.InternetPerConnOptionList perConnOptionList = new User32.InternetPerConnOptionList()
{
pOptions = ptr1
};
perConnOptionList.Size = Marshal.SizeOf((object) perConnOptionList);
perConnOptionList.Connection = IntPtr.Zero;
perConnOptionList.OptionCount = internetPerConnOptionArray.Length;
perConnOptionList.OptionError = 0;
int num1 = Marshal.SizeOf((object) perConnOptionList);
IntPtr num2 = Marshal.AllocCoTaskMem(num1);
Marshal.StructureToPtr((object) perConnOptionList, num2, true);
bool flag = User32.InternetSetOption(hInternet, User32.InternetOption.InternetOptionPerConnectionOption, num2, num1);
Marshal.FreeCoTaskMem(ptr1);
Marshal.FreeCoTaskMem(num2);
User32.InternetCloseHandle(hInternet);
if (!flag)
throw new ApplicationException(" Set Internet Option Failed!");
else
return true;
}
private static User32.InternetPerConnOptionList GetSystemProxy()
{
User32.InternetPerConnOption[] internetPerConnOptionArray = new User32.InternetPerConnOption[3]
{
new User32.InternetPerConnOption()
{
dwOption = 1
},
new User32.InternetPerConnOption()
{
dwOption = 2
},
new User32.InternetPerConnOption()
{
dwOption = 3
}
};
IntPtr num = Marshal.AllocCoTaskMem(Marshal.SizeOf((object) internetPerConnOptionArray[0]) + Marshal.SizeOf((object) internetPerConnOptionArray[1]) + Marshal.SizeOf((object) internetPerConnOptionArray[2]));
IntPtr ptr = num;
foreach (User32.InternetPerConnOption internetPerConnOption in internetPerConnOptionArray)
{
Marshal.StructureToPtr((object) internetPerConnOption, ptr, false);
ptr = (IntPtr) ((int) ptr + Marshal.SizeOf((object) internetPerConnOption));
}
User32.InternetPerConnOptionList optionList = new User32.InternetPerConnOptionList()
{
pOptions = num
};
optionList.Size = Marshal.SizeOf((object) optionList);
optionList.Connection = IntPtr.Zero;
optionList.OptionCount = internetPerConnOptionArray.Length;
optionList.OptionError = 0;
int size = Marshal.SizeOf((object) optionList);
if (!User32.InternetQueryOptionList(IntPtr.Zero, User32.InternetOption.InternetOptionPerConnectionOption, ref optionList, ref size))
throw new ApplicationException(" Set Internet Option Failed! ");
else
return optionList;
}
public static bool RestoreSystemProxy()
{
IntPtr hInternet = User32.InternetOpen(User32.ApplicationName, 1, (string) null, (string) null, 0);
User32.InternetPerConnOptionList systemProxy = User32.GetSystemProxy();
int num1 = Marshal.SizeOf((object) systemProxy);
IntPtr num2 = Marshal.AllocCoTaskMem(num1);
Marshal.StructureToPtr((object) systemProxy, num2, true);
bool flag = User32.InternetSetOption(hInternet, User32.InternetOption.InternetOptionPerConnectionOption, num2, num1);
Marshal.FreeCoTaskMem(systemProxy.pOptions);
Marshal.FreeCoTaskMem(num2);
if (!flag)
throw new ApplicationException(" Set Internet Option Failed! ");
User32.InternetSetOption(hInternet, User32.InternetOption.InternetOptionSettingsChanged, IntPtr.Zero, 0);
User32.InternetSetOption(hInternet, User32.InternetOption.InternetOptionRefresh, IntPtr.Zero, 0);
User32.InternetCloseHandle(hInternet);
return true;
}
public enum WindowShowStyle : uint
{
Hide = 0U,
ShowNormal = 1U,
ShowMinimized = 2U,
Maximize = 3U,
ShowMaximized = 3U,
ShowNormalNoActivate = 4U,
Show = 5U,
Minimize = 6U,
ShowMinNoActivate = 7U,
ShowNoActivate = 8U,
Restore = 9U,
ShowDefault = 10U,
ForceMinimized = 11U,
}
private enum InternetOption
{
InternetOptionRefresh = 37,
InternetOptionSettingsChanged = 39,
InternetOptionPerConnectionOption = 75,
}
private enum InternetOptionPerConnFlags
{
ProxyTypeDirect = 1,
ProxyTypeProxy = 2,
ProxyTypeAutoProxyUrl = 4,
ProxyTypeAutoDetect = 8,
}
private struct InternetPerConnOption
{
public int dwOption;
public User32.InternetPerConnOptionOptionUnion Value;
}
private struct InternetPerConnOptionList
{
public int Size;
public IntPtr Connection;
public int OptionCount;
public int OptionError;
public IntPtr pOptions;
}
[StructLayout(LayoutKind.Explicit)]
private struct InternetPerConnOptionOptionUnion
{
[FieldOffset(0)]
public int dwValue;
[FieldOffset(0)]
public IntPtr pszValue;
[FieldOffset(0)]
private readonly System.Runtime.InteropServices.ComTypes.FILETIME ftValue;
}
private enum InternetPerConnOptionEnum
{
InternetPerConnFlags = 1,
InternetPerConnProxyServer = 2,
InternetPerConnProxyBypass = 3,
InternetPerConnAutoconfigUrl = 4,
InternetPerConnAutodiscoveryFlags = 5,
InternetPerConnAutoconfigSecondaryUrl = 6,
InternetPerConnAutoconfigReloadDelayMins = 7,
InternetPerConnAutoconfigLastDetectTime = 8,
InternetPerConnAutoconfigLastDetectUrl = 9,
InternetPerConnFlagsUi = 10,
}
Question: How could i use that code to apply a proxy with username and password ?
Notes:
I know that there is a couple of similar questions here but i cannot
get a good answer out of them.
I heard that this can be achieved using InternetSetOption however
i can't find how to implement that cause i don't have enough
knowledge about windoes functions etc...
The proper options to set the proxy credentials in WinINET are INTERNET_OPTION_PROXY_USERNAME and INTERNET_OPTION_PROXY_PASSWORD as shown at http://msdn.microsoft.com/en-us/library/windows/desktop/aa385328(v=vs.85).aspx
You may need to implement IAuthenticate instead, since the other calls are really intended for WinINET handles, which aren't exposed when you're using the Web Browser control.
I have a problem that I am hoping someone can help with. I have a c# application that needs to get the File Owner information from a file that resides on a Linux server. The .Net System.IO GetFileInfo throws an exception and the WMI calls fail. I know there is the PInvoke method GetFileOwner however the example on pinvoke.net is not complete and does not compile. Does anyone have a good complete example or a link to find this information?
This is a .Net c# 3.5 windows application and does have permissions to access the file, however I want to get the owner information before it does the rest of the processing.
Thanks
Below is the code sample I used. It works in my application and in my environment. Should work in others. Sorry this was not posted sooner, was new to StackOverFlow. I hope this posts properly.
public class GetUserInfo{
private const int NAME_SIZE = 0x40;
// Methods
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern bool ConvertSidToStringSid(IntPtr Sid, ref IntPtr StringSid);
public string ConvertSidToStringSidNT(IntPtr Sid)
{
string ans = string.Empty;
if (IsValidSid(Sid))
{
ans = "S-1-";
SID_IDENTIFIER_AUTHORITY psia = (SID_IDENTIFIER_AUTHORITY) Marshal.PtrToStructure(GetSidIdentifierAuthority(Sid), typeof(SID_IDENTIFIER_AUTHORITY));
int num = Marshal.ReadInt16(GetSidSubAuthorityCount(Sid));
if ((psia.Value[0] != 0) & (psia.Value[1] != 0))
{
ans = ((ans + Conversion.Hex(psia.Value[0]) + Conversion.Hex(psia.Value[1]).PadLeft(2, '0')) + Conversion.Hex(psia.Value[2]).PadLeft(2, '0') + Conversion.Hex(psia.Value[3]).PadLeft(2, '0')) + Conversion.Hex(psia.Value[4]).PadLeft(2, '0') + Conversion.Hex(psia.Value[5]).PadLeft(2, '0');
}
else
{
long top = psia.Value[5];
top += psia.Value[4] * 0x100;
top += (psia.Value[3] * 0x100) * 0x100;
ans = ans + ((top + (((psia.Value[2] * 0x100) * 0x100) * 0x100))).ToString();
}
int VB$t_i4$L0 = num - 1;
for (int i = 0; i <= VB$t_i4$L0; i++)
{
ans = ans + "-" + Marshal.ReadInt32(GetSidSubAuthority(Sid, i)).ToString();
}
}
return ans;
}
public string GetFileOwner(string Path)
{
string MachineName;
IntPtr OwnerSid;
int peUse;
IntPtr SD;
string UserName;
IntPtr VB$t_struct$N0;
SE_OBJECT_TYPE ObjectType = SE_OBJECT_TYPE.SE_FILE_OBJECT;
if (GetNamedSecurityInfo(ref Path, ObjectType, SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION, ref OwnerSid, ref VB$t_struct$N0, ref VB$t_struct$N0, ref VB$t_struct$N0, ref SD) != 0)
{
return "Error";
}
Marshal.FreeHGlobal(SD);
if (Path.StartsWith(#"\\"))
{
MachineName = Path.Split(new char[] { '\\' })[2];
}
else
{
MachineName = "";
}
int name_len = 0x40;
int domain_len = 0x40;
string name = Strings.Space(name_len);
string domain_name = Strings.Space(domain_len);
if (!LookupAccountSid(ref MachineName, OwnerSid, ref name, ref name_len, ref domain_name, ref domain_len, ref peUse))
{
string SidString;
if (Marshal.GetLastWin32Error() != 0x534)
{
return "Error";
}
if (Environment.Version.Major == 4)
{
SidString = this.ConvertSidToStringSidNT(OwnerSid);
}
else
{
IntPtr StringPtr;
if (!ConvertSidToStringSid(OwnerSid, ref StringPtr))
{
return "Error";
}
SidString = Marshal.PtrToStringAuto(StringPtr);
Marshal.FreeHGlobal(StringPtr);
}
domain_len = 0;
name = SidString;
name_len = Strings.Len(name);
}
if (domain_len > 0)
{
UserName = Strings.Left(name, name_len);
}
else
{
UserName = Strings.Left(name, name_len);
}
return UserName;
}
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern int GetNamedSecurityInfo([MarshalAs(UnmanagedType.VBByRefStr)] ref string pObjectName, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, ref IntPtr ppsidOwner, ref IntPtr ppsidGroup, ref IntPtr ppDacl, ref IntPtr ppSacl, ref IntPtr ppSecurityDescriptor);
[DllImport("advapi32.dll", CharSet=CharSet.Ansi, SetLastError=true, ExactSpelling=true)]
private static extern IntPtr GetSidIdentifierAuthority(IntPtr pSid);
[DllImport("advapi32.dll", CharSet=CharSet.Ansi, SetLastError=true, ExactSpelling=true)]
private static extern IntPtr GetSidSubAuthority(IntPtr pSid, int nSubAuthority);
[DllImport("advapi32.dll", CharSet=CharSet.Ansi, SetLastError=true, ExactSpelling=true)]
private static extern IntPtr GetSidSubAuthorityCount(IntPtr pSid);
[DllImport("advapi32.dll", CharSet=CharSet.Ansi, SetLastError=true, ExactSpelling=true)]
private static extern bool IsValidSid(IntPtr pSid);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern bool LookupAccountSid([MarshalAs(UnmanagedType.VBByRefStr)] ref string lpSystemName, IntPtr lpSid, [MarshalAs(UnmanagedType.VBByRefStr)] ref string lpName, ref int cchName, [MarshalAs(UnmanagedType.VBByRefStr)] ref string lpReferenceDomainName, ref int cchReferencedDomainName, ref int peUse);
// Nested Types
private enum SE_OBJECT_TYPE
{
SE_UNKNOWN_OBJECT_TYPE,
SE_FILE_OBJECT,
SE_SERVICE,
SE_PRINTER,
SE_REGISTRY_KEY,
SE_LMSHARE,
SE_KERNEL_OBJECT,
SE_WINDOW_OBJECT,
SE_DS_OBJECT,
SE_DS_OBJECT_ALL,
SE_PROVIDER_DEFINED_OBJECT,
SE_WMIGUID_OBJECT,
SE_REGISTRY_WOW64_32
}
private enum SECURITY_INFORMATION
{
DACL_SECURITY_INFORMATION = 4,
GROUP_SECURITY_INFORMATION = 2,
OWNER_SECURITY_INFORMATION = 1,
PROTECTED_DACL_SECURITY_INFORMATION = 0x20,
PROTECTED_SACL_SECURITY_INFORMATION = 0x10,
SACL_SECURITY_INFORMATION = 8,
UNPROTECTED_DACL_SECURITY_INFORMATION = 0x80,
UNPROTECTED_SACL_SECURITY_INFORMATION = 0x40
}
[StructLayout(LayoutKind.Sequential)]
private struct SID_IDENTIFIER_AUTHORITY
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=6)]
public byte[] Value;
} }