![]() |
|
|
Регистрация | << Правила форума >> | 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
|
||||
|
||||
![]() По стеку вызовов глянь.
— Как тебя понимать? — Понимать меня не обязательно. Обязательно меня любить и кормить вовремя. На Delphi, увы, больше не программирую. Рекомендуемая литература по программированию |
Этот пользователь сказал Спасибо 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
|
||||
|
||||
![]() Я понял, спасибо! Мне исходника не хватало, а как посмотрел - всё устаканилось
![]() ![]() |