Глюки Lazarus

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Ответить
Angel_19
новенький
Сообщения: 37
Зарегистрирован: 24.06.2014 17:29:47

Глюки Lazarus

Сообщение Angel_19 »

Такая проблема проявилась.

Есть небольшой проект.
Одно время он компилировался и работал нормально. Какое-то время я его не использовал.
Тут внес небольшие изменения, и часть кода просто не выполняется....
Т.е. как пример - при запуске программы, вызываю процедуру, в которой в Memo добавляются строки. Часть строк добавляется, а часть нет.
Пробовал: Файл - очистить каталог - проблема осталась.

Добавил на форму кнопку, в которой вызываю ту же процедуру - она отрабатывает нормально.

В чем проблема? (Просто подозреваю, что и в крупном проекте несмотря на внесенные изменения, выполняется как бы старый код...)
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 836
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

Не видя код это гадание.
Как доступ к Мемо осуществляется, как вывод идет, где какие обновления....

:arrow: "-Помогите, мотоцикл не заводится! -Бензин есть? Нейтраль включил? Аварийный стоп выключен? Почему ключи от другого мотоцикла вставляешь?"
Angel_19
новенький
Сообщения: 37
Зарегистрирован: 24.06.2014 17:29:47

Сообщение Angel_19 »

Код: Выделить всё

procedure TForm1.GetName;
Var
   vSizet  : DWord;
   vPWChart: PWideChar;
   vNamePC,
   vNameUser : String;
   I         : DWord;
   vWNameUser,
   vWNamePC  : WideString;
begin
     vSizet := 1024;
     vPWChart := GetMem(vSizet);
     // получаем имя ПК
     if GetComputerNameW(vPWChart, vSizet) then
     begin
        SetString(vWNamePC, vPWChart, vSizet);
        vNamePC := UTF8Encode(vWNamePC);
     end
     else
        vNamePC := '';
     Memo1.Lines.Add('Имя ПК: '+vNamePC);

     // получаем логин !!!
     vSizet := 1024;
     if GetUserNameW(vPWChart, vSizet) then
     begin
          SetString(vWNameUser, vPWChart, vSizet);
          vNameUser := UTF8Encode(vWNameUser);
     end
     else
     begin
        vNameUser := '';
        Memo1.Lines.Add('LastError: ' + SysErrorMessageUTF8(GetLastError));
     end;
     Memo1.Lines.Add('GetUserName: '+vNameUser);
     for i:= 0 to 12 do
     begin
          vSizet := 1024;
          if GetUserNameExW(I,vPWChart, vSizet) then
          begin
               SetString(vWNameUser, vPWChart, vSizet);
               vNameUser := UTF8Encode(vWNameUser);
          end
          else
          begin
               vNameUser := '';
               vNameUser := 'LastError: ' + SysErrorMessageUTF8(GetLastError);
          end;
          Memo1.Lines.Add('GetUserNameEx '+IntToStr(I)+': '+vNameUser);
     end;
     FreeMem(vPWChart);
end;

Если вызываю в FormCreate , то то что в for i:= 0 to 12 do не работает.
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 836
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

Angel_19 писал(а):Если вызываю в FormCreate , то то что в for i:= 0 to 12 do не работает.

Нет, все что после

Код: Выделить всё

Memo1.Lines.Add('GetUserName: '+vNameUser);

Не отображается в самом мемо. Если ее закомментируешь, то работать будет.
Там что то в переменной передается, что мешает Мемо работать.
Angel_19
новенький
Сообщения: 37
Зарегистрирован: 24.06.2014 17:29:47

Сообщение Angel_19 »

В переменной там обычная строка.

Добавлено спустя 4 минуты 7 секунд:
Там в конце строки идет символ: #0 , он то все и портит.
если изменить код так, то все работает сразу:

Код: Выделить всё

procedure TForm1.GetName;
Var
   vSizet  : DWord;
   vPWChart: PWideChar;
   vNamePC,
   vNameUser : String;
   I         : DWord;
   vWNameUser,
   vWNamePC  : WideString;
begin
     vSizet := 1024;
     vPWChart := GetMem(vSizet);
     // получаем имя ПК
     if GetComputerNameW(vPWChart, vSizet) then
     begin
        SetString(vWNamePC, vPWChart, vSizet);
        vNamePC := UTF8Encode(vWNamePC);
     end
     else
        vNamePC := '';
     Memo1.Lines.Add('Имя ПК: '+vNamePC);

     // получаем логин !!!
     vSizet := 1024;
     if GetUserNameW(vPWChart, vSizet) then
     begin
         // SetString(vWNameUser, vPWChart, vSizet);
         // vNameUser := UTF8Encode(vWNameUser);
        vNameUser := UTF8Encode(WideString(vPWChart));
     end
     else
     begin
        vNameUser := '';
        Memo1.Lines.Add('LastError: ' + SysErrorMessageUTF8(GetLastError));
     end;
     vNameUser := 'GetUserName: '+vNameUser;
     Memo1.Lines.Add(vNameUser);
     for i:= 0 to 12 do
     begin
          vSizet := 1024;
          if GetUserNameExW(I,vPWChart, vSizet) then
          begin
               SetString(vWNameUser, vPWChart, vSizet);
               vNameUser := UTF8Encode(vWNameUser);
          end
          else
          begin
               vNameUser := '';
               vNameUser := 'LastError: ' + SysErrorMessageUTF8(GetLastError);
          end;
          Memo1.Lines.Add('GetUserNameEx '+IntToStr(I)+': '+vNameUser);
     end;
     FreeMem(vPWChart);
