![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#16
|
||||
|
||||
|
у меня 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
|
|||
|
|||
|
Цитата:
Для длинных строк вызывается LStrFromPCharLen(из анализа дампа) |
| Этот пользователь сказал Спасибо icWasya за это полезное сообщение: | ||
BBBCat (14.03.2013)
| ||
|
#18
|
||||
|
||||
|
Спасибо большое. Я увидел, то что хотел. Облом, я как-то надеялся, что алгоритм изложенный icWasya был верный(уж простите меня icWasya). Оказалось, что просто выделяется новая область память. Т.е. к сожалению вопрос осталя без ответа - откуда AccessViolation?
|
|
#19
|
||||
|
||||
|
По стеку вызовов глянь.
|
| Этот пользователь сказал Спасибо M.A.D.M.A.N. за это полезное сообщение: | ||
BBBCat (14.03.2013)
| ||
|
#20
|
||||
|
||||
|
Глубже SetString в дебагере зайти не могу, ошибку выдаёт именно на её выполнении. Надо к процессу приаттачиться чтоли?
А чё с сайтом-то было? Пинговался, а страница в Опере не грузилась. |
|
#21
|
|||
|
|||
|
>>Т.е. к сожалению вопрос осталя без ответа - откуда AccessViolation?
Ну даже в коде, который привёл Aristarh Dark, после выделения памяти происходит очистка старого содержимого Dest - вызывается _LStrClr или _UStrClr. Смотрите что там делается Запоминается старое значение, которое было в строке Код:
Temp:=Pointer(Dest); Затем заказывается память под новую строку Код:
Pointer(Dest) := _NewUnicodeString(CharLength); Код:
if Source <> nil then
Move(Source^, Pointer(Dest)^, CharLength * SizeOf(WideChar)); Всё как Вы думали. А затем Код:
_UStrClr(Temp); Код:
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} |
|
#22
|
||||
|
||||
|
Но мне почему-то видится так:
Код:
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, тем не менее обнулили старую строку.Если посмотреть ассемблерный код после {$ELSE}, то там то же самое. Всё!!! Всем спасибо, я допёр. А "выполняет пункты 1)-5) из моего первого поста. На шаге 4) и происходит облом" - она не с результатом их выполняет и в самом конце, т.е. говорили мы в нужную сторону. Резюме: SetString() выделяет под строку новую память, но про старую строку не забывает, уменьшает у ней refCnt. Так и должно быть. На один вопрос я ответ не получил, но это чистое любопытство и крайне несущественно. Тема закрыта. Ещё раз пасибки! Последний раз редактировалось BBBCat, 14.03.2013 в 19:30. |
|
#23
|
|||
|
|||
|
А шаги переставлены, что бы возможные ошибки не приводили к краху всей системы.
То есть сначала выделяем память, если не получилось, то EOutOfMemory, но старая строка остаётся какая была. Затем присваиваем указатель на место Dest. Если не получилось - значит подали неправильный адрес переменной, с самого начала там мусор, и мы не виноваты. Затем уменьшаем счётчик ссылок у старой строки. Если не получилось - то старая строка была неправильно сформирована, Access Violation, но в пользовательской переменной уже находится правильный указатель на новую строку, и если мы будем обрабатывать исключение, то будем работать с правильной строкой. И только потом освобождаем память, занятую старой строкой. Возможна ситуация, как в предыдущем пункте. |
|
#24
|
||||
|
||||
|
Я понял, спасибо! Мне исходника не хватало, а как посмотрел - всё устаканилось
Характер такой - не успокоюсь, пока по-пиксельно не разберусь Ещё раз спасибо за помощь! |