Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Запуск приложения под Win7, Только в режиме совместимости с XP 
V
    Опции темы
Doga
Дата 7.6.2012, 18:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 115
Регистрация: 20.12.2007
Где: Россия, Обнинск

Репутация: нет
Всего: нет



Имеется приложение, которое осуществляет мониторинг изменений в каком-либо каталоге. Для этого используется API-функция ReadDirectoryChangesW, запускаемая в отдельном потоке в асинхронном режиме. Для ожидания изменений используется другая API-функция - WaitForMultipleObjects, которой передаются хендлы двух событий - изменения в каталоге и завершения потока.

При запуске приложения под WinXP всё работает прекрасно.  При запуске приложения под Win7, при любом изменении в наблюдаемом каталоге, приложение перестает отвечать системе. Приложение работает под Win7 только, если установить для него режим совместимиости с WinXP или запустить его от имени администратора.

Как заставить работать это приложение в Win7 без дополнительных ручных манипуляций?
PM MAIL WWW   Вверх
feodorv
Дата 7.6.2012, 20:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(Doga @  7.6.2012,  19:22 Найти цитируемый пост)
приложение перестает отвечать системе

Вы проверяете возвращаемое значение от WaitForMultipleObjects на ошибку? Если да, то какова ошибка (скорее всего - недостаточность прав), и какова реакция приложения на эту ошибку (если не реагировать, то цикл пожрёт все ресурсы)?


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Doga
Дата 8.6.2012, 11:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 115
Регистрация: 20.12.2007
Где: Россия, Обнинск

Репутация: нет
Всего: нет



Прошу прощения, но только сегодня выяснилось, что проблема имеется только при запуске приложения в Win7 x64. Подозреваю, что эта проблема может быть актуальна и для других 64-разрядных ОС Windows, в частности для Vista.  
В Win7 x32 всё в порядке, никаких дополнительных настроек не требуется. 

Да, конечно, ошибки обрабатываются. Но, похоже, дело до них просто не доходит. Вот код потока, занимающегося мониторингом каталога.

Его запуск осуществляется вызовом функции bool __fastcall RunChangesInformer(TForm *AInformedForm, AnsiString AWorkFolder)
остановка - вызовом функции void __fastcall StopChangesInformer(void).

Информация об изменениях в каталоге или ошибках передаётся в главную форму с помощью сообщений WM_FILE_CHANGE  (WM_USER+0x033A).

Проект компилируется в WinXP SP3 x32,  Embarcadero RAD Studio 2010.

ChangesInformer.h
Код

//---------------------------------------------------------------------------
#ifndef ChangesInformerUnitH
#define ChangesInformerUnitH
//---------------------------------------------------------------------------
#include <Classes.hpp>
//---------------------------------------------------------------------------
//Информирует окно, запустившее поток, о изменении какого-либо файла в рабочем каталоге
//WPARAM = char *FullFileName
//LPARAM = unsigned int ActionCode или, если WPARAM = 0, или int ErrorCode (получен с помощью GetLastError) в противном случае
#define WM_FILE_CHANGE (WM_USER+0x033A)
//---------------------------------------------------------------------------
//При мониторинге изменений в сетевом каталоге,
//размер InfoSize не должен превышать 64 КБайта !!!
//Т.е. максимальный размер UDP-пакета.
#define InfoSize 8192
//---------------------------------------------------------------------------
bool __fastcall RunChangesInformer(TForm *AInformedForm, AnsiString AWorkFolder);
void __fastcall StopChangesInformer(void);
//---------------------------------------------------------------------------
class TChangesInformer : public TThread
{
  private:

  protected:
    TForm *FInformedForm;

    HANDLE FFolderHandle;

    HANDLE FEventArray[2];

    char *FFileInfoBuffer;

    void __fastcall Execute();
    void __fastcall SendChangeInfo(void);
    void __fastcall TerminateInformer(TObject *Sender);

  public:
    __fastcall TChangesInformer(TForm *AInformedForm, HANDLE AFolderHandle, char *AFileInfoBuffer, HANDLE ATerminateEvent, HANDLE AChangeEvent);
};
//---------------------------------------------------------------------------
#endif


