Форум программистов, компьютерный форум, киберфорум
Delphi
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.76/29: Рейтинг темы: голосов - 29, средняя оценка - 4.76
0 / 0 / 1
Регистрация: 16.07.2013
Сообщений: 24

Работа с Pchar

04.10.2013, 16:11. Показов 6168. Ответов 16
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день!
У меня есть задача. Hанее почти не работал с PChar.
Помогите разобраться. В длл есть функция:

GetCfgData(var Info:TPosInfo): Byte(возвращает код ошибки)

при запуске в коде программы эта функция должна получить данные из длл
в TPosIno.
Где TPosInfo = record
Open: Byte
SerNo: PChar (указатель на буфер серийного номера, min размер 12+1 байт)

Вопрос: рак реализовать работу этой функции. Не совсем понимаю как работать с Pchar. Кто может объяснить как описать это в коде программы. И как далее работать с полем SerNo. В теории это должен быть серийный номер устройства.

вот например так:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
TYPE
TPosInfo = record
    Open: Byte;
    SerNo: PChar;
end;
 
GetCfgData  : function(var Info: TPosInfo): Byte; stdcall;
...
Var
   ConfigData: TPosInfo;
...
begin
  Answer:= GetCfgData(ConfigData);
...
end.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
04.10.2013, 16:11
Ответы с готовыми решениями:

Как переступить через #0 в PChar ?
К примеру Функция_В_ДЛЛ SetStr(Value: PChar): PChar; stdcall; begin // Валуя должна равняться := 'abcd' + #0 + #0 + 'abcd' ...

String - '1234567890123456SomethingElse' PChar - '1234567890123456'
Проблема вот какая: при переводе строки String в строку PChar: PChar('asdf' + bbb + 'dsaf'), где bbb - типа String возникает...

Неудачное преобразование string в pChar
В общем на рисунке кусок кода и результат его выполнения в отладчике. Функция получает получает string в качестве параметра, если к этому...

16
Пишу на Delphi...иногда
 Аватар для cotseec
1423 / 1278 / 286
Регистрация: 03.12.2012
Сообщений: 3,914
Записей в блоге: 5
04.10.2013, 18:15
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
TYPE
TPosInfo = record
    Open: Byte;
    SerNo: PChar;
end;
 
GetCfgData  : function(var Info: TPosInfo): Byte; stdcall;
...
Var
   ConfigData: TPosInfo;
...
begin
   ConfigData.SerNo := StrAlloc(13);// указатель на буфер серийного номера, min размер 12+1 байт
   Answer:= GetCfgData(ConfigData);
   if Answer <> {код какой-то ошибки} then
     MessageBox(0, ConfigData.SerNo, 'SerNo', 0);
   StrDispose(ConfigData.SerNo);
...
end.
0
0 / 0 / 1
Регистрация: 16.07.2013
Сообщений: 24
09.10.2013, 14:56  [ТС]
Цитата Сообщение от cotseec Посмотреть сообщение
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
TYPE
TPosInfo = record
    Open: Byte;
    SerNo: PChar;
end;
 
GetCfgData  : function(var Info: TPosInfo): Byte; stdcall;
...
Var
   ConfigData: TPosInfo;
...
begin
   ConfigData.SerNo := StrAlloc(13);// указатель на буфер серийного номера, min размер 12+1 байт
   Answer:= GetCfgData(ConfigData);
   if Answer <> {код какой-то ошибки} then
     MessageBox(0, ConfigData.SerNo, 'SerNo', 0);
   StrDispose(ConfigData.SerNo);
...
end.
Спасибо за помощь! Тут все хорошо.
Возник другой вопрос как к примеру через ConfigData правильно передать в функцию данные. Пример.

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
TPosInfo = record
    Open: Byte;
    SerNo: PChar;
end;
 
GetCfgData  : function(var Info: TPosInfo): Byte; stdcall;
...
Var
   ConfigData: TPosInfo;
