На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! user posted image
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.

Соблюдайте общие правила форума

Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как запустить программу/файл? (и дождаться ее завершения)
5. Как перехватить API-функции, поставить hook? (перехват сообщений от мыши, клавиатуры - внедрение в удаленное адресное прстранство)
... (продолжение следует) ...

Внимание:
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки - бан.
Мат в разделе - бан на три месяца...

Полезные ссылки:
user posted image MSDN Library user posted image FAQ раздела user posted image Поиск по разделу user posted image Как правильно задавать вопросы


Выразить свое отношение к модераторам раздела можно здесь: user posted image Rouse_, user posted image Krid

Модераторы: Rouse_, Krid
  
> Delphi 2010, WinAPI-функция GetDiskFreeSpaceEx
    Всем привет. У меня такая проблема:
    Необходимо вывести информацию о диске C:\ с помощью WinAPI-функции GetDiskFreeSpaceEx. Имеется следующий программный код:

    ExpandedWrap disabled
      procedure TForm1.Button1Click(Sender: TObject);
      var
        lpRootPathName:PChar;
        lpFreeBytesAvailable:PLargeInteger;
        lpTotalNumberOfBytes:PLargeInteger;
        lpTotalNumberOfFreeBytes:PLargeInteger;
      begin
        new(lpFreeBytesAvailable);
        new(lpTotalNumberOfBytes);
        new(lpTotalNumberOfFreeBytes);
        lpRootPathName:=StringToOleStr('C:\');
        if not Windows.GetDiskFreeSpaceEx(lpRootPathName,lpFreeBytesAvailable,
        lpTotalNumberOfBytes,lpTotalNumberOfFreeBytes) then
        begin
          lpFreeBytesAvailable^:=0;
          lpTotalNumberOfBytes^:=0;
          lpTotalNumberOfFreeBytes^:=0;
        end;
        ShowMessage('Диск С:'+#13#10+
        'lpFreeBytesAvailable = '+inttostr(lpFreeBytesAvailable^)+#13#10+
        'lpTotalNumberOfBytes = '+inttostr(lpTotalNumberOfBytes^)+#13#10+
        'lpTotalNumberOfFreeBytes = '+inttostr(lpTotalNumberOfFreeBytes^))
      end;


    После запуска программы и нажатия кнопки Button1 на экране появляется сообщение об ошибке:

    Project Project1.exe raised exception class EAccessViolation with message 'Access violation at address 004B3465 in module 'Project1.exe'. Read of address 00000008'.

    Как исправить ошибку, подскажите пожалуйста.
      ExpandedWrap disabled
        var
          lpRootPathName:PChar;
          lpFreeBytesAvailable: Int64;
          lpTotalNumberOfBytes: Int64;
          lpTotalNumberOfFreeBytes: Int64;
        begin
          lpRootPathName:=StringToOleStr('C:\');
          if not GetDiskFreeSpaceEx(lpRootPathName, lpFreeBytesAvailable,
          lpTotalNumberOfBytes, @lpTotalNumberOfFreeBytes) then
          begin
            lpFreeBytesAvailable := 0;
            lpTotalNumberOfBytes := 0;
            lpTotalNumberOfFreeBytes := 0;
          end;
          ShowMessage('Диск С:'+#13#10+
          'lpFreeBytesAvailable = '+inttostr(lpFreeBytesAvailable)+#13#10+
          'lpTotalNumberOfBytes = '+inttostr(lpTotalNumberOfBytes)+#13#10+
          'lpTotalNumberOfFreeBytes = '+inttostr(lpTotalNumberOfFreeBytes))
        Проверяй, выделяется ли вообще память. Потом, проверь, какого типа у тебя возвращается указатель из StringToOleStr(), по описанию там PWideChar, а у тебя в коде PChar, при этом тип, принимаемый GetDiskFreeSpaceEx, зависит от того, определен UNICODE или нет (плюс она с сишной декларацией, не помню, надо ли что-то делать в коде помимо вызова). И наконец, строку из StringToOleStr надо освобождать руками. То есть для начала поменяй тип у lpRootPathName на PWideChar.

        Добавлено
        MBo, то есть если в WinAPI в описании указатель, Дельфи нормально принимает имя переменной, и передает правильный указатель без всяких проблем?
          У меня использовано объявление из SysUtils
          ExpandedWrap disabled
             GetDiskFreeSpaceEx: function (Directory: PChar; var FreeAvailable, TotalSpace: TLargeInteger; TotalFree: PLargeInteger): Bool

          т.к. Windows модуль сразу не нашёлся (у меня нужно было WinApi.Windows написать)

          В любом случае - что var, что указательный тип параметра - в функцию передаётся адрес.
          Объявление с var это скрывает, и передавать нужно саму переменную (адрес её подставит компилятор)

          в Windows функция объявлена так:
          ExpandedWrap disabled
            function GetDiskFreeSpaceEx(lpDirectoryName: LPCWSTR;
              var lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes; lpTotalNumberOfFreeBytes: PLargeInteger): BOOL; stdcall;

          т.е. два бестиповых var-параметра, и нужно также передавать переменную, а не адрес, иначе получится двойное взятие адреса - будет использован адрес переменной
          ExpandedWrap disabled
            lpFreeBytesAvailable:PLargeInteger;
          , а не её содержимое
            опять попался на разыменовании указателей. Отвык уже :) спасибо.
              В справочной системе Delphi 2010 нет информации о SysUtils.GetDiskFreeSpaceEx. Чем SysUtils.GetDiskFreeSpaceEx отличается от Windows.GetDiskFreeSpaceEx? Как правильно вызвать Windows.GetDiskFreeSpaceEx?
                Точно так же
                  Цитата grh2 @
                  В справочной системе Delphi 2010 нет информации о SysUtils.GetDiskFreeSpaceEx.
                  Чем SysUtils.GetDiskFreeSpaceEx отличается от Windows.GetDiskFreeSpaceEx?
                  Как правильно вызвать Windows.GetDiskFreeSpaceEx?

                  На все три вопроса один ответ - смотри подсказку по параметрам функции при их наборе. Эта подсказка должна появляться автоматически (если не отключена в настройках), а также ее можно вызвать самому по Ctrl+Shift+пробел, когда курсор находится внутри скобок функции.
                  Если видишь, что вместо параметра-указателя (как в оригинальной АПИ-функции) использован var-параметр соответствующего типа (или вообще без указания типа), то нужно передавать не указатель на переменную, а саму переменную указанного типа.
                  Например, в GetDiskFreeSpaceEx последний параметр объявлен как указатель PLargeInteger, а второй и третий параметры заменены на var (либо TLargeInteger либо без указания типа - в этом случае вместо TLargeInteger можно использовать другой совместимый тип, например Int64). Поэтому в примере MBo все три передаваемые параметра объявляются как Int64 (или можно TLargeInteger), два из них передаются как есть (как переменные), а для третьего передается указатель на переменную - @lpTotalNumberOfFreeBytes. Если же использовать твой (весьма своеобразный) подход с объявлением переменных как указателей PLargeInteger с выделением под них памяти через new, то нужно наоборот, последний параметр передавать как есть (как указатель), а для первых двух использовать разьименование указателей - lpFreeBytesAvailable^, lpTotalNumberOfBytes^.

                  PS: Выделять память через new под простые переменные не нужно - так никто не делает. Локальные переменные "сами по себе" выделяются при вызове функции и уничтожаются при выходе из нее без всяких лишних телодвижений. И копия строки lpRootPathName:=StringToOleStr(..) тут совершенно не нужна - можно сразу передавать в функцию строковый литерал 'C:\' или переменную типа S:string с приведением ее типа к PChar(S)
                    Всем спасибо. Проблема решена с помощью функций DiskSize, DiskFree.
                    ExpandedWrap disabled
                      procedure TForm1.Button1Click(Sender: TObject);
                      var DS,DF:int64;
                      begin
                        DS:=DiskSize(3);DF:=DiskFree(3);
                        ShowMessage('Диск С:'+#13#10+'DiskSize = '+inttostr(DS)+#13#10+
                        'DiskFree = '+inttostr(DF))
                      end;
                    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                    0 пользователей:


                    Рейтинг@Mail.ru
                    [ Script execution time: 0,0322 ]   [ 17 queries used ]   [ Generated: 29.03.24, 05:19 GMT ]