ChangesInformer.cpp
Код

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#include "ChangesInformerUnit.h"
#include <Forms.hpp>
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
//Хендл события для завершения потока
HANDLE TerminateEvent = NULL;
//Хендл события изменения в каталоге
HANDLE ChangeEvent    = NULL;
//Хендл контролируемого каталога
HANDLE FolderHandle   = NULL;
//Информационный буфер
char *FileInfoBuffer;
//---------------------------------------------------------------------------
TChangesInformer *ChangesInformer = NULL;
//---------------------------------------------------------------------------
bool __fastcall RunChangesInformer(TForm *AInformedForm, AnsiString AWorkFolder)
{
  bool Result = false;

  //Остановка предыдущего потока,
  //если он ещё работает...
  StopChangesInformer();

  if (DirectoryExists(AWorkFolder))
  {
    //Хендл контролируемого каталога
    FolderHandle = CreateFile
    (
      AWorkFolder.c_str(),
      FILE_LIST_DIRECTORY,
      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
      NULL,
      OPEN_EXISTING,
      FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
      NULL
    );

    //Хендл каталога получен, всё в порядке...
    if (FolderHandle != INVALID_HANDLE_VALUE)
    {
      //Создание хендлов событий:
      //завершения потока и
      //изменения в каталоге
      TerminateEvent = CreateEvent(NULL, false, false, TEXT("TerminateEvent"));
      ChangeEvent    = CreateEvent(NULL, false, false, TEXT("ChangeEvent"));

      //Директива для приведения вырвнивания
      //блоков памяти (Data Alignment)
      //к DWORD (32 бита или 4 байта)
      //Необходимо для корректной работы буфера
      //с API-функцией ReadDirectoryChangesW(...)
      #pragma pack(4)
      //Информационный буфер для записи изменений в каталоге
      FileInfoBuffer = new char[InfoSize];
      ZeroMemory(FileInfoBuffer, InfoSize);

      //Создание и запуск нового потока наблюдения за катологом
      if (TerminateEvent && ChangeEvent)
      {
        ChangesInformer = new TChangesInformer(AInformedForm, FolderHandle, FileInfoBuffer, TerminateEvent, ChangeEvent);
        Result = true;
      }
    }
  }

  //Если запустить поток не удалось,
  //удаляем всё, что успели насоздавать...
  if (!Result)
  {
    ChangesInformer = NULL;

    if (FileInfoBuffer)
    {
      delete [] FileInfoBuffer;
      FileInfoBuffer = NULL;
    }

    if (TerminateEvent)
    {
      CloseHandle(TerminateEvent);
      TerminateEvent = NULL;
    }

    if (ChangeEvent)
    {
      CloseHandle(ChangeEvent);
      ChangeEvent = NULL;
    }

    if (FolderHandle)
    {
      CloseHandle(FolderHandle);
      FolderHandle = NULL;
    }
  }

  return Result;
}
//---------------------------------------------------------------------------
void __fastcall StopChangesInformer(void)
{
  if (ChangesInformer)
  {
    //Нормальное завершение потока
    if (TerminateEvent)
    {
      //Выход из потока с помощью генерации внешнего события
      SetEvent(TerminateEvent);

      //Ожидание штатного завершения потока
      ChangesInformer->WaitFor();
    }
    
    //Удаление потока
    delete ChangesInformer;
    ChangesInformer = NULL;
  }

  //Закрытие хендлов событий:
  //завершения потока и
  //изменения в каталоге
  if (TerminateEvent)
  {
    CloseHandle(TerminateEvent);
    TerminateEvent = NULL;
  }

  if (ChangeEvent)
  {
    CloseHandle(ChangeEvent);
    ChangeEvent = NULL;
  }

  //Очистка буфера
  if (FileInfoBuffer)
  {
    delete [] FileInfoBuffer;
    FileInfoBuffer = NULL;
  }
}
//---------------------------------------------------------------------------
__fastcall TChangesInformer::TChangesInformer(TForm *AInformedForm, HANDLE AFolderHandle, char *AFileInfoBuffer, HANDLE ATerminateEvent, HANDLE AChangeEvent)
  : TThread(false)
{
  FreeOnTerminate = false;
  Priority = tpNormal;

  FInformedForm   = AInformedForm;
  FFolderHandle   = AFolderHandle;
  FFileInfoBuffer = AFileInfoBuffer;
  FEventArray[0]  = ATerminateEvent;
  FEventArray[1]  = AChangeEvent;
}
//---------------------------------------------------------------------------
void __fastcall TChangesInformer::Execute()
{
  //---- Place thread code here ----
  if (FInformedForm && FFolderHandle && FFileInfoBuffer && FEventArray[0] && FEventArray[1])
  {
    OVERLAPPED OverlappedInfo;
    OverlappedInfo.hEvent = FEventArray[1]; //AChangeEvent

    bool CanContinue = true;

    long int ErrorCode;
    unsigned int WaitResult;
    unsigned long BufferInfoSize = InfoSize;
    unsigned long BytesReturned;

    while (CanContinue)
    {
      //Запуск функции мониторинга изменений
      //в каталоге в асинхронном режиме
      CanContinue = (bool)ReadDirectoryChangesW
      (
        FolderHandle,
        (void *)FileInfoBuffer,
        BufferInfoSize,
        false,
        FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_ACCESS |
        FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE |
        FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY,
        &BytesReturned,  //При асинхронном вызове возвращаемое в lpBytesReturned значение не определено
        &OverlappedInfo,
        NULL
      );

      //Продолжим, если вызов ReadDirectoryChangesW
      //завершился без ошибок
      if (CanContinue)
      {
        WaitResult = WaitForMultipleObjects(2, &FEventArray[0], false, INFINITE);

        switch (WaitResult)
        {
          //Произошло событие для EventArray[0], т.е. TerminateEvent - завершение потока по внешенему сигналу.
          case WAIT_OBJECT_0:
            CanContinue = false;
            break;

          //Произошло событие для EventArray[1], т.е. ChangeEvent - надо просмотреть содержимое буфера FileInfoBuffer.
          //Далее - повтор цикла
          case WAIT_OBJECT_0 + 1:
            {
              ErrorCode = GetLastError();

              //Если нет ошибки
              if (ErrorCode == ERROR_SUCCESS)
              {
                FILE_NOTIFY_INFORMATION *FileNotifyInfo;
                unsigned int NextOffset = 0;

                //Получение всех блоков информации из буфера
                do
                {
                  FILE_NOTIFY_INFORMATION *FileNotifyInfo = reinterpret_cast< FILE_NOTIFY_INFORMATION * > (FileInfoBuffer + NextOffset);

                  if (FileNotifyInfo)
                  {
                    FileNotifyInfo->FileName[FileNotifyInfo->FileNameLength/2] = 0;

                    AnsiString ChangedFile = FileNotifyInfo->FileName;

                    //FileNotifyInfo->Action, со значением FILE_ACTION_MODIFIED
                    //даёт СЛИШКОМ общее представление о происходящем
                    long int ActionCode = (long int)FileNotifyInfo->Action;

                    SendMessage(FInformedForm->Handle, WM_FILE_CHANGE, reinterpret_cast< WPARAM > (ChangedFile.c_str()), ActionCode);

                    //Смещение адреса для следующего блока информации
                    NextOffset = FileNotifyInfo->NextEntryOffset;
                  }
                }
                while (NextOffset);

                CanContinue = true;
              }
              else
              {
                //Завершаем поток
                SendMessage(FInformedForm->Handle, WM_FILE_CHANGE, 0, ErrorCode );
                CanContinue = false;
              }
            }
            break;

          //За истёкший период ничего не случилось, повтор цикла ожидания
          //Вообще то, при bWaitAll == false и dwMilliseconds == INFINITE
          //этого никогда не случится...
          case WAIT_TIMEOUT:
            CanContinue = true;
            break;

          //Если ошибки, в том числе:
          //WAIT_ABANDONED_0
          //WAIT_ABANDONED_0 + 1
          //WAIT_FAILED
          //то принудительное завершение потока
          default:
            ErrorCode = GetLastError();
            SendMessage(FInformedForm->Handle, WM_FILE_CHANGE, 0, ErrorCode );
            CanContinue = false;
            break;
        }
      }
      else
      {
        ErrorCode = GetLastError();  //If the network redirector or the target file system does not support this operation, the function fails with ERROR_INVALID_FUNCTION
        SendMessage(FInformedForm->Handle, WM_FILE_CHANGE, 0, ErrorCode );
        CanContinue = false;
      }
    }
  }
}
//---------------------------------------------------------------------------