...
begin
   ConfigData.SerNo := StrAlloc(13);// указатель на буфер серийного номера, min размер 12+1 байт
 
   ConfigData.SerNo := 'test'; // вариант 1
   StrPCopy(ConfigData.SerNo,'test'); //вариант 2
   ConfigData.SerNo := PChar('test'); // вариант 3
 
   Answer:= GetCfgData(ConfigData);
   if Answer <> {код какой-то ошибки} then
     MessageBox(0, ConfigData.SerNo, 'SerNo', 0);
   StrDispose(ConfigData.SerNo);
тут указано 3 способа присвоения данных
По идее верный только вариант 2.

Вариант 1 по сути переопределяет указатель на строку "test" и тогда в ConfigData.SerNo := StrAlloc(13) нет никакого смысла так как мы меняем адрес.

Вариант 3 делает тоже самое с приведением типа

Вариант 2 копирует строку по адресу который мы указали

правильно ли я понимаю??
Важно: нужно поместить данные именно по адресу выделенному в ConfigData.SerNo := StrAlloc(13)
может есть еще способы?
0
angstrom
09.10.2013, 15:13
Для
Delphi
1
2
ConfigData.SerNo := 'test';
ConfigData.SerNo := PChar('test');
память выделять не требуется. Для 2-го варианта нужно выделить.
 Аватар для Mawrat
13114 / 5895 / 1708
Регистрация: 19.09.2009
Сообщений: 8,809
09.10.2013, 15:34
Добавлю.
Цитата Сообщение от Smallboy Посмотреть сообщение
В длл есть функция:
GetCfgData(var Info:TPosInfo): Byte(возвращает код ошибки)
В отношении этой функции надо узнать, как происходит работа с параметром Info. Если этот параметр служит только для возвращения данных из функции, то память для нуль-терминальной строки, скорее всего, должна выделять вызываемая функция. А освобождать память должна вызывающая программа.
Если параметр Info служит также для передачи данных в функцию, то выделять память должна вызывающая программа. Причём, если функция не заменяет нуль-терминальную строку, а изменяет значение в ней, то вызывающая программа должна разместить нуль-терминальную строку в динамической памяти. Т. е., в этом случае приемлем вот такой способ в задании нуль-терминальной строки:
Delphi
1
2
3
4
5
6
7
8
9
var
  S : String;
...
begin
...
  ConfigData.SerNo := StrAlloc(12 + 1); //+ 1 - так мы учитываем терминальный ноль.
  StrPCopy(ConfigData.SerNo, 'test');
...
end;
А способ с передачей указателя на статические данные уже будет недопустим:
Delphi
1
ConfigData.SerNo := 'test';
Потому что функция не сможет поменять содержимое, расположенное в статической памяти.

В общем, действия зависят от логики работы функции. Надо начать именно с этого - выяснить как функция использует параметр Info.
0
0 / 0 / 1
Регистрация: 16.07.2013
Сообщений: 24
09.10.2013, 15:50  [ТС]
Цитата Сообщение от Mawrat Посмотреть сообщение
Добавлю.

В отношении этой функции надо узнать, как происходит работа с параметром Info. Если этот параметр служит только для возвращения данных из функции, то память для нуль-терминальной строки, скорее всего, должна выделять вызываемая функция. А освобождать память должна вызывающая программа.
Если параметр Info служит также для передачи данных в функцию, то выделять память должна вызывающая программа. Причём, если функция не заменяет нуль-терминальную строку, а изменяет значение в ней, то вызывающая программа должна разместить нуль-терминальную строку в динамической памяти. Т. е., в этом случае приемлем вот такой способ в задании нуль-терминальной строки:
Delphi
1
2
3
4
5
6
7
8
9
var
  S : String;
...
begin
...
  ConfigData.SerNo := StrAlloc(12 + 1); //+ 1 - так мы учитываем терминальный ноль.
  StrPCopy(ConfigData.SerNo, 'test');
...
end;
А способ с передачей указателя на статические данные уже будет недопустим:
Delphi
1
ConfigData.SerNo := 'test';
Потому что функция не сможет поменять содержимое, расположенное в статической памяти.

В общем, действия зависят от логики работы функции. Надо начать именно с этого - выяснить как функция использует параметр Info.
Если брать полную картину то работа идет так:

function(var SendInfo: Info1 , var GetInfo: Info2): Byte

данные передаются через SendInfo: Info1
ответ передают назад в программу через GetInfo: Info2

