Перейти из форума на сайт.

НовостиФайловые архивы
ПоискАктивные темыТоп лист
ПравилаКто в on-line?
Вход Забыли пароль? Первый раз на этом сайте? Регистрация
Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » Вопросы по Delphi (до версии 2009) - часть 6

Модерирует : ShIvADeSt

 Версия для печати • ПодписатьсяДобавить в закладки
Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125

Открыть новую тему     Написать ответ в эту тему

ShIvADeSt



Moderator
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Продолжение темы Вопросы по Delphi (до версии 2009) - часть 5

Познаем сами, помогаем другим...
Обсуждаем вопросы, не связанные с юникоидными версиями Delphi - для этого есть соответствующая тема (см. ссылки ниже).


 
Правила топика:
    Прежде чем спрашивать:
  1. Желательно изучить вопрос, попытаться найти ответ в прилагаемых мануалах, хелпах и анализируя исходники.
  2. Выполнить поиск по топику (открыть "Версия для печати" и поискать ответ там).
  3. Применить фильтр по разделу "Прикладное программирование". Ответы на многие старые вопросы могли быть даны в отдельных темах.
  4. Продумайте вопрос. На поверхностные вопросы вы получите поверхностные ответы, или вообще ответов не получите.
  5. Желательно указывать версии используемого компилятора и операционной системы.
    Прежде чем отвечать:
  1. Если не можете помочь, не мешайте.
  2. Если уж вы отвечаете на вопрос, давайте ответ по сути.
  3. Если вы не уверены, так и говорите! Ошибочный, но авторитетно звучащий ответ хуже, чем отсутствие ответа.
  4. Задавайте дополнительные вопросы, чтобы получить больше информации.
  • Отсутствие ответа не равносильно игнорированию - иногда участники форума просто не знают ответ. Повторная посылка вопроса не приветствуется. Посты типа "неужели никто не знает ответа..." или "может мне все-таки кто-нибудь ответит" недопустимы.  
  • Все большие куски кода (более 5 строк) оформляем в тег [morе] дабы уменьшить размер поста. FAQ по тегу [morе].


    Некоторые "родственные" топики:
     
  • Вопросы по Delphi (версии 2009-2010 Weaver)
  • Вопросы по компонентам для Delphi, C++ Builder
  • Использование DevExpress
  • Вопросы по Ehlib
  • Компоненты и утилиты для Delphi/BCB/FreePascal/Lazarus - только Open Source
  • Коммерческие компоненты и утилиты для Delphi/BCB
  • кабак программистов :)
     
    См. также: Некоторые полезные ресурсы о Delphi
     
    И старайтесь, чтобы ваш код не попал сюда :)

  • Всего записей: 3956 | Зарегистр. 29-07-2003 | Отправлено: 05:13 19-05-2010 | Исправлено: akaGM, 02:33 15-07-2020
    my610

    Junior Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Maks150988, никогда не используйте в структурах (как ваша, к примеру TRouteItem) типы String, WideString, которые потом планируется объявлять как XXX: array of TYyy; это 100% тро ло ло, который будет вылазить в самый непредсказуемый момент.
    лучше использовать указатели на строки (PChar, PWideChar), то есть в вашем случае:

    Код:
     
       PRouteItem = ^TRouteItem;
       TRouteItem = record  
         bGateWay    : Boolean;  
         bChecked    : Boolean;  
         pszRouteName: PWideChar;  
         dwNetWork   : DWORD;  
         dwNetMask   : DWORD;  
       end;
     

    и второе, как правильно заметили, лучше и удобнее использовать класс TList для хранения массива TRouteItem
     
    ps: SendDlgItemMessage удобнее юзать, чем SendMessage и GetDlgItem
     
    idItem:= SendDlgItemMessage(hWnd, IDC_MAIN_LISTBOX, LB_GETCURSEL, 0, 0);  
     
    Добавлено:
    R3Pa4eK

    Цитата:
    Как можно разблокировать файл?

    если имеется ввиду файл открытый монопольно каким нибудь процессом, то вот можно почитать о способах и подводных камнях.

    Всего записей: 34 | Зарегистр. 10-05-2011 | Отправлено: 02:37 22-09-2011 | Исправлено: my610, 02:43 22-09-2011
    rrromano



    Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    my610
     
    И всё равно лучше унаследовать класс и докрутить его. Безопаснее и удобнее в дальнейшем сопровождении.

    Всего записей: 283 | Зарегистр. 20-09-2006 | Отправлено: 10:04 22-09-2011
    Frodo_Torbins

    Silver Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    my610
    Цитата:
    никогда не используйте в структурах (как ваша, к примеру TRouteItem) типы String, WideString, которые потом планируется объявлять как XXX: array of TYyy; это 100% тро ло ло, который будет вылазить в самый непредсказуемый момент.
    А можно узнать, как такое возможно, и на какой версии делфи? Если бы речь шла о указателях, CopyMem и прочих не типобезопасных вещах, то еще понятно. А сами по себе массивы, записи и строки в любых комбинациях полностью безопасны.

    Всего записей: 2318 | Зарегистр. 24-05-2007 | Отправлено: 12:13 22-09-2011 | Исправлено: Frodo_Torbins, 12:15 22-09-2011
    DmitryKz

    Silver Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Вопрос, наверно, совсем не по теме... но как можно сделать мониторинг изменений в директории (и её поддиректориях)? Написать службу, это понятно, интересует способ реализации. Я так понимаю, этот тот же принцип, что применяют в своей работе антивирусы... Как это делается?

    Всего записей: 3142 | Зарегистр. 29-09-2005 | Отправлено: 13:13 22-09-2011
    wasilissk

    Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    DmitryKz
    Антивирусы ставят хуки на вызовы всяких  ZCreateFile,  ZCopyFile, ZWCreateFile, ZWopenFile...

    Всего записей: 293 | Зарегистр. 25-12-2006 | Отправлено: 15:00 22-09-2011
    rrromano



    Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Frodo_Torbins
    Представьте, что вы создали 2 элемента структуры, один из них заполнили. Второй остался непроинициализирован. Соответственно, поле структуры с типом строка тоже не проинициализирован. Теперь при операции присвоения Дельфи корректно скопирует всё содержимое одного элемента в другой, создав при этом экземпляр класса строковой переменной "за кадром". Всё ок. А теперь представьте, что вы копируете один элемент в другой путём копирования области памяти, а потом источник грохнете. Таким образом вы скопировали указатель на экземпляр класса строки, а саму строку прибили. Или попытались прибить. Что будет? Будет нехорошо. )))
    Мне так кажется.

    Всего записей: 283 | Зарегистр. 20-09-2006 | Отправлено: 15:25 22-09-2011
    DmitryKz

    Silver Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    wasilissk
    Так, начинаю понимать... спасибо за указание направления.
    Дополнительный вопрос: кто-нибудь знает, утилита FileMon работает по этому же принципу? Я знаю, что она связана с драйвером файловой системы... функции вида Zw...File принадлежат этому драйверу? Хочется добиться максимальной производительности при мониторинге...

    Всего записей: 3142 | Зарегистр. 29-09-2005 | Отправлено: 15:29 22-09-2011
    Varenik



    Advanced Member
    Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору
    rrromano
    Цитата:
    создали 2 элемента структуры
    Значит, проинициализированы оба, в том числе и строка как элемент каждой структуры. Если ей ничего не присвоить, то она будет просто пустой строкой  


    ----------
    Если нравится, считайте, что получилось…

    Всего записей: 1766 | Зарегистр. 21-07-2001 | Отправлено: 15:48 22-09-2011
    wasilissk

    Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    DmitryKz
    http://technet.microsoft.com/ru-ru/sysinternals/bb896642
    Абзац "Принцип работы FileMon"

    Всего записей: 293 | Зарегистр. 25-12-2006 | Отправлено: 16:09 22-09-2011
    DmitryKz

    Silver Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    wasilissk
    Жаль, на форуме нет возможности плюсовать ответы...
    Спасибо!

    Всего записей: 3142 | Зарегистр. 29-09-2005 | Отправлено: 16:15 22-09-2011
    Frodo_Torbins

    Silver Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    rrromano
    Цитата:
    копируете один элемент в другой путём копирования области памяти, а потом источник грохнете
    Вот это я и называю работой с указателями и не типобезопасным кодом. Если вы так делаете, то конечно у вас могут возникнуть проблемы.
     
    DmitryKz
    Есть такие винапишные функции как FindFirstChangeNotification, FindNextChangeNotification, FindCloseChangeNotification - это если вы не хотите заморачиваться с драйверами и тревожить антивирусы.

    Всего записей: 2318 | Зарегистр. 24-05-2007 | Отправлено: 16:54 22-09-2011 | Исправлено: Frodo_Torbins, 16:56 22-09-2011
    data man



    Advanced Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    DmitryKz

    Цитата:
    как можно сделать мониторинг изменений в директории (и её поддиректориях)?

    1. Использовать FindFirstChangeNotification*/FindNextChangeNotification.  
    Такой способ используется в ATFileNotification.
    2. Использовать ReadDirectoryChanges.  
    Его использует TCnFileSystemWatcher из состава CnVcl (CnPack), например.
     
    Оба компонента позволяют отслеживать (и рекурсивно - тоже) переименование, удаление, создание, изменение атрибутов, размера или их сочетания.

    ----------
    Любой достаточно развитый тролль неотличим от подлинно помешанного на какой-либо идее.
    Кекс. Антибиотики. Ламбада.

    Всего записей: 1696 | Зарегистр. 13-10-2005 | Отправлено: 17:19 22-09-2011
    rrromano



    Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору

    Цитата:
    Если вы так делаете, то конечно у вас могут возникнуть проблемы.

     
    Нет, я так не делаю. Кажется, я собирался автору вопроса это писать а попало к вам ). Это он так делает.
     
    Добавлено:

    Цитата:
    Значит, проинициализированы оба, в том числе и строка как элемент каждой структуры. Если ей ничего не присвоить, то она будет просто пустой строкой  

     
    Спасибо, я неправильно выразился. Конечно, проинициализированы, я там дальше указатели упоминал. Всё верно. Просто эта пустая строка всё равно создаётся в памяти как экземпляр класса, и в структуру пишется указатель на неё. А дальше, как я и писал. Правильно?

    Всего записей: 283 | Зарегистр. 20-09-2006 | Отправлено: 17:37 22-09-2011
    Varenik



    Advanced Member
    Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору
    rrromano
    Цитата:
    А дальше, как я и писал. Правильно?
    А дальше надо разобраться, что вы подразумеваете под
    Цитата:
    копируете один элемент в другой путём копирования области памяти
    - как именно это делается и с чем (в сообщении мешанина из структур и экземпляров класса).

    ----------
    Если нравится, считайте, что получилось…

    Всего записей: 1766 | Зарегистр. 21-07-2001 | Отправлено: 16:25 23-09-2011
    rrromano



    Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Varenik

    Цитата:
    - как именно это делается и с чем (в сообщении мешанина из структур и экземпляров класса).

     
    Загляните на предыдущую страницу. Там автор вопроса делает вот так:
     

    Код:
    // Структура для хранения данных.  
       
       TRouteItem = record  
         bGateWay    : Boolean;  
         bChecked    : Boolean;  
         pszRouteName: WideString;  
         dwNetWork   : DWORD;  
         dwNetMask   : DWORD;  
       end;  
     // Глобальный массив этих структур.  
       
     pRouteInfo: Array of TRouteItem;

     
    и
     

    Код:
    //idItem и iCount это Integer  
       
               idItem := SendMessageW(GetDlgItem(hWnd, IDC_MAIN_LISTBOX), LB_GETCURSEL, 0, 0);  
               if (idItem <> LB_ERR) then  
               begin  
                 iCount := SendMessageW(GetDlgItem(hWnd, IDC_MAIN_LISTBOX),  
                   LB_DELETESTRING, idItem, 0);  
                 if (iCount <> LB_ERR) then  
                 begin  
                   if (idItem < iCount) then  
                     CopyMemory(  
                       @pRouteInfo[idItem],  
                       @pRouteInfo[idItem + 1],  
                       (iCount - idItem) * SizeOf(TRouteItem)  
                     );  
                   SetLength(pRouteInfo, iCount);  
     //Move(pRouteInfo[idItem+1],pRouteInfo[idItem],(iCount-idItem)*SizeOf(pRouteInfo[0]));  
       
                 end;  
               end;

     
    Я просто писал в ключе "Представьте себе...", чтобы натолкнуть автора вопроса на мысли.
     
    Лично я бы унаследовал класс списка и добавил к нему новое свойство с типом, аналогичным описанию элемента структуры. Чистое ООП и никаких структур.

    Всего записей: 283 | Зарегистр. 20-09-2006 | Отправлено: 16:44 23-09-2011
    Frodo_Torbins

    Silver Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Maks150988

    Цитата:
    Заместо CopyMemory использую цикл.

    Код:
    for i := (idItem + 1) to iCount do
      pRouteInfo[i - 1] := pRouteInfo[i];

    Вот так и дальше делайте. А тот код с CopyMemory, который продемонстрировал rrromano в предыдущем сообщении, это однозначный баг. Либо управляйте выделением памяти под записи руками.

    Всего записей: 2318 | Зарегистр. 24-05-2007 | Отправлено: 19:10 23-09-2011
    Maks150988



    Advanced Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    rrromano
    Нет, без всяких ООП надо.
     
    Frodo_Torbins
    А как тогда управлять памятью? Ну вот использую я способ с CopyMemory. Задача - вставить новый элемент в список. Это типа надо выделить память через GetMem, например, для локальной переменной ^TRouteItem размером SizeOf(TRouteItem), выделить в ней подобным способом память под буфер pszRouteName, если тот будет уже LPWSTR и только потом скопировать все под нужный индекс массива, с освобождение памятей этой локальной переменной и буфера от нее?
     
     
     
    А вообще интересная задачка выходит. =) Кстати, я тут ранее отписывался насчет контрола. Может кто посмотрит и скажет в чем ошибка. Когда остается один элемент в списке, то при его удалении нарушение доступа возникает. Связано это с освобождением буфера. Хотя я не понял где там косячок, вроде бы все корректно освобождаю, проверив на nil его. Видать FreeMem может что неправильно делает, все-таки там юникод и этот еще нультерминирующий символ присутствовать может, так то если строка пустая, то размер ее 2 байта будет и наверняка пытается как-то не так память освободить. Вобщем кому не сложно, да и тема интересна, гляньте код функции CtrlWndProc_LbDeleteString. =) Может кто даже оптимизирует текущую наработку. Я тут кое-чего добавляю в свободное время. =)
     
    extended_listbox_src.zip
     


    Всего записей: 836 | Зарегистр. 23-12-2006 | Отправлено: 17:01 24-09-2011
    Frodo_Torbins

    Silver Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Maks150988
    Память вы должны выделять руками для всего, что является указателем. Если LPWSTR в вашем случае указатель, то под него тоже нужно выделять память. Если же это просто WideString то ничего делать не нужно.

    Всего записей: 2318 | Зарегистр. 24-05-2007 | Отправлено: 19:53 24-09-2011
    rrromano



    Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Maks150988
    Для вас процитирую:

    Цитата:
    В отличие от ShortString, WideString - указатель, ссылающийся на переменные. Память распределяется для AnsiString только когда необходимо. Например, присваивание значения одного AnsiString другому не распределяет память для копии первой строки. Вместо этого, ссылка считает первую строку увеличенной, и второй AnsiString устанавливает указатель на него.  
     
     Но когда вторая строка изменяется, то для этой новой строки выделяется новая память, и ссылка считает первую строку уменьшенной.  
     
     Когда на строку больше не ссылаются (последний указатель WideString установлен на ноль), она уничтожается.  
     
    WideStrings может быть присвоен от других строк, от функций, которые возвращают строку, и конкатенациями как в данном примере.

     
    Внимательно прочитав, вы всё поймёте.

    Всего записей: 283 | Зарегистр. 20-09-2006 | Отправлено: 23:28 24-09-2011
    Frodo_Torbins

    Silver Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    rrromano
    А я что то не понял AnsiString - это автоматически управляемая строка со счетчиком ссылок. Тоесть несколько переменных могут ссылаться на одну строку. WideString - автоматически управляемая строка без счетчика ссылок, на нее всегда ссылается только одна переменная. Плюс символы в ней занимают по два байта. В обоих случаях сама переменная имеет длину 4 байта и указывает на строку лежащую где то в другой области памяти. Что касается ShortString то тут я не в курсе. Наверное имеется в виду что переменная этого типа занимает от 0 до 256 байт, и является самой строкой а не указателем на нее.

    Всего записей: 2318 | Зарегистр. 24-05-2007 | Отправлено: 00:23 25-09-2011
    Открыть новую тему     Написать ответ в эту тему

    Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125

    Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » Вопросы по Delphi (до версии 2009) - часть 6


    Реклама на форуме Ru.Board.

    Powered by Ikonboard "v2.1.7b" © 2000 Ikonboard.com
    Modified by Ru.B0ard
    © Ru.B0ard 2000-2024

    BitCoin: 1NGG1chHtUvrtEqjeerQCKDMUi6S6CG4iC

    Рейтинг.ru