Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: BCB++ и WinAPI  (Прочитано 1013 раз)
0 Пользователей и 1 Гость смотрят эту тему.
NeferSky
Участник

ru
Offline Offline
Бессмертный


« : 11-11-2016 09:36 » 

Добрый день всем.
Давно уже пишу на Делфях, но ничто не вечно. Это время пришло. Начал осваивать С++.
Для примеров перевожу код своих проектов с Паскаля на С. Внезапно - запутался с указателями при использовании WinAPI. А именно - есть у меня функция. В Делфях работает, в BCB - нет. Хватаю AV на функции Move(). Чую, там дело в двойном указателе void **InfoPtr, но что я не так с ним делаю - не пойму. Разыменовываю, вроде, правильно... тип у него - тоже, как будто подходящий, и Move() ожидает там указатель... В чем может быть дело?

Pascal code:
Код:
function GetFullFileVersion(const FileName: string): string;
var
  InfoSize, puLen: DWORD;
  Pt, InfoPtr: Pointer;
  VerInfo: TVSFixedFileInfo;
begin
  InfoSize := GetFileVersionInfoSize(PChar(FileName), puLen);
  FillChar(VerInfo, SizeOf(TVSFixedFileInfo), 0);

  if InfoSize > 0 then
  begin
    GetMem(Pt, InfoSize);
    GetFileVersionInfo(PChar(FileName), 0, InfoSize, Pt);

    VerQueryValue(Pt, '\', InfoPtr, puLen);
    Move(InfoPtr^, VerInfo, SizeOf(TVSFixedFileInfo));
    FreeMem(Pt);

    Result := Format('%u.%u.%u.%u', [HiWord(VerInfo.dwProductVersionMS),
      LoWord(VerInfo.dwProductVersionMS), HiWord(VerInfo.dwProductVersionLS),
        LoWord(VerInfo.dwProductVersionLS)]);
  end
  else
    Result := '';
end;

C++ code:
Код:
String __fastcall TNsUtils::GetFullFileVersion(const String FileName)
{
  unsigned long *puLenLong, InfoSize;
  unsigned int *puLenInt;
  void *Pt;
  void **InfoPtr;
  TVSFixedFileInfo *VerInfo;

  InfoSize = GetFileVersionInfoSize(FileName.c_str(), puLenLong);

  if (InfoSize > 0)
  {
    Pt = malloc(InfoSize);
    GetFileVersionInfo(FileName.c_str(), 0, InfoSize, Pt);

    memset(VerInfo, sizeof(TVSFixedFileInfo), 0);

    VerQueryValue(Pt, "\\", InfoPtr, puLenInt);
    Move(*InfoPtr, VerInfo, sizeof(TVSFixedFileInfo));  // Здесь падает с AV
    free(Pt);

    TVarRec args[4] = {HIWORD(VerInfo->dwProductVersionMS),
      LOWORD(VerInfo->dwProductVersionMS),
      HIWORD(VerInfo->dwProductVersionLS),
      LOWORD(VerInfo->dwProductVersionLS)};
    String Result = Format("%u.%u.%u.%u", args, 3);
    return Result;
  }
  else
  {
    return "";
  }
}
Записан

Не тронь налаженный механизм, и он тебя не подведет.
Делать надо хорошо, а плохо - само получится.
darkelf
Молодой специалист

ua
Offline Offline

« Ответ #1 : 11-11-2016 10:24 » 

Давно уже пишу на Делфях, но ничто не вечно. Это время пришло. Начал осваивать С++.
Для примеров перевожу код своих проектов с Паскаля на С.

Досконально не разбирался, но по-моему, скорее всего, должно быть что-то типа такого:
Код: (C++)
String __fastcall TNsUtils::GetFullFileVersion(const String FileName)
{
  unsigned long *puLenLong, InfoSize;
  unsigned int *puLenInt;
  void *Pt;
  void *InfoPtr;
  TVSFixedFileInfo *VerInfo;

  InfoSize = GetFileVersionInfoSize(FileName.c_str(), puLenLong);

  if (InfoSize > 0)
  {
    Pt = malloc(InfoSize);
    GetFileVersionInfo(FileName.c_str(), 0, InfoSize, Pt);

    memset(VerInfo, sizeof(TVSFixedFileInfo), 0);

    VerQueryValue(Pt, "\\", &InfoPtr, puLenInt);
    Move(InfoPtr, VerInfo, sizeof(TVSFixedFileInfo));  // Здесь не должно уже падать с AV
    free(Pt);

    TVarRec args[4] = {HIWORD(VerInfo->dwProductVersionMS),
      LOWORD(VerInfo->dwProductVersionMS),
      HIWORD(VerInfo->dwProductVersionLS),
      LOWORD(VerInfo->dwProductVersionLS)};
    String Result = Format("%u.%u.%u.%u", args, 3);
    return Result;
  }
  else
  {
    return "";
  }
}
Записан
NeferSky
Участник

ru
Offline Offline
Бессмертный


« Ответ #2 : 11-11-2016 10:41 » 

darkelf, все равно AV. Я, пожалуй, дома на другой версии билдера еще попробую перекомпилить, чтобы исключить какие-нибудь настройки самой IDE.
Записан

Не тронь налаженный механизм, и он тебя не подведет.
Делать надо хорошо, а плохо - само получится.
Aether
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 11-11-2016 10:45 » 

https://msdn.microsoft.com/en-us/library/windows/desktop/ms647464(v=vs.85).aspx

Цитата
BOOL WINAPI VerQueryValue(
  _In_  LPCVOID pBlock,
  _In_  LPCTSTR lpSubBlock,
  _Out_ LPVOID  *lplpBuffer,
  _Out_ PUINT   puLen
);
Код:
...
void *InfoPtr;
...
VerQueryValue(Pt, "\\", &InfoPtr, puLenInt);
...
Move(InfoPtr, VerInfo, sizeof(TVSFixedFileInfo));
...
void ** InfoPtr, вероятно было бы корректнее.
Прототип Move откуда брать непонятно.
Лучше протестировать на каком этапе что и где получается. И, код выявления ошибок после malloc и прочих функций добавить.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #4 : 11-11-2016 10:52 » 

NeferSky, никакая версия не спасет от незнания языка. Включи больше варнингов. Выполни проход функции пошагово:
1) найди, где падает
2) посмотри, что ты передаешь

