Исправление ошибки ERROR_INVALID_NAME при получении GUID диска в Delphi
Вопрос, с которым сталкиваются разработчики, работающие с функциями операционной системы в Delphi, заключается в правильном использовании внешних функций, таких как GetVolumeNameForVolumeMountPoint. Эта функция предназначена для получения имени тома по его точке монтирования, но она может возвращать ошибку ERROR_INVALID_NAME при неправильном использовании.
Описание проблемы
Проблема заключается в том, что разработчик пытается получить GUID конкретного диска, используя функцию GetVolumeNameForVolumeMountPoint. В коде, предоставленном разработчиком, используется неправильный тип кодировки для строковых аргументов функции, что приводит к ошибке ERROR_INVALID_NAME с кодом 123.
Пример кода с ошибкой
Function GetVolumeNameForVolumeMountPoint(lpszVolumeMountPoint: LPCTSTR; lpszVolumeName: LPTSTR; cchBufferLength: DWORD): BOOL; stdcall;
external 'kernel32.dll' name 'GetVolumeNameForVolumeMountPointW';
procedure TForm1.Button1Click(Sender: TObject);
var
Buffer: array[0..50] of AnsiChar;
begin
if GetVolumeNameForVolumeMountPoint('C:\', Buffer, SizeOf(Buffer)) then
begin
ShowMessage(Buffer); // Ожидается вывод: "\\?\Volume{deadbeef-895e-4a1d-9d64-9b82fa068d76}\"
end
else RaiseLastOSError; // Фактически: ERROR_INVALID_NAME (123).
end;
Подтвержденный ответ
Ошибка возникает из-за того, что разработчик вызывает Unicode-версию функции, но передает ей строку в ANSI-формате. Это приводит к неправильной кодировке первого аргумента, что и вызывает ошибку.
Исправление
Для корректной работы с функцией GetVolumeNameForVolumeMountPoint необходимо использовать соответствующую версию функции, в зависимости от того, используете ли вы ANSI или Unicode версию Delphi. В случае использования ANSI версии Delphi, код должен выглядеть следующим образом:
{$APPTYPE CONSOLE}
uses
SysUtils, Windows;
function GetVolumeNameForVolumeMountPointA(lpszVolumeMountPoint: PAnsiChar;
lpszVolumeName: PAnsiChar; cchBufferLength: DWORD): BOOL; stdcall;
external 'kernel32.dll';
procedure Main;
var
Buffer: array [0 .. 49] of AnsiChar;
begin
Win32Check(GetVolumeNameForVolumeMountPointA('C:\', Buffer, Length(Buffer)));
Writeln(Buffer);
end;
begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
Если же вы используете Unicode версию Delphi, код будет выглядеть так:
{$APPTYPE CONSOLE}
uses
SysUtils, Windows;
function GetVolumeNameForVolumeMountPointW(lpszVolumeMountPoint: PWideChar;
lpszVolumeName: PWideChar; cchBufferLength: DWORD): BOOL; stdcall;
external 'kernel32.dll';
procedure Main;
var
Buffer: array [0 .. 49] of WideChar;
begin
Win32Check(GetVolumeNameForVolumeMountPointW('C:\', Buffer, Length(Buffer)));
Writeln(Buffer);
end;
begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
Для совместимости с различными версиями Delphi можно использовать следующий подход:
{$APPTYPE CONSOLE}
uses
SysUtils, Windows;
const
Win32ImportSuffix = {$IFDEF Unicode}'W'{$ELSE}'A'{$ENDIF};
function GetVolumeNameForVolumeMountPointA(lpszVolumeMountPoint: PAnsiChar;
lpszVolumeName: PAnsiChar; cchBufferLength: DWORD): BOOL; stdcall;
external 'kernel32.dll';
function GetVolumeNameForVolumeMountPointW(lpszVolumeMountPoint: PWideChar;
lpszVolumeName: PWideChar; cchBufferLength: DWORD): BOOL; stdcall;
external 'kernel32.dll';
function GetVolumeNameForVolumeMountPoint(lpszVolumeMountPoint: PChar;
lpszVolumeName: PChar; cchBufferLength: DWORD): BOOL; stdcall;
external 'kernel32.dll' name 'GetVolumeNameForVolumeMountPoint' + Win32ImportSuffix;
procedure Main;
var
Buffer: array [0 .. 49] of Char;
begin
Win32Check(GetVolumeNameForVolumeMountPoint('C:\', Buffer, Length(Buffer)));
Writeln(Buffer);
end;
begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
Этот код автоматически выбирает нужную версию функции в зависимости от того, используете ли вы ANSI или Unicode версию Delphi. Это позволяет избежать ошибки ERROR_INVALID_NAME и корректно получить GUID диска.
Разработчик столкнулся с ошибкой `ERROR_INVALID_NAME` при попытке получить GUID диска в Delphi из-за несоответствия типа кодировки строковых аргументов функции `GetVolumeNameForVolumeMountPoint`.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.