Это сообщение отредактировал(а) Doga - 8.6.2012, 11:21
PM MAIL WWW   Вверх
xvr
Дата 8.6.2012, 13:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 40
Всего: 223



Замечания по коду:
  •  #pragma pack(4) работает только для определения структур, но никоим образом не для оператора new
  •  (строка 210 в cpp файле) - получение результата от ReadDirectoryChangesW (в этом случае) осуществляется с помощью GetOverlappedResult, а никоим образом не через GetLastError


Это сообщение отредактировал(а) xvr - 8.6.2012, 13:55
PM MAIL   Вверх
Doga
Дата 8.6.2012, 18:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 115
Регистрация: 20.12.2007
Где: Россия, Обнинск

Репутация: нет
Всего: нет



Без  #pragma pack(4) программа реагирует только на самое первое изменение в каталоге после начала наблюдения. Остальные изменения для него тихо пропадают. Вообще то, эту строку я поставил как страховку, если в опциях проекта установлено другое выравнивание. Если существует правильный спосб выделить память для FileInfoBuffer с выравниванием в 4 байта - буду безумно рад с ним познакомится  smile  .

GetOverlappedResult с последним параметром BOOL bWait, равным TRUE, не возвращает управление программе, пока в наблюдаемом каталоге не произойдет какое-либо изменение. Это значит, что поток наблюдения можно будет завершить не тогда, когда нужно, а только после этого изменения. Это меня не устраивает. Вообще, MSDN говорит о ReadDirectoryChangesW так:
Цитата

