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

НовостиФайловые архивы
ПоискАктивные темыТоп лист
ПравилаКто в 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
    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
    Maks150988



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

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



    Junior Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Maks150988
     
    Быть не может. Вы где-то ошиблись, видимо. Только что проверил (удостоверится, що з глузду не зъихав), Delphi 2007:
     

    Код:
     
    procedure TForm1.FormCreate(Sender: TObject);
    var
      s1, s2: WideString;
    begin
      s1 := 'аБв';
      s2 := 'аБв';
     
      if s1 = s2 then
        Caption := '!';
    end;
     

     
    , в заголовок формы выводит "!" (если регистр символа в какой-то из строк поменять - остается "Form1"). При этом - Pointer(s1) <> Pointer(s2), то есть, это именно что _разные_ строки.

    Всего записей: 186 | Зарегистр. 02-01-2006 | Отправлено: 00:15 09-04-2010 | Исправлено: Odysseos, 00:18 09-04-2010
    Maks150988



    Advanced Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Odysseos
     
    Вот моя программа: Ссылка
     
    Возможно и ошибся, но я проверял на MessageBox, где смотрел все что появляется, предварительно поместив сраниваемую строку между символами тире, дабы убедиться а нет ли пробелов. Потом проверял на цифрах, результат тот же.
     
    Код находится в модуле D_FinsWind.pas:

    Код:
    if (lstrcmpiW(@ObjectName[1], @pszEntry[1]) = 0) then

    Соответственно ранее код был такой:

    Код:
    if (ObjectName = pszEntry) then

     
    Может я действительно где-то ошибся.

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



    Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    Maks150988, я код по ссылке не смотрел (времени нет), но исходя из общепринятого стиля именования переменных (ведь Вы же всё из каких-то сишных/апишных примеров берёте, как я вижу) pszEntry - это указатель на некое число (скорее всего размер чего-либо). Сравнивать имя некоторого объекта с указателем на число - ну, сами понимаете...
     
    А вообще, строки обычным оператором сравнения сравнивать нельзя никогда, исключительно функциями WideSameText/WideSameStr/WideCompareText/WideCompareStr, как и написал Odysseos. Для Ansi-строк также есть соотв. аналоги с префиксом Ansi.

    Всего записей: 316 | Зарегистр. 05-06-2007 | Отправлено: 10:07 09-04-2010 | Исправлено: AviDen, 10:08 09-04-2010
    Maks150988



    Advanced Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    AviDen
    ObjectName и pszEntry это WideString.
     
    Ну теперь буду знать, просто практически всегда на форумах попадаются такие вот сравнения, я как-то не задумывался об этом.
     
    Odysseos
     
    Не знаю как насчет быстроты вашего рабочего кода, но я пока сделал так, впринципе если я ничего не попутал в коде, размер буфера будет увеличиваться до тех пор, пока разница будет равна 2.
     

    Код:
    function IniFileProfileExistsW(pszFileName, pszAppName: WideString): Boolean;
    var
      pszBuf : WideString;
      workBuf: LPWSTR;
      nSize  : DWORD;
      dwRet  : DWORD;
    begin
     
      Result := FALSE;
     
      nSize := MAX_PATH;
      dwRet := 0;
      SetLength(pszBuf, nSize);
     
      repeat
        Inc(nSize);
        SetLength(pszBuf, nSize);
        dwRet := GetPrivateProfileSectionNamesW(LPWSTR(pszBuf), nSize, LPWSTR(pszFileName));
      until
        (nSize - dwRet) <> 2;
     
      workBuf := LPWSTR(pszBuf);
     
      while (workBuf <> nil) and (workBuf^ <> #0) do
      begin
        if (lstrcmpiW(LPWSTR(pszAppName), workBuf) = 0) then
        begin
          Result := TRUE;
          Break;
        end;
        Inc(workBuf, lstrlenW(workBuf) + 1);
      end;
     
    end;

    Всего записей: 836 | Зарегистр. 23-12-2006 | Отправлено: 11:38 09-04-2010 | Исправлено: Maks150988, 14:05 09-04-2010
    Odysseos



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


    Код:
     
        Inc(nSize);
        SetLength(pszBuf, nSize);
        dwRet := GetPrivateProfileSectionNamesW(LPWSTR(pszBuf), nSize, LPWSTR(pszFileName));
     


     
    Я правильно понимаю, что если суммарная длина заголовков всех секций в ini-файле будет, например, MAX_PATH + 200, то функцию GetPrivateProfileSectionNamesW Вы вызовете 1 + 200 раз?

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

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

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

     
    на д2010  свой компонент не тестили?  
     
    я тут был пару своих проектиков решил портануть. в них как-раз используются ДЛЛки с обработкой widestring'ов.  вроде все работает но память утекает непонятно куда . пришлось на время перенос отложить.  
     

    Всего записей: 708 | Зарегистр. 26-02-2002 | Отправлено: 16:34 09-04-2010
    AviDen



    Member
    Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
    apnss, нет, у нас проект на D7 и будет на ней ещё оооочень долго
    Для борьбы с утечками FastMM используете? Попробуйте, крайне рекомендую.

    Всего записей: 316 | Зарегистр. 05-06-2007 | Отправлено: 17:37 09-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