Why The Following Code always reports C:\ although It reports different Device Name
handle = FindFirstVolumeW(volName, sizeof(volName));
do{
wchar_t wVolName[MAX_PATH];
QString::fromWCharArray(volName).toWCharArray(wVolName);//make a copy of volName on wVolName
wVolName[wcslen(volName)-1] = L'\0';
wchar_t wDeviceName[MAX_PATH];
int charCount = 0;
charCount = QueryDosDeviceW(&wVolName[4], wDeviceName, ARRAYSIZE(wDeviceName));
qDebug() << QString::fromWCharArray(wVolName) << "Device: " << QString::fromWCharArray(wDeviceName);//print wVolName and wDeviceName
wchar_t driveName[MAX_PATH];
GetVolumePathName(wDeviceName, driveName, MAX_PATH);
CloseHandle(handle);
qDebug() << QString::fromWCharArray(driveName);
}while(FindNextVolume(handle, volName, sizeof(volName)));
FindVolumeClose(handle);
Output:
"\\?\Volume{5c77cc58-d5ab-11e0-a0ec-806d6172696f}" Device: "\Device\HarddiskVolume2"
"C:\"
"\\?\Volume{5c77cc59-d5ab-11e0-a0ec-806d6172696f}" Device: "\Device\HarddiskVolume3"
"C:\"
"\\?\Volume{5c77cc57-d5ab-11e0-a0ec-806d6172696f}" Device: "\Device\CdRom0"
"C:\"
"\\?\Volume{5c77cc56-d5ab-11e0-a0ec-806d6172696f}" Device: "\Device\Floppy0"
"C:\"
"\\?\Volume{8d974f2c-e9a1-11e0-b7da-0013d407432f}" Device: "\Device\Harddisk1\DP(1)0- 0+8"
"C:\"
Why doesn't it report D, E, etc ..
EDIT
and How can I derive the Drive Letter assigned to the Volume
The documentation for the function says it all:
You must specify a valid Win32 namespace path. If you specify an NT namespace path, for example, "\DosDevices\H:" or "\Device\HardDiskVolume6", the function returns the drive letter of the current volume, not the drive letter of that NT namespace path.
By the way, a volume can be mounted to multiple drive letters (a drive name like C: is nothing more than a symlink in the NT namespace), so it doesn't really make sense to translate in this manner.
From the GetVolumePathName documentation:
If you specify a relative directory or file name without a volume
qualifier, GetVolumePathName returns the drive letter of the current
volume.
Perhaps because you are calling CloseHandle while in the loop: don't do that.
It looks like you modeled your code after http://msdn.microsoft.com/en-us/library/cc542456%28v=vs.85%29.aspx: you'll notice the only time they call CloseHandle is AFTER the entire loop is done.
Related
As you all know, the appdata folder is this
C:\Users\*Username*\AppData\Roaming
on windows 7
Since my application will be deployed on all kinds of Windows OSes i need to be able to get the folder 100% percent of the time.
The question is how do you do it in C++? Since i don't know the the exact Windows OS it could be XP,Vista or 7 and most importantly i don't know what the Username is.
For maximum compatibility with all versions of Windows, you can use the SHGetFolderPath function.
It requires that you specify the CSIDL value for the folder whose path you want to retrieve. For the application data folder, that would be CSIDL_APPDATA.
On Windows Vista and later, you should use the SHGetKnownFolderPath function instead, which requires that you specify the folder's KNOWNFOLDERID value. Again, for the application data folder, the appropriate value is FOLDERID_RoamingAppData.
To use either of these functions from your C++ application, you'll need to include shlobj.h.
You can try the following:
char* appdata = getenv("APPDATA");
This code reads the environment variable APPDATA (you can also see it when you type SET in a command window). It is set by Windows when your system starts.
It will return the path of the user's appdata as an absolute path, including Username and taking into account whichever OS version they're using.
Perhaps fellow Googlers might find it interesting to have a look at std::filesystem. For instance, let's assume the default temp directory location and AppData directory structure in Windows 10:
#include <filesystem>
auto path = std::filesystem::temp_directory_path()
.parent_path()
.parent_path();
path /= "Roaming";
if (!std::filesystem::exists(path))
std::filesystem::create_directories(path);
In the case of OP, I am assuming this doesn't solve the problem. I do want to raise a word of caution against doing the above in a situation that requires a 100% robust implementation, as system configurations can easily change and break the above.
But perhaps new visitors to the question might find std::filesystem useful. Chances are, you're going to want to manipulate the items in the directory if you're looking for it, and for this, std::filesystem can be your friend.
If someone is looking for a simple implementation, here's mine:
#include <windows.h>
#include <shlobj.h>
#include <filesystem>
#include <iostream>
int main(void)
{
std::filesystem::path path;
PWSTR path_tmp;
/* Attempt to get user's AppData folder
*
* Microsoft Docs:
* https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath
* https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid
*/
auto get_folder_path_ret = SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &path_tmp);
/* Error check */
if (get_folder_path_ret != S_OK) {
CoTaskMemFree(path_tmp);
return 1;
}
/* Convert the Windows path type to a C++ path */
path = path_tmp;
/* Free memory :) */
CoTaskMemFree(path_tmp);
std::cout << path << std::endl;
return 0;
}
Use this Code to reads the environment variable "APPDATA"
Include stdio.h file in beginning
char *pValue;
size_t len;
errno_t err = _dupenv_s(&pValue, &len, "APPDATA");
Here is a simple implementation for old C++ versions :
#include <shlobj.h>
// ...
wchar_t* localAppDataFolder;
if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) {
std::cerr << "problem getting appdata folder" << std::endl;
}
else std::wcout << L"folder found: " << localAppDataFolder << std::endl;
I made a program that runs automatically at startup, but my program does not perform the task of append text to the file when it runs automatically.
Here example code:
#include <Windows.h>
#include <fstream>
#include <iostream>
void AutoRun() {
LONG key;
std::string FP;
char re[MAX_PATH];
FP = std::string(re, GetModuleFileNameA(NULL, re, MAX_PATH));
HKEY hkey;
key = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\Currentversion\\Run", 0, KEY_WRITE, &hkey);
if (key == ERROR_SUCCESS)
{
std::cout << "paketi yüklüyoruzzz";
key = RegSetValueExA(hkey, "testzort", 0, REG_SZ, (BYTE*)FP.c_str(), strlen(FP.c_str()));
RegCloseKey(hkey);
}
else {
std::cout << "Maga mapket müklenemedi:(: " << key;
}
}
int main(){
// open output file in append mode
const char* output_filename = "testing.log";
std::cout << "Logging output to " << output_filename << std::endl;
output_file.open(output_filename, std::ios_base::app);
AutoRun();
output_file << "zozozort\n";
}
When I restart my computer after execute this code, not add my file like:
zozozort
zozozort
What is the problem ?
NOTE: For the first time to run the regedit api, I ran the program with administrator mode when starting
First off, consider using HKEY_CURRENT_USER instead of HKEY_LOCAL_MACHINE (unless you really want all users of your machine running your app). And consider using KEY_SET_VALUE instead of KEY_WRITE (which includes rights you don't need in this code). This will reduce the need for your code to run as an admin when setting up the auto-run.
In any case, when calling RegSetValueEx(), you are setting the data size to strlen(FP.c_str()), which is wrong, as RegSetValueEx() requires the null terminator to be included in the data size:
If the data is of type REG_SZ, REG_EXPAND_SZ, or REG_MULTI_SZ, cbData must include the size of the terminating null character or characters.
So, use strlen(FP.c_str())+1 instead, or better FP.size()+1.
That being said, your app is opening the text file using a relative path, so its location is relative to the app's current working directory, which you don't know what it is when your app is started (you can use GetCurrentDirectory() to determine that). Just because the text file is in the same folder as your app doesn't mean the working directory points to your app's folder. Always use absolute paths when creating/opening files.
If you were using CreateFile() instead of (o)fstream (BTW, where is your output_file variable declared?) to create/open the file, then you could use GetFinalPathNameByHandle() to determine its actual full path, so you can see if it is what you are expecting.
If your really want to create/open the text file in your app's folder, you already know how to get the app's full file path from GetModuleFileName(), so simply replace the filename portion after the last '\' character with your text file's name, and then use that full path to create/open the file. Just make sure your app is not running in a folder that denies write access to non-admins, such as Program Files.
You really should be writing the text file into a folder that is guaranteed to be accessible to the calling user (preferably within their own profile), instead of in the app's folder. For instance, get a user-accessible folder path via either:
SHGetFolderPath(), specifying something like CSIDL_(LOCAL_|COMMON_)APPDATA, CSIDL_DESKTOPDIRECTORY, CSIDL_MYDOCUMENTS, etc.
SHGetKnownFolderPath(), specifying something like FOLDERID_(Roaming|Local)AppData, FOLDERID_ProgramData, FOLDERID_Desktop, FOLDERID_Documents, etc.
Then, create your own subfolder underneath that folder, and create the file inside that subfolder.
I have searched internet but couldn't find answer,how can I get drive name from drive letter on c++ for windows?I mean if I say G:\ it has to give me the name of pen drive.Ex:Removable Disk.
It is as simple as calling the GetVolumeInformation API function. You pass in the drive letter as the path name (e.g., G:\), and the function fills a buffer containing the volume name (along with other information, if you are interested in any of that).
Here is the code required to retrieve the volume name for the G:\ drive. The volume name is placed into the szVolumeName buffer:
WCHAR szVolumeName[MAX_PATH];
BOOL bSucceeded = GetVolumeInformationW(L"G:\\",
szVolumeName,
MAX_PATH,
NULL,
NULL,
NULL,
NULL,
0);
If you want any of the other information while you're calling the function, like the volume's DOS serial number, the file system name, etc., then you can change the parameters from NULL to the appropriate buffers.
I need help with one of my programs that pulls out available drives on a system and prints various information about the drives. I am using VC++ and am fairly new to C++ and need some high level inputs or example code from experienced programmers.
Here is my current source code:
#include "stdafx.h"
#include Windows.h
#include stdio.h
#include iostream
using namespace std;
int main()
{
// Initial Dummy drive
WCHAR myDrives[] = L" A";
// Get the logical drive bitmask (1st drive at bit position 0, 2nd drive at bit position 1... so on)
DWORD myDrivesBitMask = GetLogicalDrives();
// Verifying the returned drive mask
if(myDrivesBitMask == 0)
wprintf(L"GetLogicalDrives() failed with error code: %d\n", GetLastError());
else {
wprintf(L"This machine has the following logical drives:\n");
while(myDrivesBitMask) {
// Use the bitwise AND with 1 to identify
// whether there is a drive present or not.
if(myDrivesBitMask & 1) {
// Printing out the available drives
wprintf(L"drive %s\n", myDrives);
}
// increment counter for the next available drive.
myDrives[1]++;
// shift the bitmask binary right
myDrivesBitMask >>= 1;
}
wprintf(L"\n");
}
system("pause");
}
`
-Here is the output-
This machine has the following logical drives:
drive C
drive D
drive E
drive F
drive G
drive H
drive I
I need to output additional information about each drive (perhaps an example will tell the story in a shorter amount of time):
Drive – C:\
Drive Type: Fixed
Drive Ready Status: True
Volume Label: Boot Drive
File System Type : NTFS
Free Space: 30021926912
Total Drive Size: 240055742464
Drive – D:\
Drive Type: Fixed
Drive Ready Status: True
Volume Label: Application Data
File System Type : NTFS
Free Space: 42462507008
Total Drive Size: 240054693888
Which methods, libs api, etc. can I use to pull out drive type, drive status, volume label, file system type, free space, and total drive size?
*Side note, I noticed a defect with my pre-processor directives, specifically within the standard I/O header files. I know that is not the recommended way using printf and cout is type safe and the proper route to go but I couldn't figure out how to format output in cout as you would do in wprintf(L"drive %s\n", myDrives);.... so how would you do this with cout??
Thanks in advance.
You want to look at functions such as GetVolumeInformation to retrieve file system information such as free space and volume name.
GetDriveType will give you some basic information about the drive type, but USB thumb sticks and flash readers can give surprising results.
I'm not sure what you mean by "ready status". If you mean whether there is a valid volume in the drive, then you can try CreateFile with a path of "\\.\C:" to try and open the volume. If it fails then there is no volume (disk) present. This will be of use for SD card readers. To do this without an error dialog appearing you will need to call SetErrorMode(SEM_NOOPENFILEERRORBOX) first.
To check whether a drive is ready you may also use GetDiskFreeSpaceEx. If this fails, the drive is not ready/usable.
Here is some example code: http://pinvoke.net/default.aspx/coredll/GetDiskFreeSpaceEx.html
As you all know, the appdata folder is this
C:\Users\*Username*\AppData\Roaming
on windows 7
Since my application will be deployed on all kinds of Windows OSes i need to be able to get the folder 100% percent of the time.
The question is how do you do it in C++? Since i don't know the the exact Windows OS it could be XP,Vista or 7 and most importantly i don't know what the Username is.
For maximum compatibility with all versions of Windows, you can use the SHGetFolderPath function.
It requires that you specify the CSIDL value for the folder whose path you want to retrieve. For the application data folder, that would be CSIDL_APPDATA.
On Windows Vista and later, you should use the SHGetKnownFolderPath function instead, which requires that you specify the folder's KNOWNFOLDERID value. Again, for the application data folder, the appropriate value is FOLDERID_RoamingAppData.
To use either of these functions from your C++ application, you'll need to include shlobj.h.
You can try the following:
char* appdata = getenv("APPDATA");
This code reads the environment variable APPDATA (you can also see it when you type SET in a command window). It is set by Windows when your system starts.
It will return the path of the user's appdata as an absolute path, including Username and taking into account whichever OS version they're using.
Perhaps fellow Googlers might find it interesting to have a look at std::filesystem. For instance, let's assume the default temp directory location and AppData directory structure in Windows 10:
#include <filesystem>
auto path = std::filesystem::temp_directory_path()
.parent_path()
.parent_path();
path /= "Roaming";
if (!std::filesystem::exists(path))
std::filesystem::create_directories(path);
In the case of OP, I am assuming this doesn't solve the problem. I do want to raise a word of caution against doing the above in a situation that requires a 100% robust implementation, as system configurations can easily change and break the above.
But perhaps new visitors to the question might find std::filesystem useful. Chances are, you're going to want to manipulate the items in the directory if you're looking for it, and for this, std::filesystem can be your friend.
If someone is looking for a simple implementation, here's mine:
#include <windows.h>
#include <shlobj.h>
#include <filesystem>
#include <iostream>
int main(void)
{
std::filesystem::path path;
PWSTR path_tmp;
/* Attempt to get user's AppData folder
*
* Microsoft Docs:
* https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath
* https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid
*/
auto get_folder_path_ret = SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &path_tmp);
/* Error check */
if (get_folder_path_ret != S_OK) {
CoTaskMemFree(path_tmp);
return 1;
}
/* Convert the Windows path type to a C++ path */
path = path_tmp;
/* Free memory :) */
CoTaskMemFree(path_tmp);
std::cout << path << std::endl;
return 0;
}
Use this Code to reads the environment variable "APPDATA"
Include stdio.h file in beginning
char *pValue;
size_t len;
errno_t err = _dupenv_s(&pValue, &len, "APPDATA");
Here is a simple implementation for old C++ versions :
#include <shlobj.h>
// ...
wchar_t* localAppDataFolder;
if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) {
std::cerr << "problem getting appdata folder" << std::endl;
}
else std::wcout << L"folder found: " << localAppDataFolder << std::endl;