If the function succeeds, the return value is nonzero. For synchronous calls, this means that the operation succeeded. For asynchronous calls, this indicates that the operation was successfully queued.

Или этого не достаточно?

Нашел ошибку у себя, в обработчике сообщений потока. Теперь известен код ошибки получаемый при попытке запуска процесса наблюдения в каталогах под Win7 х64:
87,  Параметр задан неверно

Что бы это значило?

Это сообщение отредактировал(а) Doga - 8.6.2012, 18:37
PM MAIL WWW   Вверх
Dem_max
Дата 8.6.2012, 18:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1780
Регистрация: 12.4.2007

Репутация: 16
Всего: 39



ошибка 87
Цитата

ERROR_INVALID_PARAMETER
87 (0x57)

The parameter is incorrect.



--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
Doga
Дата 8.6.2012, 19:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 115
Регистрация: 20.12.2007
Где: Россия, Обнинск

Репутация: нет
Всего: нет



The parameter is incorrect. Параметр задан неверно. Масло маслянное.   smile 

Делать то что?


PM MAIL WWW   Вверх
Dem_max
Дата 8.6.2012, 19:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1780
Регистрация: 12.4.2007

Репутация: 16
Всего: 39



Задавать правильный параметр


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
Doga
Дата 8.6.2012, 20:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 115
Регистрация: 20.12.2007
Где: Россия, Обнинск

Репутация: нет
Всего: нет



Так вот оно чё, Михалыч!  smile 
PM MAIL WWW   Вверх
feodorv
Дата 8.6.2012, 21:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(Doga @  8.6.2012,  19:36 Найти цитируемый пост)
Если существует правильный спосб выделить память для FileInfoBuffer с выравниванием в 4 байта - буду безумно рад с ним познакомится

Выделяемая память всегда выровнена, и, по-моему, даже по 16 байтной границе. А что, есть какие-то указания, что это не так?

Цитата(Doga @  8.6.2012,  12:11 Найти цитируемый пост)
                    FileNotifyInfo->FileName[FileNotifyInfo->FileNameLength/2] = 0;

А не портится таким образом следующая запись?

Цитата(Doga @  8.6.2012,  19:36 Найти цитируемый пост)
GetOverlappedResult с последним параметром BOOL bWait, равным TRUE, не возвращает управление программе, пока в наблюдаемом каталоге не произойдет какое-либо изменение. 