И да, Win32 API писали уроды. С этим надо свыкнуться.
Цитата
LPVOID  *lplpBuffer
LPVOID - это тип указателя из дебрей винды, эквивалентный void*.
LPVOID* эквивалентен void**.
« Последнее редактирование: 11-11-2016 10:55 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.

Хз, я не очень просто не очень во всё это верю, во всякие там сатурны и прочую поебень.
zubr
Команда клуба

by
Offline Offline
Пол: Мужской

« Ответ #5 : 11-11-2016 10:54 » 

TVSFixedFileInfo *VerInfo;
Где выделение памяти под структуру, раз она объявлена как указатель. Или тогда:
TVSFixedFileInfo VerInfo;
Код:
String __fastcall TNsUtils::GetFullFileVersion(const String FileName)
{
  unsigned long puLenLong, InfoSize;
  unsigned int puLenInt;
  void *Pt;
  void *InfoPtr;
  TVSFixedFileInfo VerInfo;

  InfoSize = GetFileVersionInfoSize(FileName.c_str(), &puLenLong);

  if (InfoSize > 0)
  {
    Pt = malloc(InfoSize);
    GetFileVersionInfo(FileName.c_str(), 0, InfoSize, Pt);

    memset(&VerInfo, sizeof(TVSFixedFileInfo), 0);

    VerQueryValue(Pt, "\\", &InfoPtr, &puLenInt);
    Move(InfoPtr, &VerInfo, sizeof(TVSFixedFileInfo));
« Последнее редактирование: 11-11-2016 10:56 от zubr » Записан
Aether
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 11-11-2016 11:02 » 

https://msdn.microsoft.com/en-us/library/windows/desktop/ms647005(v=vs.85).aspx
Цитата
DWORD WINAPI GetFileVersionInfoSize(
  _In_      LPCTSTR lptstrFilename,
  _Out_opt_ LPDWORD lpdwHandle
);
...
lpdwHandle [out, optional]
Type: LPDWORD
A pointer to a variable that the function sets to zero.
...
zubr уже поправил, но всё же. Как понял второй аргумент требует передать адрес переменной, которая будет сброшена в ноль. (Зачем?) Под такую переменную память должна быть выделена, если просто передать указатель, то функция попытается сбросить в ноль не пойми что.
Записан
zubr
Команда клуба

by
Offline Offline
Пол: Мужской

« Ответ #7 : 11-11-2016 11:40 » 

Aether,
1. Проблема у топикстартера не в этой функции, а в том, что он в функции Move использует указатель на невыделенный блок памяти.
2. Касаемо GetFileVersionInfoSize, мне тоже не совсем понятно назначение параметра lpdwHandle. Наверно разаработчики что то предусматривали на будущее. Но пока данный параметр, бессмыслен там, имхо. Что касается выделения памяти под данную переменную, так если объявлена переменная типа DWORD -  то память в стеке 4 байта под нее уже выделена, а функции указывается указатель на ячейку стека, где эта память выделена.
Записан
NeferSky
Участник

ru
Offline Offline
Бессмертный


« Ответ #8 : 11-11-2016 11:41 » 

Цитата
BOOL WINAPI VerQueryValue(
  _In_  LPCVOID pBlock,
  _In_  LPCTSTR lpSubBlock,
  _Out_ LPVOID  *lplpBuffer,
  _Out_ PUINT   puLen
);
Видел, спасибо.
void ** InfoPtr, вероятно было бы корректнее.
void ** InfoPtr мне тоже кажется корректнее. Я так и сделал сразу, если обратили внимание.
Прототип Move откуда брать непонятно.
Move(const * void Source, void * Dest, int Count), как предлагает BCB...
Move(const Source, var Dest, count: Integer), как предлагает Delphi.
Лучше протестировать на каком этапе что и где получается. И, код выявления ошибок после malloc и прочих функций добавить.
Пошаговым выполнением смотрел - все, вроде, ровно было. Только этот двойной указатель отследить не смог.

NeferSky, никакая версия не спасет от незнания языка.
Ну так и говорю - переучиваюсь с Делфей. Точнее, С++ вторым языком осваивать начал.
LPVOID - это тип указателя из дебрей винды, эквивалентный void*.
LPVOID* эквивалентен void**.
Видел, спасибо.

TVSFixedFileInfo *VerInfo;
Где выделение памяти под структуру, раз она объявлена как указатель. Или тогда:
TVSFixedFileInfo VerInfo;
Так эээ... memset(VerInfo, sizeof(TVSFixedFileInfo), 0) не выделение памяти?
Ваш код помог, спасибо.

Записан

Не тронь налаженный механизм, и он тебя не подведет.
Делать надо хорошо, а плохо - само получится.
zubr
Команда клуба

by
Offline Offline
Пол: Мужской

« Ответ #9 : 11-11-2016 11:59 » 

memset - это не выделение памяти, а инициализация ее опреленными байтами, в твоем случае 0.
Записан
NeferSky
Участник

ru
Offline Offline
Бессмертный


« Ответ #10 : 11-11-2016 12:14 » 

Ааа! То есть, это заполнение уже выделенного куска памяти? Тогда ясно. Ошибку понял, спасибо за пояснение.
Записан

Не тронь налаженный механизм, и он тебя не подведет.
Делать надо хорошо, а плохо - само получится.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines