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

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

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

ShIvADeSt (19-05-2010 05:14): Продолжаем тут http://forum.ru-board.com/topic.cgi?forum=33&topic=11215  Версия для печати • ПодписатьсяДобавить в закладки
Страницы: 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

   

ShIvADeSt



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

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

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

  • Всего записей: 3956 | Зарегистр. 29-07-2003 | Отправлено: 02:09 28-06-2009 | Исправлено: psa1974, 12:00 02-02-2010
    volser

    Advanced Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Maks150988
    Я имел ввиду класс TIniFile. Если нужен уникод можно посмотреть реализацию в Delphi 2010. Но поскольку нельзя использовать SysUtils, то он не подходит.

    Всего записей: 713 | Зарегистр. 31-03-2006 | Отправлено: 20:37 07-04-2010
    AviDen



    Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Maks150988, да, именно этот абзац я и имел в виду. Ну и? Как с этим согласуется проверка
    Код:
    if (dwRet <> 0) then
    ??? Далее, почему ты для pszbuf выделяешь именно MAX_PATH байт, это же буфер не под имя файла? Нужно или выделять сразу как можно больше (ну, смотря сколько секций в твоей инишке может быть в принципе), или, что правильнее, проверять возвращаемый результат и, если "return value is equal to the length specified by nSize minus two" - выделять, ну скажем в 2 раза бОльший буфер, снова вызывать GetPrivateProfileSectionNamesW и так до тех пор, поку буфера не хватит.

    Всего записей: 316 | Зарегистр. 05-06-2007 | Отправлено: 21:03 07-04-2010
    Maks150988



    Advanced Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    AviDen
    Да у меня 5 секций, ну ладно, даже если их будет тысяча.
     

    Цитата:
    if (dwRet <> 0) then

    Да ну вдруг вообще покажет что 0 символов скопируетсмя, ведь ини файл вообще может быть пустым, кто его знает. Тем более у меня вначале указано что результат отрицательный и если функцию вернет нуль, никуда и не пойдем. Буфер pszbuf выделен под список секций, я без понятия сколько надо памяти жахнуть туда, ну взял самое распространенное значение.
    Мне значит вернуло какой-то размер скопированных данных, но раз поперли повторы в цикле, значит памяти было выделено достаточно я так понял. Ну я и попытался уменьшить размер этого pszbuf раз такое дело, может я вообще приравниваю криво его к workbuf или чего там надо. Оно непонятно чего-то.

    Всего записей: 836 | Зарегистр. 23-12-2006 | Отправлено: 21:26 07-04-2010
    Odysseos



    Junior Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Bonivur
     
    Мне нужен просто общий алгоритм - как подобные задачи решаются.
     
    Полным перебором они решаются.

    Всего записей: 186 | Зарегистр. 02-01-2006 | Отправлено: 22:00 07-04-2010
    Bonivur



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

    Цитата:
    Полным перебором они решаются.

    Если под полным перебором ты имеешь в виду цикл-в-цикле, то пробовал. Все возможные вариатны не находятся. Проблема в том что эти три ноты аккорда могут быть в произвольном порядке и между ними может быть как пустые струны так и просто не звучащие. К тому же на каждой отдельной струне могут быть две ноты входящие в аккорд.


    ----------
    Что будет стоить тысяча слов когда важна будет крепость руки? (В.Цой)

    Всего записей: 655 | Зарегистр. 22-06-2003 | Отправлено: 23:26 07-04-2010 | Исправлено: Bonivur, 23:28 07-04-2010
    Odysseos



    Junior Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Bonivur
     
    Ну так надо сначала описать все _граничные_условия_ - как то:
    - что у нас "басы" (все три басовых струны, или только две E и A, или только E, или нам вообще просто абстрактные аппликатыру нужны);
    - что у нас голоса;
    - маскимальное расстояние между нотами на разных струнах (а то ведь пальцы не до бесконечности растягиваются, да);
    - допустимы ли не звучащие струны (то есть - струны, на которых в диапазоне максимально допустимого расстояния нет ни одной подходящей ноты) посреди "голосов";
    - преимущества нот (если нота уже есть в басах - то какую ступень из доступных по расстоянию предпочитать в "голосах")...
     
    Я, собственно, не зря спросил - абстрактная ли задача, или для реального применения.
     
     
    Добавлено:
    Maks150988
     
    Вот код чтения unicode'ного ini-значения любой длины:
     

    Код:
     
    const
      BUF_SIZE = 16384;
     
    function ReadIniValueW(const FileName, Section, Ident: WideString): WideString;
    var
      s_buf: WideString;
      len, n: Integer;
    begin
      s_buf := '';
      repeat
        len := Length(s_buf) + BUF_SIZE;
     
        SetLength(s_buf, len);
        s_buf[len] := High(s_buf[len]);
     
        n := GetPrivateProfileStringW(
          PWideChar(Section), PWideChar(Ident), nil,
          PWideChar(s_buf), len,
          PWideChar(FileName));
      until (n < len - 1) or (s_buf[len] <> #0);
     
      if n > 0 then
        Result := Trim(Copy(s_buf, 1, n))
      else
        Result := '';
    end;
     

     
    Но я хоть убей не пойму, нафига извращаться с именно юникодными версиями функций, если можно русские (да хоть китайские!) строковые значения хранить в обычном ANSI ini закодированными в UTF8.

    Всего записей: 186 | Зарегистр. 02-01-2006 | Отправлено: 23:35 07-04-2010 | Исправлено: Odysseos, 23:43 07-04-2010
    Maks150988



    Advanced Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Odysseos
    Ну там конечно да, можно приводить к Unicode через Utf8Encode/Utf8Decode, но у меня уже константы сами WideString и приводить к типам не хочется лишний раз, уж если для функции реестровой подаю константу, то и хочу подавать спокойно в функцию по работе с ини файлами. В ини храню обычный анси, но теперь уже тупо интресно как перечислить все секции с помощью GetPrivateProfileSectionNamesW.

    Всего записей: 836 | Зарегистр. 23-12-2006 | Отправлено: 00:03 08-04-2010
    YuriyRR



    Full Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Maks150988
    Если  я правильно путаю, то должно быть так
     
    Inc(workbuf, lstrlenW(workbuf)*2 + 1);  
     
    а код
           Result := TRUE;  
              FreeMem(pszbuf, MAX_PATH);  
              Break  
    Break не отменяет исполнение секции  
      finally  
        FreeMem(pszbuf, MAX_PATH);  

    Всего записей: 516 | Зарегистр. 07-06-2007 | Отправлено: 00:36 08-04-2010
    Odysseos



    Junior Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Maks150988
     
    интресно как перечислить все секции с помощью GetPrivateProfileSectionNamesW
     
    Вот так:
     
    Подробнее...
     
    Нужны модули Types (для TWideStringDynArray - впрочем, его можно легко описать как TWideStringDynArray = array of WideString) и SysUtils (для Trim и WideSameText).
     
    Если интересно - то вот запись и удаление значений и секций:
     
    Подробнее...

    Всего записей: 186 | Зарегистр. 02-01-2006 | Отправлено: 00:50 08-04-2010
    Maks150988



    Advanced Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    YuriyRR
    Да я вот тоже атк думал.
     
    Odysseos
    Ну нет, это как-то грязно. Вот сделал, на гуглокоде сишный пример понятный попался.
     

    Код:
    function IniFileProfileExistsW(pszFileName, pszAppName: WideString): Boolean;
    var
      pszBuf: Array [0..MAX_PATH] of WideChar;
      pBuf  : LPWSTR;
      dwRet: DWORD;
    begin
     
      Result := FALSE;
     
      dwRet := GetPrivateProfileSectionNamesW(pszBuf, SizeOf(pszBuf), LPWSTR(pszFileName));
      pBuf := pszBuf;
     
      while (pBuf <> nil) and (pBuf^ <> #0) do
      begin
        if (lstrcmpiW(LPWSTR(pszAppName), pBuf) = 0) then
        begin
          Result := TRUE;
          Break;
        end;
        Inc(pBuf, lstrlenW(pBuf) + 1);
      end;
     
    end;

     
    До этого сделал вообще такое.
     

    Код:
    function IniFileProfileExistsW(pszFileName, pszAppName: WideString): Boolean;
    var
      pszText: WideString;
      hFile  : THandle;
      hMem   : Cardinal;
      pMem   : Pointer;
      dwRead : DWORD;
    begin
     
      Result := FALSE;
     
      hFile := CreateFileW(
        LPWSTR(pszFileName),
        GENERIC_READ or GENERIC_WRITE,
        FILE_SHARE_READ or FILE_SHARE_WRITE,
        nil,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        0
      );
     
      if (hFile <> INVALID_HANDLE_VALUE) then
      try
     
        hMem := GlobalAlloc(GMEM_MOVEABLE or GMEM_ZEROINIT, 65535);
        pMem := GlobalLock(hMem);
        ReadFile(hFile, pMem^, 65535 - 1, dwRead, nil);
        pszText := FormatW('[%s]', [pszAppName]);
        Result := Pos(pszText, LPSTR(pMem)) > 0;
     
      finally
     
        GlobalUnlock(HGLOBAL(pMem));
        GlobalFree(hMem);
        CloseHandle(hFile);
     
      end;
     
    end;

     
    Оболдеть, кажется такая простая задача, а над решением можно долго биться.

    Всего записей: 836 | Зарегистр. 23-12-2006 | Отправлено: 01:56 08-04-2010
    Odysseos



    Junior Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Maks150988
     
    Во-первых - грязно в каком, простите, смысле? Неоптимально? (Стоило бы обосновать, где именно.) Непонятно? (А никто и не обещал.) Или что?
     
    Во-вторых - GetPrivateProfileSectionNamesW - это просто обертка для все той же GetPrivateProfileStringW, с равными nil параметрами lpAppName и lpKeyName.
     
    В-третьих - Ваш код, списаный c какого-то C-примера, как отреагирует на то, что суммарная длина всех секций в ini будет больше, чем MAX_PATH?
     
    В-четвертых - почему Вы считаете, что WinAPI-функция поиска конца PWideChar-строки (lstrlenW) будет быстрей, чем просто проход в цикле по всем символам? Там есть что-то, что M$ может сделать оптимальней, чем просто посимвольным перебором в цикле? (Заметьте - сравнение идет не по подстроке, где и действительно есть, чего оптимизировать, а по отдельному символу.)
     
    ...Короче говоря - я предложил заведомо рабочее решение (из рабочего проекта). Не нравится - не пользуйтесь.

    Всего записей: 186 | Зарегистр. 02-01-2006 | Отправлено: 03:00 08-04-2010
    Maks150988



    Advanced Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Odysseos
    Ну желательно меньшим кодом "отделаться", но я ваш пример сохранил, есть кое-что интересное.
    Даже если и обертка, то зря чтоли функция существует, раз выдумали ее - будем пользоваться.
    Не проблема, в цикле тогда надо увеличивать буфер и сравнивать значение, а не меньше ли возврат на 2, пока не достигнем нужного размера. Тем более у вас в коде так вообще заранее выделяется большой буфер, какая разница, можно и тут заведомо огромный сделать и с лихвой хватит.

    Всего записей: 836 | Зарегистр. 23-12-2006 | Отправлено: 07:33 08-04-2010
    AviDen



    Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Odysseos
    Цитата:
    почему Вы считаете, что WinAPI-функция поиска конца PWideChar-строки (lstrlenW) будет быстрей, чем просто проход в цикле по всем символам

    Ну если бы я на месте M$ писал lstrlenW, я бы использовал процессорную инструкцию repnz scansw (всего одну!!), которая будет, скажем так, слегка шустрее, чем цикл по символам Кстати, подозреваю, что так она и сделана.
     

    Цитата:
    нафига извращаться с именно юникодными версиями функций, если можно русские (да хоть китайские!) строковые значения хранить в обычном ANSI ini закодированными в UTF8

    Я так скажу - лично мне проще пользоваться "родным" для винды типом WideString (кодировка UCS16-LE), чем utf8. Ну не нравятся мне типы с переменной длиной одного символа, не нравятся! Ну, а уж Ansi и прочее неюникодное фуфло - это вообще позавчерашний день.
     
    Добавлено:
    Maks150988

    Цитата:
    Оболдеть, кажется такая простая задача, а над решением можно долго биться.

    Добро пожаловать в мир WinApi.

    Всего записей: 316 | Зарегистр. 05-06-2007 | Отправлено: 11:16 08-04-2010
    Odysseos



    Junior Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    AviDen
     
    Ну если бы я на месте M$ писал lstrlenW, я бы использовал процессорную инструкцию repnz scansw (всего одну!!), которая будет, скажем так, слегка шустрее, чем цикл по символам  Кстати, подозреваю, что так она и сделана.
     
    Я Вас расстрою - но lstrlenW работает вот так:
     
    ...
    7655A51F  mov cx,[eax]
    7655A522  inc eax
    7655A523  inc eax
    7655A524  test cx,cx
    7655A527  jnz $7655a51f
    ...
     
    И это еще не считая разной подготовительной работы и вообще самого call'а со срывом конвейера (тем более, что внутри есть еще один call).
     
     
    Я так скажу - лично мне проще пользоваться "родным" для винды типом WideString (кодировка UCS16-LE), чем utf8. Ну не нравятся мне типы с переменной длиной одного символа, не нравятся! Ну, а уж Ansi и прочее неюникодное фуфло - это вообще позавчерашний день.
     
    Delphi 2009+ - Ваш выбор в этом случае.
     
    ...А насчет WideString (BSTR, если уж на то пошло) - Вы в курсе, что он "малость" менее оптимален, чем "родные" строки Delphi? В том смысле, что он не reference-counted, и при всех его присваиваниях-передачах Delphi каждый раз создает точную копию строки.
     
    Добавлено:
    Maks150988
     
    Ну желательно меньшим кодом "отделаться"
     
    Это как? Чтоб один компонент на форму бросить - и порядок, заработало?
     
     
    Не проблема, в цикле тогда надо увеличивать буфер и сравнивать значение, а не меньше ли возврат на 2, пока не достигнем нужного размера.
     
    Мой код именно это и делает.
     
     
    Тем более у вас в коде так вообще заранее выделяется большой буфер, какая разница, можно и тут заведомо огромный сделать и с лихвой хватит.
     
    В моем коде буфер можно задать хоть в один символ - он все равно прочитает _все_ (пусть и не очень быстро). А Ваш - не больше размера буфера.

    Всего записей: 186 | Зарегистр. 02-01-2006 | Отправлено: 12:00 08-04-2010
    AviDen



    Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Odysseos, меня это не расстраивает )) я всегда пользую length(), который просто читает длину строки из нулевого символа (кстати, чистые pchar- и pwidechar- данные мне тоже не особо нравятся по причине невозможности быстро узнать длину строки, не считая символы). Да и ваще, работа со строками c-style - это жуткий отстой и гемор, сочувствую сишникам, не имеющих простых и удобных string и widestring типов.
     
    Про отсутствие reference-countring у широких строк, понятное дело, знаю, однако это не проблема. Если грамотно подходить к написанию кода (держа в памяти тот факт, что строки копируются всегда при передаче по значению или присвоении), то в 99% случаев лишних операций с памятью можно избежать. Как минимум, объявляя все widestring-параметры  в функциях и процедурах как const или var (тогда они передаются по ссылке без копирования). Ну и ещё есть пара трюков в запасе. А остальной 1% с лихвой компенсируется удобством использования и универсальностью на многие годы вперёд.
     
    P.S. Про D2009 пока только мечтаю, к сожалению, проект ещё не скоро дойдёт до состояния готовности к апгрейду с d7 на что-то посвежее...  ((
     
    Добавлено:
    P.P.S. А чего это call должен срывать конвейер? Я конечно в этом не дока, но это же не условный переход (да и те проц умеет предсказывать, плюс он в любом случае на всякий случай конвейеризует код по обоим веткам, если я не ошибаюсь).

    Всего записей: 316 | Зарегистр. 05-06-2007 | Отправлено: 12:22 08-04-2010
    Odysseos



    Junior Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    AviDen
     
    я всегда пользую length()
     
    В данной задаче - чтении и разборе списка всех секций из ini-файла - приходится работать именно с C-строками, последователно расположенными в буфере и разеленными #0. Их так WinAPI возвращает, и ничего с этим не поделать.
     
     
    А чего это call должен срывать конвейер? Я конечно в этом не дока, но это же не условный переход
     
    Не обязательно сорвет. Но вероятность есть, особенно учитывая несколько условных переходов внутри call'а, еще один внутренний call и условный возврат из него.

    Всего записей: 186 | Зарегистр. 02-01-2006 | Отправлено: 12:37 08-04-2010
    AviDen



    Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Да мы вообще для проекта написали свой widestring-аналог TIniFile и не паримся... А то винапишные танцы с бубном по каждому мелкому поводу как-то не прельщают.

    Всего записей: 316 | Зарегистр. 05-06-2007 | Отправлено: 12:57 08-04-2010
    YuriyRR



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

    Цитата:
    Я Вас расстрою - но lstrlenW работает вот так

    Угарно!. 5 баллов.

    Всего записей: 516 | Зарегистр. 07-06-2007 | Отправлено: 16:51 08-04-2010
    Maks150988



    Advanced Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Да ладно вам блин, а то щас начнется бурление коричневого вещества, такое бурное обсуждение.
    У меня вот такой вопрос, годится ли сранивание WideString тупо через знак равенства?

    Код:
    if (wstr1 = wstr2) then blablabla

    Я был уверен что да, ведь оно работало, а потом как-то в одной программе целый день искал недочет в коде, весь косяк был в сравнении вайдстрингов, пришлось использовать lstrcmpi функцию. При чем до переустановки делфи все компилировалось во вполне работоспособный код, а после вот так.

    Всего записей: 836 | Зарегистр. 23-12-2006 | Отправлено: 19:50 08-04-2010
    Odysseos



    Junior Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Maks150988
     
    Оператор "=" сравнивает строки с учетом регистра. А в описании lstrcmpi ясно указано:
     

    Цитата:
     
    Compares two character strings. The comparison is not case-sensitive.
     

     
    Если хотите wide-строки сравнивать "по-дельфийски" - то WideSameText для сравнения без учета регистра, и WideSameStr - c учетом (полный аналог "=").
     
    Также - WideCompareText и WideCompareStr сравнивают wide-строки (без учета регистра и с учетом соответственно) на меньше/больше/равно.

    Всего записей: 186 | Зарегистр. 02-01-2006 | Отправлено: 20:31 08-04-2010 | Исправлено: Odysseos, 20:32 08-04-2010
       

    Страницы: 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

    Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » Вопросы по Delphi (до версии 2009) - часть 5
    ShIvADeSt (19-05-2010 05:14): Продолжаем тут http://forum.ru-board.com/topic.cgi?forum=33&topic=11215


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

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

    BitCoin: 1NGG1chHtUvrtEqjeerQCKDMUi6S6CG4iC

    Рейтинг.ru