Задать вопрос
@1q2w1q2w
sudo make install

WinAPI DeviceIOControl QueryDosDevice почему не компилируется?

Добрый вечер!
Прошу помочь, срочно надо доделать часть программы:
нужно просто получить соответствие каждого логического диска реальному, физическому диску.
Т.е. что то вроде: std::string getPhysicalDrive(logicalDisk);
Нагуглил несколько вариантов того, как это можно сделать:
1) получить список дисков и использовать DeviceIOControl(), которая вернет принадлежность диска конкретному накопителю. Пытаюсь запустить код в Visual Studio 2015:
// ConsoleApplication1.cpp: определяет точку входа для консольного приложения.
//

#include "stdafx.h"

#define _WIN32_WINNT    0x501
#include <windows.h>
#include <shlwapi.h>
#include <stdio.h>


int GetDevicePhysicalDiskNumber(LPCTSTR lpszDevice, LPSTR lpszResult, DWORD cchResultMax) // by Napalm
{
	HANDLE hDevice;
	STORAGE_DEVICE_NUMBER sdNumber;
	DWORD dwBytesReturned;
	int nResult = 0;

	hDevice = CreateFile(lpszDevice, GENERIC_READ, FILE_SHARE_READ |
		FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
	if (hDevice != INVALID_HANDLE_VALUE) {
		if (DeviceIoControl(hDevice, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0,
			&sdNumber, sizeof(sdNumber), &dwBytesReturned, NULL))
		{
			wnsprintf(lpszResult, cchResultMax, "\\\\.\\PhysicalDrive%d", sdNumber.DeviceNumber);
			nResult = 1;
		}
		CloseHandle(hDevice);
	}

	return nResult;
}

int main(int argc, char *argv[])
{
	TCHAR szDrive[MAX_PATH], szPath[MAX_PATH];

	// Method one.. not exactly what you want.
	StrCpy(szDrive, "C:");
	if (QueryDosDevice(szDrive, szPath, MAX_PATH) > 0) {
		printf("%s to %s\n", szDrive, szPath);
	}

	// Method two.. exactly what you want
	StrCpy(szDrive, "\\\\.\\C:"); // really "\\.\C:"
	if (GetDevicePhysicalDiskNumber(szDrive, szPath, MAX_PATH)) {
		printf("%s to %s\n", szDrive, szPath);
	}

	return 0;
}

Ошибки:
Серьезность	Код	Описание	Проект	Файл	Строка	Состояние подавления
Ошибка	C2664	"int wnsprintfW(PWSTR,int,PCWSTR,...)": невозможно преобразовать аргумент 1 из "LPSTR" в "PWSTR"	ConsoleApplication1	e:\test\consoleapplication1\consoleapplication1\consoleapplication1.cpp	25	
Ошибка	C2664	"PWSTR StrCpyW(PWSTR,PCWSTR)": невозможно преобразовать аргумент 2 из "const char [3]" в "PCWSTR"	ConsoleApplication1	e:\test\consoleapplication1\consoleapplication1\consoleapplication1.cpp	40	
Ошибка	C2664	"PWSTR StrCpyW(PWSTR,PCWSTR)": невозможно преобразовать аргумент 2 из "const char [7]" в "PCWSTR"	ConsoleApplication1	e:\test\consoleapplication1\consoleapplication1\consoleapplication1.cpp	46	
Ошибка	C2664	"int GetDevicePhysicalDiskNumber(LPCTSTR,LPSTR,DWORD)": невозможно преобразовать аргумент 2 из "TCHAR [260]" в "LPSTR"	ConsoleApplication1	e:\test\consoleapplication1\consoleapplication1\consoleapplication1.cpp	47

Попробовал поменять LPSTR на LPWSTR PWSTR и прочее ... разные строковые типы как я понимаю (с winapi знаком плохо), но времени вникать в это нет (программу делаю на Qt, нужен лишь небольшой кусок специфичного для Windows кода).
2) Использовать QueryDosDevice() (см. выше) или GetVolumeInformation. Эти способы, насколько я понял, хуже в том плане, что на выходе мы получаем не конкретно какой то жесткий диск, а Volume, которому соответствует логический диск. \\Device\Harddisk1\Partition1 ...
Код:
// ConsoleApplication1.cpp: определяет точку входа для консольного приложения.
//

#include "stdafx.h"

#include <iomanip>
#include <iostream>
#include <windows.h> 
using namespace std;

int main()
{
	char szDIR[] = "?:";
	char szVolumeName[MAX_PATH] = { 0 };
	char szFileSystem[MAX_PATH] = { 0 };
	DWORD nVolumeSerialNumber = 0;
	DWORD nMaxComponentLength = 0;
	DWORD nFileSystemFlags = 0;
	while (true)
	{
		cout << "Enter volume label  : "; cin >> szDIR[0];
		if
			(
				!GetVolumeInformation
				(
					szDIR,
					szVolumeName,
					MAX_PATH,
					&nVolumeSerialNumber,
					&nMaxComponentLength,
					&nFileSystemFlags,
					szFileSystem,
					MAX_PATH
					)
				)
			cout << "GetVolumeInformation ERROR : " << strerror(GetLastError()) << endl;
		else
			if (!CharToOem(szVolumeName, szVolumeName))
				cout << "CharToOem ERROR : " << strerror(GetLastError()) << endl;
			else
				if (!CharToOem(szFileSystem, szFileSystem))
					cout << "CharToOem ERROR : " << strerror(GetLastError()) << endl;
				else
				{
					cout << "szVolumeName        :   " << szVolumeName << endl;
					cout << "nVolumeSerialNumber : 0x" << hex << nVolumeSerialNumber << endl;
					cout << "nMaxComponentLength :   " << nMaxComponentLength << endl;
					cout << "nFileSystemFlags    : 0x" << hex << nFileSystemFlags << endl;
				}
	}
	return 0;
}



// char* to System::String^
System::String^  CharToSysString(char* ch)
{
char * chr=new char[]=ch;
System::String^ str;
for(int i=0;chr[i]!='\0';i++)
{
str+=wchar_t(ch[i]);
}
return str;
}

Ошибки:
Серьезность	Код	Описание	Проект	Файл	Строка	Состояние подавления
Ошибка (активно)		аргумент типа "char *" несовместим с параметром типа "LPWSTR"	ConsoleApplication1	e:\test\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cpp	27	
Серьезность	Код	Описание	Проект	Файл	Строка	Состояние подавления
Ошибка	C2664	"BOOL GetVolumeInformationW(LPCWSTR,LPWSTR,DWORD,LPDWORD,LPDWORD,LPDWORD,LPWSTR,DWORD)": невозможно преобразовать аргумент 1 из "char [3]" в "LPCWSTR"	ConsoleApplication1	e:\test\consoleapplication1\consoleapplication1\consoleapplication1.cpp	34	
Ошибка	C2664	"BOOL CharToOemW(LPCWSTR,LPSTR)": невозможно преобразовать аргумент 1 из "char [260]" в "LPCWSTR"	ConsoleApplication1	e:\test\consoleapplication1\consoleapplication1\consoleapplication1.cpp	38	
Ошибка	C2664	"BOOL CharToOemW(LPCWSTR,LPSTR)": невозможно преобразовать аргумент 1 из "char [260]" в "LPCWSTR"	ConsoleApplication1	e:\test\consoleapplication1\consoleapplication1\consoleapplication1.cpp	41

опять что то со строковыми типами и преобразованиями ... вроде бы можно делать преобразования через WideCharToMultiByte(), но почему тогда эти версии программ работали без преобразований? может мне нужно еще какие то заголовочные файлы подключить? И как тогда пользоваться этой функций - у нее 100500 параметров, как и у остальных API )))
3) Использование WMI - я сразу отсеял, т.к. пишут что тормозная (все операции проходят на серваке).

Вроде примеры должны работать - долго искал и, кажется, нашел то что нужно, но с ошибками разобраться не могу.
Вообще мне нужно, чтобы программа компилировалась с помощью Qt5 (MinGW) ... собственно на API уже сделано получение списка дисков, файловой системы и т.д. Осталось получение физического диска по имени логического.
Знающие люди, пожалуйста,помогите!)

зы: может есть готовые функции какие то на этот счет?
или есть пример с похожей задачей?
или есть варианты проще? (только не парсить вывод сторонних утилит)
если не жалко, поделитесь)
если это имеет значение: ОС Windows 10, пакет DDK не устанавливал.

UPD:
// ConsoleApplication1.cpp: определяет точку входа для консольного приложения.
//

#include "stdafx.h"

#include <iomanip>
#include <iostream>
#include <windows.h> 
#include <stdio.h>
#include <Winioctl.h>
#include <cstring>
#include "atlstr.h"

using namespace std;

VOID LogicalToPhysical(TCHAR *szDrive)
{
	CString szPhysical;
	HANDLE h = CreateFile(szDrive, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
	if (INVALID_HANDLE_VALUE != h)
	{
		STORAGE_DEVICE_NUMBER sd;
		DWORD dwRet;
		if (DeviceIoControl(h, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sd, sizeof(STORAGE_DEVICE_NUMBER), &dwRet, NULL))
		{
			szPhysical.Format(_T("\\\\.\\PhysicalDrive%d"), sd.DeviceNumber);
			cout << szPhysical << " is " << sd.DeviceNumber;
		}
		CloseHandle(h);
	}
}

int main()
{
	LogicalToPhysical(_T("\\\\.\\\\C:"));

	system("pause");

	return 0;
}

удалось скомпилировать это, но программа ничего не выводит. А должна, если я правильно понимаю, вывести номер физического диска? что не так?
  • Вопрос задан
  • 1824 просмотра
Подписаться 1 Оценить 1 комментарий
Решения вопроса 3
1. Если DeviceIoControl возвращает FALSE надо проверять ошибку через GetLastError
2. Инициализировать структуру лучше так STORAGE_DEVICE_NUMBER sd = {0};
3. stackoverflow.com/questions/7584627/how-to-get-a-l...
Ответ написан
AtomKrieg
@AtomKrieg
Давай я поищу в Google за тебя
void func_disk ()
{
	LPCWSTR lpDeviceName[8] = { L"A:", L"B:", L"C:", L"D:", L"E:", L"F:", L"G:", L"K:" };
	TCHAR lpTargetPath[1000];

	for (int i = 0; i <= 7; i++)
	{
		DWORD retval = QueryDosDevice ( lpDeviceName[i], (LPWSTR)lpTargetPath, 1000 );
		auto err = GetLastError ();
		
		std::wstring w1 ( lpDeviceName[i] );
		std::wcout << L"retval: " << retval << " err: " << err << std::endl;
		if (retval == 0 || retval == ERROR_INSUFFICIENT_BUFFER)
		{
			std::wcout << L"QueryDosDevice fails " << w1 << std::endl;
			continue;
		}
		std::wstring w2 ( lpTargetPath );
		std::wcout << w1 << " " << w2 << std::endl;
	}
}


Дальше читать это: stackoverflow.com/questions/3824221/volume-to-phys...
Ответ написан
Комментировать
@1q2w1q2w Автор вопроса
sudo make install
Всем большое спасибо! Выручили)
Вот рабочий код, пробовал и на студии и на Qt Creator:
#include <iostream>
#include <windows.h>

using namespace std;

VOID LogicalToPhysical(TCHAR *szDrive)
{
        LPCTSTR szPhysical; // was CString

        HANDLE h = CreateFile(szDrive, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
        if (INVALID_HANDLE_VALUE != h)
        {
                STORAGE_DEVICE_NUMBER sd = { 0 };
                DWORD dwRet;
                if (DeviceIoControl(h, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sd, sizeof(STORAGE_DEVICE_NUMBER), &dwRet, NULL))
                {
                        cout << "Physical disk: " << sd.DeviceNumber;
                }
                else {
                        cout << GetLastError();
                }
                CloseHandle(h);
        }
        else {
                cout << "Invalid handle value\n";
        }
}

int main(int argc, char *argv[])
{
    LogicalToPhysical(TEXT("\\\\.\\\\E:"));
    return 0;
}

Как раз то, что нужно ... номер физического диска на букву логического.
зы: для студии сыпалась куча ошибок из-за того, что я не поменял в настройках проекта используемую кодировку с Unicode на WideChar )
еще раз всем СПАСИБО!)
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
petermzg
@petermzg
Самый лучший программист
Что ж вы основ то не знаете - WCHAR
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы