Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #16  
Старый 14.03.2013, 14:37
Аватар для Aristarh Dark
Aristarh Dark Aristarh Dark вне форума
Модератор
 
Регистрация: 07.10.2005
Адрес: Москва
Сообщения: 2,907
Версия Delphi: Delphi XE
Репутация: выкл
По умолчанию

у меня XE и там вызывается вот это, но смысла это не меняет:
Код:
procedure _UStrFromPWCharLen(var Dest: UnicodeString; Source: PWideChar; CharLength: Integer);
{$IFDEF PUREPASCAL}
var
  Temp: Pointer;
begin
  Temp := Pointer(Dest);
  if CharLength > 0 then
  begin
    Pointer(Dest) := _NewUnicodeString(CharLength);
    if Source <> nil then
      Move(Source^, Pointer(Dest)^, CharLength * SizeOf(WideChar));
  end
  else
    Pointer(Dest) := nil;
  _UStrClr(Temp);
end;
{$ELSE}
asm
        { ->    EAX     pointer to dest         }
        {       EDX     source                  }
        {       ECX     length in characters    }

        PUSH    EBX
        PUSH    ESI
        PUSH    EDI

        MOV     EBX,EAX // EBX := addr of Dest (result) in EBX
        MOV     ESI,EDX // ESI := source
        MOV     EDI,ECX // EDI := length

        { allocate new string }

        MOV     EAX,EDI // EAX := length

        CALL    _NewUnicodeString // EAX := new string (result)
        MOV     ECX,EDI // ECX := length
        MOV     EDI,EAX // EDI := result

        TEST    ESI,ESI // nil source?
        JE      @@noMove

        MOV     EDX,EAX // EDX := result (dest for Move)
        MOV     EAX,ESI // EAX := source (source for Move)
        SHL     ECX,1   // ECX := ECX * 2 (turn length into characters)
        CALL    Move

        { assign the result to dest }

@@noMove:
        MOV     EAX,EBX
        CALL    _LStrClr
        MOV     [EBX],EDI

        POP     EDI
        POP     ESI
        POP     EBX
end;
{$ENDIF !PUREPASCAL}
__________________
Некоторые программисты настолько ленивы, что сразу пишут рабочий код.

Если вас наказали ни за что - радуйтесь: вы ни в чем не виноваты.
Ответить с цитированием
Этот пользователь сказал Спасибо Aristarh Dark за это полезное сообщение:
BBBCat (14.03.2013)
  #17  
Старый 14.03.2013, 14:46
icWasya icWasya вне форума
Местный
 
Регистрация: 09.11.2010
Сообщения: 499
Репутация: 10
По умолчанию

Цитата:
Сообщение от BBBCat
Не, ну это-то я уже видел. Это ж для ShortString. Там и вопроса-то такого не возникло бы. А вот что для String?

Для длинных строк вызывается LStrFromPCharLen(из анализа дампа)
Ответить с цитированием
Этот пользователь сказал Спасибо icWasya за это полезное сообщение:
BBBCat (14.03.2013)
  #18  
Старый 14.03.2013, 14:57
Аватар для BBBCat
BBBCat BBBCat вне форума
Новичок
 
Регистрация: 10.03.2013
Сообщения: 73
Репутация: 10
По умолчанию

Спасибо большое. Я увидел, то что хотел. Облом, я как-то надеялся, что алгоритм изложенный icWasya был верный(уж простите меня icWasya). Оказалось, что просто выделяется новая область память. Т.е. к сожалению вопрос осталя без ответа - откуда AccessViolation?
Ответить с цитированием
  #19  
Старый 14.03.2013, 15:06
Аватар для M.A.D.M.A.N.
M.A.D.M.A.N. M.A.D.M.A.N. вне форума
Sir Richard Abramson
 
Регистрация: 05.04.2008
Сообщения: 5,505
Версия Delphi: XE10
Репутация: выкл
По умолчанию

По стеку вызовов глянь.
__________________
— Как тебя понимать?
— Понимать меня не обязательно. Обязательно меня любить и кормить вовремя.


На Delphi, увы, больше не программирую.
Рекомендуемая литература по программированию
Ответить с цитированием
Этот пользователь сказал Спасибо M.A.D.M.A.N. за это полезное сообщение:
BBBCat (14.03.2013)
  #20  
Старый 14.03.2013, 17:05
Аватар для BBBCat
BBBCat BBBCat вне форума
Новичок
 
Регистрация: 10.03.2013
Сообщения: 73
Репутация: 10
По умолчанию

Глубже SetString в дебагере зайти не могу, ошибку выдаёт именно на её выполнении. Надо к процессу приаттачиться чтоли?
А чё с сайтом-то было? Пинговался, а страница в Опере не грузилась.
Ответить с цитированием
  #21  
Старый 14.03.2013, 17:17
icWasya icWasya вне форума
Местный
 
Регистрация: 09.11.2010
Сообщения: 499
Репутация: 10
По умолчанию

>>Т.е. к сожалению вопрос осталя без ответа - откуда AccessViolation?

Ну даже в коде, который привёл Aristarh Dark, после выделения памяти происходит очистка старого содержимого Dest - вызывается _LStrClr или _UStrClr.
Смотрите что там делается
Запоминается старое значение, которое было в строке
Код:
  Temp:=Pointer(Dest);
здесь используется приведение к Pointer, чтобы убрать "магию" компилятора.
Затем заказывается память под новую строку
Код:
  Pointer(Dest) := _NewUnicodeString(CharLength);
Строка выделяется с уже установленым в 1 счётчиком. Опять "магия" не используется.
Код:
  if Source <> nil then
      Move(Source^, Pointer(Dest)^, CharLength * SizeOf(WideChar)); 
Если был успешный заказ пямяти, то копируем в строку переданный буфер.
Всё как Вы думали.
А затем
Код:
_UStrClr(Temp); 
В самой первой строке процедуры мы запомнили в переменной Temp то, что раньше было в Dest. А далее
Код:
procedure _UStrClr(var S);
asm
        JMP     _LStrClr
end;
просто переход на функцию
Код:
procedure _LStrClr(var S);
{$IFDEF PUREPASCAL}
var
  P: PStrRec;
begin
  if Pointer(S) <> nil then
  begin
    P := Pointer(Integer(S) - Sizeof(StrRec));
    Pointer(S) := nil;
    if P.refCnt > 0 then
      if InterlockedDecrement(P.refCnt) = 0 then
        FreeMem(P);
  end;
end;
{$ELSE}
asm
        { ->    EAX pointer to str      }

        MOV     EDX,[EAX]                       { fetch str                     }
        TEST    EDX,EDX                         { if nil, nothing to do         }
        JE      @@done
        MOV     dword ptr [EAX],0               { clear str                     }
        MOV     ECX,[EDX-skew].StrRec.refCnt    { fetch refCnt                  }
        DEC     ECX                             { if < 0: literal str           }
        JL      @@done
   LOCK DEC     [EDX-skew].StrRec.refCnt        { threadsafe dec refCount       }
        JNE     @@done
        PUSH    EAX
        LEA     EAX,[EDX-skew].StrRec.codePage    { if refCnt now zero, deallocate}
        CALL    _FreeMem
        POP     EAX
@@done:
end;
{$ENDIF}
которая и выполняет пункты 1)-5) из моего первого поста. На шаге 4) и происходит облом.
Ответить с цитированием
  #22  
Старый 14.03.2013, 18:03
Аватар для BBBCat
BBBCat BBBCat вне форума
Новичок
 
Регистрация: 10.03.2013
Сообщения: 73
Репутация: 10
По умолчанию

Но мне почему-то видится так:
Код:
Temp := Pointer(Dest); // сохраняем Dest в Temp
if CharLength > 0 then // если требуемая длина ненулевая(мой вариант идём в begin end)
 begin
    Pointer(Dest) := _NewUnicodeString(CharLength); // создаём новую! строку
     if Source <> nil then // если надо чем-то заполнить новую строку(мне не надо, след строку не выполняем)
      Move(Source^, Pointer(Dest)^, CharLength * SizeOf(WideChar)); // заполняем строку содержимым. С моими параметрами вызова это не происходит, но и происходило бы - ради бога
   end
  else // сюда вообще не попадаем, у меня длина строки больше нуля, но всё же
    Pointer(Dest) := nil; // раз строка пустая, то вот вам нильсен
_UStrClr(Temp);  // нас это не колышет, результат-то у нас в Dest, тем не менее обнулили старую строку.
И вот почему же я должен предварительно обнулять Dest, если его всё равно выкидывают на помойку и с нуля создают новую строку? И откуда в конце концов вылазит Access Violation?
Если посмотреть ассемблерный код после {$ELSE}, то там то же самое.

Всё!!! Всем спасибо, я допёр.
А "выполняет пункты 1)-5) из моего первого поста. На шаге 4) и происходит облом" - она не с результатом их выполняет и в самом конце, т.е. говорили мы в нужную сторону.
Резюме: SetString() выделяет под строку новую память, но про старую строку не забывает, уменьшает у ней refCnt. Так и должно быть.
На один вопрос я ответ не получил, но это чистое любопытство и крайне несущественно. Тема закрыта. Ещё раз пасибки!

Последний раз редактировалось BBBCat, 14.03.2013 в 19:30.
Ответить с цитированием
  #23  
Старый 15.03.2013, 09:33
icWasya icWasya вне форума
Местный
 
Регистрация: 09.11.2010
Сообщения: 499
Репутация: 10
По умолчанию

А шаги переставлены, что бы возможные ошибки не приводили к краху всей системы.
То есть сначала выделяем память, если не получилось, то EOutOfMemory, но старая строка остаётся какая была.

Затем присваиваем указатель на место Dest. Если не получилось - значит подали неправильный адрес переменной, с самого начала там мусор, и мы не виноваты.

Затем уменьшаем счётчик ссылок у старой строки. Если не получилось - то старая строка была неправильно сформирована, Access Violation, но в пользовательской переменной уже находится правильный указатель на новую строку, и если мы будем обрабатывать исключение, то будем работать с правильной строкой.

И только потом освобождаем память, занятую старой строкой. Возможна ситуация, как в предыдущем пункте.
Ответить с цитированием
  #24  
Старый 16.03.2013, 00:46
Аватар для BBBCat
BBBCat BBBCat вне форума
Новичок
 
Регистрация: 10.03.2013
Сообщения: 73
Репутация: 10
По умолчанию

Я понял, спасибо! Мне исходника не хватало, а как посмотрел - всё устаканилось Характер такой - не успокоюсь, пока по-пиксельно не разберусь Ещё раз спасибо за помощь!
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 16:29.


 

Сайт

Форум

FAQ

Соглашения

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2025