Ну так можно же вызвать с FALSE. В конце концов, событие произошло или нет?

Цитата(Doga @  8.6.2012,  19:36 Найти цитируемый пост)
Нашел ошибку у себя, в обработчике сообщений потока. Теперь известен код ошибки получаемый при попытке запуска процесса наблюдения в каталогах под Win7 х64:

А поподробнее?  smile 


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
xvr
Дата 9.6.2012, 12:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 40
Всего: 223



Цитата(Doga @  8.6.2012,  18:36 Найти цитируемый пост)
GetOverlappedResult с последним параметром BOOL bWait, равным TRUE, не возвращает управление программе, пока в наблюдаемом каталоге не произойдет какое-либо изменение. Это значит, что поток наблюдения можно будет завершить не тогда, когда нужно, а только после этого изменения. 
GetOverlappedResult нужно звать после WaitFor*Object. У вас WaitFor* есть, а GetOverlappedResult после него нету


Цитата(Doga @  8.6.2012,  18:36 Найти цитируемый пост)
Или этого не достаточно?

Для 'successfully queued' достаточно, а для последующего получения результатов - нет

Цитата(Doga @  8.6.2012,  18:36 Найти цитируемый пост)
еперь известен код ошибки получаемый при попытке запуска процесса наблюдения

В какой именно функции это происходит?

PM MAIL   Вверх
Doga
Дата 9.6.2012, 15:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 115
Регистрация: 20.12.2007
Где: Россия, Обнинск

Репутация: нет
Всего: нет



Разобрался  smile  .

Причина была в вызове GetLastError() на 211ой строке. 

В x32, возвращаемый ею результат равен ERROR_SUCCESS. В x64, она выдаёт ERROR_INVALID_PARAMETER. Не понимаю такой разницы в реакции этих ОС.  smile 

В Win7 x64 всё заработало, когда я просто отключил эту строку. 

Этот GetLastError() на 211ой строке, по совету  xvr и feodorv заменил на GetOverlappedResult. Правда, наличие или отсутсвие GetOverlappedResult, визуально по крайней мере, не повлияло на работу приложения. Но раз надо - так надо.  smile 

Всем спасибо!  smile 

После всех изменений, метод потока наблюдения Execute() выглядит так:
Код