Если с получением данных разобрался(2-й пост).
То с передачей возникли проблемы.
Для каждого поля рекорда указан объем передаваемых данных (например 12+1). Т.е необходимо выделять и освобождать память и в процессе присваивания данных не менять выделенный адрес.

Я так понял этот вариант единственно возможный:

ConfigData.SerNo := StrAlloc(12 + 1); //+ 1 - так мы учитываем терминальный ноль.
StrPCopy(ConfigData.SerNo, 'test');
StrDispose(ConfigData.SerNo);


P.S. и еще как поступать в таком случае. Для разных полей размер данных указан по разному
к примеру:
min размер 12+1
max размер 184
или вообще не указан

как лучше действовать в таких случаях
0
angstrom
09.10.2013, 16:03
Кто мешает выделить сразу по максимуму?
 Аватар для Mawrat
13114 / 5895 / 1708
Регистрация: 19.09.2009
Сообщений: 8,809
09.10.2013, 16:29
Цитата Сообщение от Smallboy Посмотреть сообщение
Я так понял этот вариант единственно возможный:
ConfigData.SerNo := StrAlloc(12 + 1); //+ 1 - так мы учитываем терминальный ноль.
StrPCopy(ConfigData.SerNo, 'test');
StrDispose(ConfigData.SerNo);
Да, верно - это для тех данных, которые передаются из вызывающей программы - в функцию.
Что касается тех данных, которые функция передаёт в вызывающую программу (Info2) - там ведь тоже есть нуль-терминальная срока. И память, которая выделена для этой строки, должна освободить вызывающая программа. Вот в этом случае надо решить, какой функцией эту память освободить. Если функция написана на Delphi и если паять для нуль-терминальных строк выделяется в теле функции через вызов StrAlloc(), то освобождать такую память надо через вызов StrDispose().
А если функция писалась, например, на Си или на Delphi и для нуль-терминальной строки память выделялась через AllocMem() или GetMem(), например, то освобождать память надо через вызов FreeMem():
Delphi
1
2
3
Len := StrLen(ConfigData.SerNo) + 1;
FreeMem(ConfigData.SerNo, Len * SizeOf(Char));
ConfigData.SerNo := nil;
Добавлено через 19 минут
Цитата Сообщение от Smallboy Посмотреть сообщение
P.S. и еще как поступать в таком случае. Для разных полей размер данных указан по разному
Цитата Сообщение от angstrom Посмотреть сообщение
Кто мешает выделить сразу по максимуму?
Согласен с angstrom - для входных параметров задавать наибольшую длину строки.
0
0 / 0 / 1
Регистрация: 16.07.2013
Сообщений: 24
09.10.2013, 16:35  [ТС]
Цитата Сообщение от Mawrat Посмотреть сообщение
Да, верно - это для тех данных, которые передаются из вызывающей программы - в функцию.
Что касается тех данных, которые функция передаёт в вызывающую программу (Info2) - там ведь тоже есть нуль-терминальная срока. И память, которая выделена для этой строки, должна освободить вызывающая программа. Вот в этом случае надо решить, какой функцией эту память освободить. Если функция написана на Delphi и если паять для нуль-терминальных строк выделяется в теле функции через вызов StrAlloc(), то освобождать такую память надо через вызов StrDispose().
А если функция писалась, например, на Си или на Delphi и для нуль-терминальной строки память выделялась через AllocMem() или GetMem(), например, то освобождать память надо через вызов FreeMem():
Delphi
1
2
3
Len := StrLen(ConfigData.SerNo) + 1;
FreeMem(ConfigData.SerNo, Len * SizeOf(Char));
ConfigData.SerNo := nil;
Добавлено через 19 минут


Согласен с angstrom - для входных параметров задавать наибольшую длину строки.
память для данных которые функция передает в программу также выделяется в программе.
в функцию передается адрес памяти куда она и записывает данные
0
 Аватар для Mawrat
