|
|
Hi everyone, I am currently looking for a solution to prevent a user from opening the CD drive during a cruicial burning process. I think I'm close, like real close but the last hurdle is keeping me back.
I've found the right api for the job, but it's unmanaged in C++ and porting to C# is real tricky. So essentially that is the answer I am after.
I've figured out that at some point my solution involves: IOCTL_STORAGE_EJECT_CONTROL and PREVENT_MEDIA_REMOVAL, being used with the function DeviceIoControl()
I have these snippets which I have edited into my code.
[DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
ref long InBuffer,
int nInBufferSize,
ref long OutBuffer,
int nOutBufferSize,
ref int pBytesReturned,
[In] ref NativeOverlapped lpOverlapped);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr CreateFile(
string fileName,
[MarshalAs(UnmanagedType.U4)] FileAccess fileAccess,
[MarshalAs(UnmanagedType.U4)] FileShare fileShare,
IntPtr securityAttributes,
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
int flags,
IntPtr template);
private void SomethingMethod()
{
IntPtr tHandle = CreateFile(@"\\.\" + destVolume, FileAccess.Read, FileShare.ReadWrite, IntPtr.Zero,
FileMode.Open, 0, IntPtr.Zero);
Bool success = DeviceIoControl(something, IOCTL_STORAGE_EJECT_CONTROL, something, something,
something, and so on);
}
I'm sure most of you will recognise that I am importing the dll libraries but the issue I am having is the Structure or Enums (I'm not quite which which is which) as I believe that IOCTL_STORAGE_EJECT_CONTROL and PREVENT_MEDIA_REMOVAL are stored as 'structs' somewhere.
So in brief, all I need to know are what parameters I need to pass to DeviceIoControl to stop the drive from ejecting.
Many Thanks.
modified on Friday, August 28, 2009 4:18 AM
|
|
|
|
|
Hi,
all I have is some comments:
1. please use PRE tags to show readable code snippets.
2. don't confuse native and managed types, they sometimes have a different length (e.g. long and char)
3. the details of IOCTL_STORAGE_EJECT_CONTROL must be available on the web; make google your friend!
4. CreateFile at the device level is bound to fail (access denied) for regular users on Windows Vista and above.
5. I'm rather convinced I can always open the optical drive, that is a hardware function, something software might trigger, but AFAIK not prevent.
|
|
|
|
|
This shouldn't be too tricky. I found this VB code[^], which should be a good start and faily easy to 'translate' to C#.
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
But there's this leeeetle hole on a CD/DVD drive; if you insert an unfolded paper clip you can eject the drive no matter what.
So you're after an unachievable goal; I doubt it's worth the trouble. Just put up a "Please don't eject the disc until this process is complete" message, with a progress bar.
|
|
|
|
|
By that logic software should never do anything to prevent the user from closing it instantly while it's writing a file or the like; afterall even if you use the malware coders guide to protect your process from being killed, the user could yank the power/battery no matter what you do. Personally I want my software to ignore a close message until they finish writing any files, etc (or the attempt times out over the lan).
The latest nation. Procrastination.
|
|
|
|
|
Not at all (even were it relevent); an application can account for its own behaviour -- if it's writing it can wait until it's done, or prompt for abort.
|
|
|
|
|
While the OP hasn't stated exactly what the critical activity the CD drive is doing, during a CD-R burning session ejecting the disk and terminating an application in mid file write only differ in that the ejected CD is ruined representing a financial loss as opposed to potentially recoverable data corruption.
The latest nation. Procrastination.
|
|
|
|
|
But given that the app will handle the case where it is asked to exit during the activity, I don't see the relevence.
I believe the OP is concerned about the user pressing the eject button, ejecting from Explorer, or perhaps another app accessing the drive.
It appears that blocking those is achievable, and perhaps enough for the OP.
My point (and I do have one) is that there is at least one other method of ejecting the disc without otherwise affecting the app and OS that can't be blocked.
The OP should merely be aware that he will not have 100% ensurance that the disc can't be ejected.
|
|
|
|
|
True, however not all drives have a pinhole to force an eject, and most non-power users have no idea about what it does. Your original post appear to be implying that because there was a hardware endrun around any protection that could could code in that writing code to cover the normalish methods wasn't a worthwhile objective. Apologies if I misunderstood your intent.
The latest nation. Procrastination.
|
|
|
|
|
Hi everyone, I really wasn't expecting such a big response. Thank you everyone for your replies.
It is true that all effort are futile due to the tiny weeny hole because the hole is an emergency overwrite incase a program locks the drive and shutdowns with releasing it or something, but PIEBALDconsult is correct in their assumsion that I wish to prevent the eject button from being accidently pressed (trust me it happens alot on laptops), or being ejected from explorer or even being eject by someone elses program.
DaveyM69, I found your link to the VB code excellent. I never stumbled across that page during my search. And I agree with you on hand-fed code, but wow that's some great work dude, I'll have to implement it now, so that your efforts aren't in vain. Many thanks. I hope that search engines point here after this because those are some really good answers.
|
|
|
|
|
I don't normally hand feed answers - but I found your problem interesting so I 've converted the VB code I linked to.
It's rough and ready and needs a bit of work - but it does what you want. Just call LockMedia("X", true); to lock, and LockMedia("X", false); to unlock where X = drive letter.
Sources (most MSDN - a good resource!):
CreateFile[^]
DeviceIoControl[^]
SECURITY_ATTRIBUTES[^]
CloseHandle[^]
VB Code[^]
public static class CDDriveControl
{
public static bool LockMedia(string driveLetter, bool lockDrive)
{
bool result = false;
string fullDrivePath = string.Format(@"\\.\{0}:", driveLetter);
SECURITY_ATTRIBUTES securityAttributes = new SECURITY_ATTRIBUTES();
IntPtr hDrive = CreateFile(
fullDrivePath,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
ref securityAttributes,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
IntPtr.Zero);
if(hDrive != INVALID_HANDLE_VALUE)
{
IntPtr outBuffer;
int bytesReturned;
NativeOverlapped overlapped = new NativeOverlapped();
result = DeviceIoControl(
hDrive,
IOCTL_STORAGE_MEDIA_REMOVAL,
ref lockDrive,
1,
out outBuffer,
0,
out bytesReturned,
ref overlapped);
CloseHandle(hDrive);
}
return result;
}
private const uint GENERIC_READ = 0x80000000;
private const int FILE_SHARE_READ = 0x00000001;
private const int FILE_SHARE_WRITE = 0x00000002;
private const int OPEN_EXISTING = 3;
private const int FILE_ATTRIBUTE_NORMAL = 0x80;
private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
private const int IOCTL_STORAGE_MEDIA_REMOVAL = 0x2D4804;
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
ref SECURITY_ATTRIBUTES lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool DeviceIoControl(
IntPtr hDevice,
int dwIoControlCode,
ref bool lpInBuffer,
int nInBufferSize,
out IntPtr lpOutBuffer,
int nOutBufferSize,
out int lpBytesReturned,
ref NativeOverlapped lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(
IntPtr hObject);
[StructLayout(LayoutKind.Sequential)]
private struct SECURITY_ATTRIBUTES
{
int nLength;
IntPtr lpSecurityDescriptor;
bool bInheritHandle;
}
}
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
Hi Dave,
Interesting. Does this work on Vista (and Win7)?
|
|
|
|
|
Untested - I don't have Win7 here, but will test on vista on my other box now
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
Works fine on Vista without any UAC prompts
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
Hi Dave,
Thanks. I just gave your code post a 5.
I'm surprised it works on Vista. I have been trying to get the real harddisk serial number, which can be attempted in a similar way: CreateFile at the device level, and do some reading. Vista doesn't let a regular user do that, and it is only reading that is needed!
I'll investigate further at some later time.
Still have to thinker about text file comparisons (see my sig).
cheers.
|
|
|
|
|
I had a look at your article earlier actually. I need to have a good close look at this problem, although it's been around forever I've never had to attempt or study it so I have to admit to being clueless. One of the benifits of being a self taught programmer!
I got this code from here[^] - I haven't tried under vista but works fine under XP so you never know
[Edit] Deleted LONG code post - tested under vista and getting hard drive serial by this method doesn't work without running as Administrator, but locking the CD/DVD tray does! [/Edit]
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia) Why are you using VB6? Do you hate yourself? (Christian Graus)
modified on Thursday, August 27, 2009 5:42 PM
|
|
|
|
|
Yeah, I will compare my failing serial number attempt with your succeeding CD locking code. Sometime, next week, I hope.
Thanks again.
|
|
|
|
|
DaveyM69 wrote: tested under vista and doesn't work without running as Administrator
Actually I'm glad, otherwise non-elevated programs could randomly jam my CD drive - but no wait, I'm on XP, so they can do it anyway
|
|
|
|
|
Sorry - that post's misleading as Luc and I went off topic a little (I'll edit again to make that clear).
Getting hard drive serial number by similar method doesn't work without elevation.
Locking the CD drive does work without elevation
Work that out, one locks the hardware, the other reads a few bytes of insignificant data. Which one does MS decide to block One day I'll understand their logic... maybe!
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
Oh, ok, thanks for clarifying
(but yea it's weird)
|
|
|
|
|
It works on windows 7 RTM,
But with regards to my app, getting the threading right is getting tricky.
|
|
|
|
|
Good morning.
I have the following code:
uipc.tsProgBar.Style = ProgressBarStyle.Marquee;
uipc.tsProgBar.MarqueeAnimationSpeed = 100;
uipc.tsProgBar.Style = ProgressBarStyle.Continuous;
uipc.tsProgBar.MarqueeAnimationSpeed = 0;
If I put a messagebox after the
uipc.tsProgBar.Style = ProgressBarStyle.Marquee;
uipc.tsProgBar.MarqueeAnimationSpeed = 100; ,
then the progress bar with start "scrolling" and stop when the user click Ok on the messagebox.
Any suggestion? Thank you, WHEELS
|
|
|
|
|
If you're doing your processes on the main thread then the gui won't be able to update as you'll have hold of the thread. Look at using a BackgroundWorker so your gui remains responsive.
|
|
|
|
|
|