end;


Добавлено спустя 6 минут 43 секунды:
Но если оставить преждний код, и на форму добавить кнопку, и вызвать эту процедуру из кнопки, то все отрабатывает нормально, хотя символ #0 есть в злополучной строке...

Добавлено спустя 19 минут 56 секунд:
Правильный код:

Код: Выделить всё

procedure TForm1.GetName;
Var
   vSizet  : DWord;
   vPWChart: PWideChar;
   vNamePC,
   vNameUser : String;
   I         : DWord;
   vWNameUser,
   vWNamePC  : WideString;
begin
     vSizet := 1024;
     vPWChart := GetMem(vSizet);
     // получаем имя ПК
     if GetComputerNameW(vPWChart, vSizet) then
     begin
        SetString(vWNamePC, vPWChart, vSizet);
        vNamePC := UTF8Encode(vWNamePC);
     end
     else
        vNamePC := '';
     Memo1.Lines.Add('Имя ПК: '+vNamePC);

     // получаем логин !!!
     vSizet := 1024;
     if GetUserNameW(vPWChart, vSizet) then
     begin
          SetString(vWNameUser, vPWChart, vSizet-1);
          vNameUser := UTF8Encode(vWNameUser);
     end
     else
     begin
        vNameUser := '';
        Memo1.Lines.Add('LastError: ' + SysErrorMessageUTF8(GetLastError));
     end;
     vNameUser := 'GetUserName: '+vNameUser;
     Memo1.Lines.Add(vNameUser);
     for i:= 0 to 12 do
     begin
          vSizet := 1024;
          if GetUserNameExW(I,vPWChart, vSizet) then
          begin
               SetString(vWNameUser, vPWChart, vSizet-1);
               vNameUser := UTF8Encode(vWNameUser);
          end
          else
          begin
               vNameUser := '';
               vNameUser := 'LastError: ' + SysErrorMessageUTF8(GetLastError);
          end;
          Memo1.Lines.Add('GetUserNameEx '+IntToStr(I)+': '+vNameUser);
     end;
     FreeMem(vPWChart);
end;

Размер использованного буфера возвращаемый системными функциями GetUserNameW и GetUserNameExW больше на 1.

Добавлено спустя 46 секунд:
Sharfik - спасибо!
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 836
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

Теперь ты мне подскажи, сделал как у тебя через GetMem выделение памяти под String.
При передаче адреса в качестве параметра функции в самой функции он уже не читается. Адрес другой.

Код: Выделить всё

....
vPString := GetMem(vSizet);
MyFunction(vPString ) // function MyFunction(Sender:Pointer):Integer;

Чтение это присвоение адреса аналогичной переменной с адресом

Код: Выделить всё

function MyFunction(Sender:Pointer):Integer;
...
vPString := Sender;
....text:=vPString^;

Я ошибся в присвоениях или система не позволяет передать объявленный участок памяти в другую функцию?
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

особо не вникал, но
>>сделал как у тебя через GetMem выделение памяти под String.
Выделять vPString := GetMem(vSizet); смысла нет, т.к. нужно vPString := GetMem(sizeof(string)) - выделяем память под переменную, под значение память выделит rtl, но нужно незабыть ее проинициализировать, иначе будут AV

>>При передаче адреса в качестве параметра функции в самой функции он уже не читается. Адрес другой.
ты похоже путаешь @vPString и @vPStringх[1] - для стрингов адрес переменной и адрес значения (содержимого переменной) - разные вещи
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 836
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

vPString:PString; //PString=^String
vPString - указатель на адрес значения
@vPString - указатель на адрес переменной с указателем на значение
Передаваться должен первый. С ним по работе проблем нет, пока не читаю указатель в функции вложенной, там адрес другой получаю. Вроде всегда нормально было, а тут бред...
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

vPString:PString; //PString=^String
vPString - указатель на адрес значения
@vPString - указатель на адрес переменной с указателем на значение

Что есть значение?
>>vPString - указатель на адрес значения
Указатель на переменную типа string, а указатель на само текстовое значение лежит внутри этой переменной вместе с другой служебной информацией

Код: Выделить всё

vPString:pstring;
....
vPString := GetMem(sizeof(string));
pointer(vPString):=nil;
pstring^:=text;

MyFunction1(vPString);//MyFunction1(param:pstring)
MyFunction2(vPString^);//MyFunction2(param:string)
MyFunction3(@vPString^[1]);//MyFunction3(param:pchar)

должно быть чтото типа такого при динамическом создании стрингов

>>Вроде всегда нормально было, а тут бред...
попрежнему всё нормально, ищите ошибки))
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 836
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

Все проще, я правильно делал, только stdcall; функции которой передавал адрес не прописал. :D
Alex2013
долгожитель
Сообщения: 3211
Зарегистрирован: 03.04.2013 11:59:44

Сообщение Alex2013 »

Для выделения памяти под динамические строки
Лучше всего применять функцию NewStr(const S: string): PString;
в паре с DisposeStr(S: PString);
То есть что задал то и освободил .И никаких лишних "танцев с бубном" вокруг длины строки ...
(Что с учетом кодировки UTF8 задача временами не тривиальная )
Ответить