13114 / 5895 / 1708
Регистрация: 19.09.2009
Сообщений: 8,809
09.10.2013, 16:35
Или так (входной параметр, передаваемый в функцию):
Delphi
1
2
3
4
5
6
7
//Это какая-то строка, которую надо передать в функцию в виде нуль-терминальной строки.
S := 'XXXXXX';
StrAlloc(ConfigData.SerNo, Length(S) + 1);
StrPCopy(ConfigData.SerNo, PChar(S));
GetCfgData(...);
StrDispose(ConfigData.SerNo);
ConfigData.SerNo := nil;
0
0 / 0 / 1
Регистрация: 16.07.2013
Сообщений: 24
09.10.2013, 16:43  [ТС]
Остался последний вопрос
к примеру один из выходных параметров равен ' ' или nill
StrPCopy(ConfigData.SerNo, ' ');

как данное преобразование будет влиять на данные записанные по адресу.
Необходимо чтобы функция понимала их как nill или как ' '
0
angstrom
09.10.2013, 16:53
Цитата Сообщение от Smallboy Посмотреть сообщение
равен ' '
Так это пробел или пустые кавычки? Пока написан пробел. Как там работает функция не знаю, но может вернуть NIL или #0.
0 / 0 / 1
Регистрация: 16.07.2013
Сообщений: 24
09.10.2013, 17:13  [ТС]
Цитата Сообщение от angstrom Посмотреть сообщение
Так это пробел или пустые кавычки? Пока написан пробел. Как там работает функция не знаю, но может вернуть NIL или #0.
пустые кавычки, в функцию тоже можно передавать nill или пустые кавычки. При их получении lданных параметров функция будет брать значение по умолчанию. Вот поэтому и волнует передадутся ли nil или ''.
0
 Аватар для Mawrat
13114 / 5895 / 1708
Регистрация: 19.09.2009
Сообщений: 8,809
09.10.2013, 17:18
Цитата Сообщение от Smallboy Посмотреть сообщение
к примеру один из выходных параметров равен ' ' или nill
StrPCopy(ConfigData.SerNo, ' ');
Это, как я понял, входной, а не выходной параметр? Т. е., входной по отношению к функции - мы подготавливаем нуль-терминальную строку, которую намереваемся передать в функцию.
Цитата Сообщение от Smallboy Посмотреть сообщение
к примеру один из выходных параметров равен ' ' или nill
StrPCopy(ConfigData.SerNo, ' ');
Пустую нуль-терминальную строку (это указатель на #0) - правильно обработает.
0
angstrom
09.10.2013, 17:24
Цитата Сообщение от Smallboy Посмотреть сообщение
пустые кавычки
Смотри внимательно, пробел написан. Так и в функцию отдашь пробел вместо пустой строки.
0 / 0 / 1
Регистрация: 16.07.2013
Сообщений: 24
10.10.2013, 16:32  [ТС]
Всем спасибо господа! Все отлично работает!
Правда в ХЕ2 не получилось, ошибки в кодировках какие-то при приеме-передаче данных через PChar. Не смог разобраться в чем дело.
В D7 все отлично работает.
0
пофигист широкого профиля
4769 / 3204 / 862
Регистрация: 15.07.2013
Сообщений: 18,612
10.10.2013, 16:49
Цитата Сообщение от Smallboy Посмотреть сообщение
Правда в ХЕ2 не получилось
В ХЕ2 надо было перед каждым буквосочетанием CHAR вставить ANSI. И перед каждым STRING.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
10.10.2013, 16:49
Помогаю со студенческими работами здесь

Как конвертировать формат String в PChar?
Как конвертировать формат String в PChar? К примеру я хочу чтобы высвечивалось сообщение MessageBox текст в которой брался бы из...

Нуль-терминальные строки PChar, StrCopy() ошибка.
Собсна необходимо сложить несколько PChar строк, решил заюзать strcat, синтакс. ошибок не было никаких, но при запуске вылетает ошибка. ...

работа с указателями Pchar
имеется код type pstr = ^UnicodeString; var Form1: TForm1; k1:pointer; k2:pointer;

Pchar из dll
в общем, требуется написать UDF под интербазу, катаем dll library UDFStr2; // uses // SysUtils; function...

Вывод текста PChar
подскажите почему выводит лишние символы var f: File; Size, i: Integer; Buffer: PChar; begin AssignFile(f,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Новые блоги и статьи
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru