W
W
whoami?root root_toor2016-04-13 21:16:59
C++ / C#
whoami?root root_toor, 2016-04-13 21:16:59

Why won't WinAPI DeviceIOControl QueryDosDevice compile?

Good evening!
Please help, we urgently need to complete a part of the program:
you just need to get the correspondence of each logical disk to a real, physical disk.
Those. something like: std::string getPhysicalDrive(logicalDisk);
Googled several options on how to do this:
1) get a list of disks and use DeviceIOControl (), which will return the disk ownership to a specific drive. Trying to run code in 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;
}

Errors:
Серьезность	Код	Описание	Проект	Файл	Строка	Состояние подавления
Ошибка	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

I tried to change LPSTR to LPWSTR PWSTR and so on ... different string types as I understand it (I'm not familiar with winapi), but I don't have time to delve into it (I'm making a program in Qt, I just need a small piece of Windows-specific code).
2) Use QueryDosDevice() (see above) or GetVolumeInformation . These methods, as far as I understand, are worse in the sense that at the output we get not a specific hard disk, but a Volume, which corresponds to a logical disk. \\Device\Harddisk1\Partition1 ...
Code:
// 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;
}

Errors:
Серьезность	Код	Описание	Проект	Файл	Строка	Состояние подавления
Ошибка (активно)		аргумент типа "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

again something with string types and conversions ... it seems that you can do conversions through WideCharToMultiByte() , but then why did these versions of programs work without conversions? maybe I need to include some other header files? And how then to use this function - it has 100500 parameters, like the rest of the API)))
3) Using WMI - I immediately weeded out, because. write that brake (all operations pass on the server).
It seems that the examples should work - I searched for a long time and, it seems, I found what I need, but I can’t figure out the errors.
In general, I need the program to be compiled using Qt5 (MinGW) ... in fact, the API has already done getting the list of disks, file system, etc. It remains to get the physical disk by the name of the logical one.
Knowledgeable people, please help!)
PS: maybe there are some ready-made functions on this subject?
Or is there an example with a similar problem?
Or are there easier options? (only do not parse the output of third-party utilities)
if it's not a pity, share it)
if it matters: Windows 10, did not install the 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;
}

managed to compile this, but the program does not output anything. Should I, if I understand correctly, display the number of the physical disk? what's wrong?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
Александр Ананьев, 2016-04-13
@1q2w1q2w

1. Если DeviceIoControl возвращает FALSE надо проверять ошибку через GetLastError
2. Инициализировать структуру лучше так STORAGE_DEVICE_NUMBER sd = {0};
3. stackoverflow.com/questions/7584627/how-to-get-a-l...

Петр, 2016-04-13
@petermzg

Что ж вы основ то не знаете - WCHAR

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question