How to determine if a CD is in CD-ROM drive - c++

I was wondering if there is a Windows API that can tell me if there is a empty CD is inside a CD-ROM/DVD-Rom drive.
I've already looked at GetVolumeInformation(), but that only brings back information on the actual CD-ROM drive, not the media that is inside it, if there's even a CD in it or not.
All I'm trying to do is see if there's a cd in the drive or not and return a boolean value.
Thanks for any help

Call GetFileAttributes() on the root directory. GetFileAttributes() is quite optimized as it's commonly used as a check whether a file or directory exists.
Another method is to call GetDiskFreeSpace, which (despite its name) also returns the total disk size.
The Shell also has some useful functions. SHGetDriveMedia will tell you what's loaded, but you should first call GetDriveType().

The API you're looking for is most probably IMAPI.
I think this article here could be of help for you http://msdn.microsoft.com/en-us/magazine/cc163992.aspx

You can use DeviceIoControl API passing IOCTL_STORAGE_CHECK_VERIFY as the dwIoControlCode. This will check if a particular disc drive is ready i. e. has a disc in it and, of course, the tray is closed. Check the DeviceIoControl MSDN documentation for more info on this function.

// FROM VISTA to ....
BOOL CDYesNo(WCHAR letter) {// like F
DWORD pdwMediaContent=0;
BOOL ret =1;
WCHAR catw[3]; // create wchar string
catw[0]=letter;
catw[1]=L':';
catw[2]=NULL; `enter code here`
HRESULT rcd=SHGetDriveMedia( catw, &pdwMediaContent);
//rcd normally is S_OK, maybe tested.
if(pdwMediaContent ==0) ret=0;
return ret; // 0=empty
}

Related

GetDiskFreeSpaceEx with NULL Directory Name failing

I'm trying to use GetDiskFreeSpaceEx in my C++ win32 application to get the total available bytes on the 'current' drive. I'm on Windows 7.
I'm using this sample code: http://support.microsoft.com/kb/231497
And it works! Well, almost. It works if I provide a drive, such as:
...
szDrive[0] = 'C'; // <-- specifying drive
szDrive[1] = ':';
szDrive[2] = '\\';
szDrive[3] = '\0';
pszDrive = szDrive;
...
fResult = pGetDiskFreeSpaceEx ((LPCTSTR)pszDrive,
    (PULARGE_INTEGER)&i64FreeBytesToCaller,
    (PULARGE_INTEGER)&i64TotalBytes,
(PULARGE_INTEGER)&i64FreeBytes);
fResult becomes true and i can go on to accurately calculate the number of free bytes available.
The problem, however, is that I was hoping to not have to specify the drive, but instead just use the 'current' one. The docs I found online (Here) state:
lpDirectoryName [in, optional]
A directory on the disk. If this parameter is NULL, the function uses the root of the current disk.
But if I pass in NULL for the Directory Name then GetDiskFreeSpaceEx ends up returning false and the data remains as garbage.
fResult = pGetDiskFreeSpaceEx (NULL,
    (PULARGE_INTEGER)&i64FreeBytesToCaller,
    (PULARGE_INTEGER)&i64TotalBytes,
(PULARGE_INTEGER)&i64FreeBytes);
//fResult == false
Is this odd? Surely I'm missing something? Any help is appreciated!
EDIT
As per JosephH's comment, I did a GetLastError() call. It returned the DWORD for:
ERROR_INVALID_NAME 123 (0x7B)
The filename, directory name, or volume label syntax is incorrect.
2nd EDIT
Buried down in the comments I mentioned:
I tried GetCurrentDirectory and it returns the correct absolute path, except it prefixes it with \\?\
it returns the correct absolute path, except it prefixes it with \\?\
That's the key to this mystery. What you got back is the name of the directory with the native api path name. Windows is an operating system that internally looks very different from what you are familiar with winapi programming. The Windows kernel has a completely different api, it resembles the DEC VMS operating system a lot. No coincidence, David Cutler used to work for DEC. On top of that native OS were originally three api layers, Win32, POSIX and OS/2. They made it easy to port programs from other operating systems to Windows NT. Nobody cared much for the POSIX and OS/2 layers, they were dropped at XP time.
One infamous restriction in Win32 is the value of MAX_PATH, 260. It sets the largest permitted size of a C string that stores a file path name. The native api permits much larger names, 32000 characters. You can bypass the Win32 restriction by using the path name using the native api format. Which is simply the same path name as you are familiar with, but prefixed with \\?\.
So surely the reason that you got such a string back from GetCurrentDirectory() is because your current directory name is longer than 259 characters. Extrapolating further, GetDiskFreeSpaceEx() failed because it has a bug, it rejects the long name it sees when you pass NULL. Somewhat understandable, it isn't normally asked to deal with long names. Everybody just passes the drive name.
This is fairly typical for what happens when you create directories with such long names. Stuff just starts falling over randomly. In general there is a lot of C code around that uses MAX_PATH and that code will fail miserably when it has to deal with path names that are longer than that. This is a pretty exploitable problem too for its ability to create stack buffer overflow in a C program, technically a carefully crafted file name could be used to manipulate programs and inject malware.
There is no real cure for this problem, that bug in GetDiskFreeSpaceEx() isn't going to be fixed any time soon. Delete that directory, it can cause lots more trouble, and write this off as a learning experience.
I am pretty sure you will have to retrieve the current drive and directory and pass that to the function. I remember attempting to use GetDiskFreeSpaceEx() with the directory name as ".", but that did not work.

Correctly creating and running a win32 service with file I/O

I've written a very simple service application based on this code example.
The application as part of its normal running assumes there exists a file in the directory it is found, or in its execution path.
When I 'install' the service and then subsequently 'start' the service from the service manager in control panel. The application fails because it can't find the file to open and read from (even though the file is in the same directory as the installed executable).
My question is when a windows service is run, which is the expected running path supposed to be?
When calling 'CreateService' there only seems to be a path parameter for the binary, not for execution. Is there someway to indicate where the binary should be executed from?
I've tried this on windows vista and windows 7. Getting the same issues.
Since Windows services are run from a different context than normal user-mode applications, it's best if you don't make any assumptions about working directories or relative paths. Aside from differences in working directories, a service could run using a completely different set of permissions, etc.
Using an absolute path to the file that your service needs should avoid this problem entirely. Absolute paths will be interpreted the same regardless of the working directory, so this should make the working directory of your service irrelevant. There are several ways to go about this:
Hard-code the absolute path - This is perhaps the easiest way to avoid the problem, however it's also the least flexible. This method is probably fine for basic development and testing work, but you probably want something a bit more sophisticated before other people start using your program.
Store the absolute path in an environment variable - This gives you an extra layer of flexibility since the path can now be set to any arbitrary value and changed as needed. Since a service can run as a different user with a different set of environment variables, there are still some gotchas with this approach.
Store an absolute path in the registry - This is probably the most fool-proof method. Retrieving the path from the registry will give you the same result for all user accounts, plus this is relatively easy to set up at install time.
By default, the current directory for your Windows service is the System32 folder.
A promising solution is creating an environment variable that keeps the full path of your input location and retrieving the path from this variable at runtime.
If you use the same path as binary, you could just read binary path and modify it accordingly. But this is rather quick-fix rather than designed-solution. If I were you, I would either create system-wide environment variable and store value there, or (even better) use windows registry to store service configuration.
Note:
You will need to add Yourself some privileges using AdjustTokenPrivileges function, you can see an example here in ModifyPrivilege function.
Also be sure to use HKEY_LOCAL_MACHINE and not HKEY_CURRENT_USER. Services ar running under different user account so it's HKCU's will be different than what you can see in your registry editor.
Today I solved this problem as it was needed for some software I was developing.
As people above have said; you can hardcode the directory to a specific file - but that would mean whatever config files are needed to load would have to be placed there.
For me, this service was being installed on > 50,000 computers.
We designed it to load from directory in which the service executable is running from.
Now, this is easy enough to set up and achieve as a non-system process (I did most of my testing as a non-system process). But the thing is that the system wrapper that you used (and I used as well) uses Unicode formatting (and depends on it) so traditional ways of doing it doesn't work as well.
Commented parts of the code should explain this. There are some redundancies, I know, but I just wanted a working version when I wrote this.
Fortunately, you can just use GetModuleFileNameA to process it in ASCII format
The code I used is:
char buffer[MAX_PATH]; // create buffer
DWORD size = GetModuleFileNameA(NULL, buffer, MAX_PATH); // Get file path in ASCII
std::string configLoc; // make string
for (int i = 0; i < strlen(buffer); i++) // iterate through characters of buffer
{
if (buffer[i] == '\\') // if buffer has a '\' in it, replace with doubles
{
configLoc = configLoc + "\\\\"; // doubles needed for parsing. 4 = 2(str)
}
else
{
configLoc = configLoc + buffer[i]; // else just add char as normal
}
}
// Complete location
configLoc = configLoc.substr(0, configLoc.length() - 17); //cut the .exe off the end
//(change this to fit needs)
configLoc += "\\\\login.cfg"; // add config file to end of string
From here on, you can simple parse configLoc into a new ifsteam - and then process the contents.
Use this function to adjust the working directory of the service to be the same as the working directory of the exe it's running.
void AdjustCurrentWorkingDir() {
TCHAR szBuff[1024];
DWORD dwRet = 0;
dwRet = GetModuleFileName(NULL, szBuff, 1024); //gets path of exe
if (dwRet != 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
*(_tcsrchr(szBuff, '\\') + 1) = 0; //get parent directory of exe
if (SetCurrentDirectory(szBuff) == 0) {
//Error
}
}
}

C++ CopyFile() does not works on c:\

hello guys i have one simple program which copying itself. Its work great when i copying in D disk. But when im trying to copy it on c disk nothing happens.
This is code :
int main()
{
string appDir = "";
appDir = std::string( result, GetModuleFileName( NULL, result, MAX_PATH ) );
CopyFile(appDir.c_str(), "C:\\SelfCopyingApp.exe", 1);
system("PAUSE");
return 0;
}
Does anyone have an idea?
Thanks...
By default, the system drive has locked down permissions which prevent anyone from copying things there who are not administrators. Generally, one should not be messing with the root of the drive. If you need to do something like an installer, then you should
Ask for Admin rights
Install yourself in the correct location, namely %PROGRAMFILES%\CompanyName\ProductName
Messing with the root of the drive is asking for trouble; that's not where programs go.
Other notes on this code not related to your question:
system("pause") is wrong. Use std::cin.get() if you really want a portable way to get that behavior.
You should probably be using Unicode.
If GetModuleFileName fails you're going to be copying some random garbage to that location, not yourself. You need to check the return codes and GetLastError codes of every Win32 function.

How to get the path of the exexuter in C++?

I am using Visual studio 2008 and I want to get the absolute path of the .exe file?
meaning when the user opens the exe file, I need to know its absolute path??
thanks in advance
Under Windows try the following:
char ExeName[8192]; // or what ever max. size you expect.
if (0 != GetModuleFileName (NULL, ExeName, sizeof (ExeName)))
{
printf ("Your array was probably not large enough. Call GetLastError for details\n");
}
If you compile for unicode use wchar_t.
Using the _pgmptr or _wpgmptr global variable is probably the easiest way.* (They're in stdlib.h.)
*Note: Under some rather rare circumstances, it's possible that this won't work... in that case, use GetModuleFileName(NULL, ...);
If you want to obtain a path of the current process, you should use API function:
GetModuleFileName
But, if you want to obtain a full path of the process that is not written by you, use
GetModuleFileNameEx
Above function expects one argument more than GetModuleFileName - it is a HANDLE of a process which path is supposed to be obtained. It is explained in more details on MSDN.

How to set the application path to the running program?

I have a program that is executed by another program. The program that is being executed needs files located at its own location [same folder]. If I call myfile.open("xpo.dll") I might get an error because I am not passing the [fullpath + name + extension]. The program that is being executed can vary paths depending on the installation path. Therefore, I was wondering if there is a way to get the application path [where the application is located] and set it so that when another program executes from another path everything might work properly...?
[Using C++ without .NET Framework]
Thanks.
Use GetModuleFileName and pass NULL for hModule.
DWORD GetModuleFileName(
HMODULE hModule, // handle to module
LPTSTR lpFilename, // path buffer
DWORD nSize // size of buffer
);
First off, I run into this problem in other languages a lot, and find Process Monitor (http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx) very useful for finding out what folder it is currently trying to access.
There is no standard function for doing this.
Just a thought, have you tried doing myfile.open "./xpo.dll"?
If it's a console application, you can use the POSIX getcwd function: http://www.dreamincode.net/code/snippet77.htm
If it's a Windows app and you can use the windows API, you can use GetModuleFileName... see the second reply to this question here: How do I get the directory that a program is running from?