void __fastcall TChangesInformer::Execute()
{
  if (FInformedForm && FFolderHandle && FFileInfoBuffer && FEventArray[0]/*ATerminateEvent*/ && FEventArray[1]/*AChangeEvent*/)
  {
    OVERLAPPED OverlappedInfo;
    ZeroMemory(&OverlappedInfo, sizeof(OverlappedInfo));
    OverlappedInfo.hEvent = FEventArray[1]; //AChangeEvent

    bool CanContinue = true;

    long int ErrorCode;
    unsigned int WaitResult;
    unsigned long BufferInfoSize = InfoSize;
    unsigned long BytesReturned;

    while (CanContinue)
    {
      //Запуск функции мониторинга изменений
      //в каталоге в асинхронном режиме
      ZeroMemory(FFileInfoBuffer, BufferInfoSize);
      CanContinue = (bool)ReadDirectoryChangesW
      (
        FFolderHandle,
        (void *)FFileInfoBuffer,
        BufferInfoSize,
        false,
        FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_ACCESS |
        FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE |
        FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY,
        &BytesReturned,  //При асинхронном вызове возвращаемое в lpBytesReturned значение не определено
        &OverlappedInfo,
        NULL
      );

      //Продолжим, если вызов ReadDirectoryChangesW
      //завершился без ошибок
      if (CanContinue)
      {
        WaitResult = WaitForMultipleObjects(2, &FEventArray[0], false, INFINITE);

        switch (WaitResult)
        {
          //Произошло событие для EventArray[0], т.е. TerminateEvent - завершение потока по внешенему сигналу.
          case WAIT_OBJECT_0:
            CanContinue = false;
            break;

          //Произошло событие для EventArray[1], т.е. ChangeEvent - надо просмотреть содержимое буфера FFileInfoBuffer.
          //Далее - повтор цикла
          case WAIT_OBJECT_0 + 1:
            {
              //Проверка результата работы функции ReadDirectoryChangesW
              CanContinue = (bool)GetOverlappedResult(FFolderHandle, &OverlappedInfo, &BytesReturned, false);

              //Если нет ошибки
              if (CanContinue)
              {
                FILE_NOTIFY_INFORMATION *FileNotifyInfo;
                unsigned int NextOffset = 0;

                //Получение всех блоков информации из буфера
                do
                {
                  FileNotifyInfo = reinterpret_cast< FILE_NOTIFY_INFORMATION * > (FFileInfoBuffer + NextOffset);

                  if (FileNotifyInfo)
                  {
                    AnsiString ChangedFile = FileNotifyInfo->FileName;

                    //FileNotifyInfo->Action, со значением FILE_ACTION_MODIFIED
                    //даёт СЛИШКОМ общее представление о происходящем.
                    //В частности, открытие файла на локальном диске (чтение)
                    //и его реальное изменение определяются одним и тем же FILE_ACTION_MODIFIED.
                    //Открытие файла (чтение) на сетевых дисках изменений в каталоге не вызывает.

                    //Что бы обработчик этих собщений не тормозил, лучше, наверное, использовать PostMessage.
                    //Если передача сообщения будет осуществляться с помощью PostMessage,
                    //то ChangedFile.c_str() использовать нельзя !!!
                    SendMessage(FInformedForm->Handle, WM_FILE_CHANGE, reinterpret_cast< WPARAM > (ChangedFile.c_str()), (long int)FileNotifyInfo->Action);

                    //Смещение адреса для следующего блока информации
                    NextOffset += FileNotifyInfo->NextEntryOffset;
                  }
                }
                while (FileNotifyInfo->NextEntryOffset);

                CanContinue = true;
              }
              else
              {
                //Завершение потока
                ErrorCode = GetLastError();
                SendMessage(FInformedForm->Handle, WM_FILE_CHANGE, 0, ErrorCode);
                CanContinue = false;
              }
            }
            break;

          //За истёкший период ничего не случилось, повтор цикла ожидания
          //Вообще то, при bWaitAll == false и dwMilliseconds == INFINITE
          //этого никогда не случится...
          case WAIT_TIMEOUT:
            CanContinue = true;
            break;

          //Если ошибки, в том числе:
          //WAIT_ABANDONED_0
          //WAIT_ABANDONED_0 + 1
          //WAIT_FAILED
          //то принудительное завершение потока
          default:
            ErrorCode = GetLastError();
            SendMessage(FInformedForm->Handle, WM_FILE_CHANGE, 0, ErrorCode);
            CanContinue = false;
            break;
        }
      }
      else
      {
        ErrorCode = GetLastError();  //If the network redirector or the target file system does not support this operation, the function fails with ERROR_INVALID_FUNCTION
        SendMessage(FInformedForm->Handle, WM_FILE_CHANGE, 0, ErrorCode);
        CanContinue = false;
      }
    }
  }
}
 

PM MAIL WWW   Вверх
xvr
Дата 9.6.2012, 15:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 40
Всего: 223



Цитата(Doga @  9.6.2012,  15:01 Найти цитируемый пост)
Причина была в вызове GetLastError() на 211ой строке. 

В x32, возвращаемый ею результат равен ERROR_SUCCESS. В x64, она выдаёт ERROR_INVALID_PARAMETER. Не понимаю такой разницы в реакции этих ОС.

Я скажу больше - она вообще имеет право возвращать что угодно. LastError от кого она должна была по вашему возвращать? Ближайший завершенный системный вызов был WaitForMultipleObjects (на 197 строке), но он завершился успешно, т.е. LastError статус не менялся, и остался от неизвестно кого. В одном можно быть уверенным - это не статус от ReadDirectoryChangesW, т.к. все функции в Win32 API могут менять LastError статус только пока они исполняются, а не после того (даже если они работают в Overlapped режиме)


Это сообщение отредактировал(а) xvr - 9.6.2012, 15:08
PM MAIL   Вверх
Doga
Дата 9.6.2012, 15:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 115
Регистрация: 20.12.2007
Где: Россия, Обнинск

Репутация: нет
Всего: нет



Это я уже понял  smile 
PM MAIL WWW   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.1107 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.