Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 11.06.2011, 22:49   #11
spamer
Software Developer
Старожил
 
Аватар для spamer
 
Регистрация: 19.12.2008
Сообщений: 2,070
По умолчанию

Кстати, как вариант можно было бы использовать memory mapped file...Хотя не до конца известно, что нужно будет в конце...
Будь проще и люди к тебе потянутся
spamer вне форума Ответить с цитированием
Старый 12.06.2011, 00:37   #12
Alter
Старожил
 
Аватар для Alter
 
Регистрация: 06.08.2007
Сообщений: 2,183
По умолчанию

Пепел Феникса, хорошо, но не загромождает ли он код. В интернете, что-то не встречал в примерах плагинов, чего-то похожего на то, что пишет mss.

mss Чего нервничаем? Не все сразу гении. Создается впечатление, что думаета так "Я д’Артаньян, а вы все *овно". Не надо набрасываться. Форум создан для помощи. Если не хотели отвечать, не отвечали бы, прошли бы мимо.
Цитата:
Сообщение от mss Посмотреть сообщение
Хрен редьки не слаще.
Ты хоть задумался что происходит при StrPCopy ?
Цитата:
Функция StrPCopy(Dest: PChar; const Source: string ):PChar;

Функция копирует Паскаль-строку Source в длинную строку Dest и возвращает указатель на Dest. Данная функция не производит проверку длины, поэтому для того, чтобы не возникало ошибок необходимо, чтобы результирующая строка вмещала Length(Source) + 1 символ.
не?

Вариант 2: отсюда "Преобразование String в PChar"

...

...
Вариант 3: пользователь сам себе выбирает сколько и куда копировать, этот вариант оставался на последок.

Цитата:
Будет мудрым решением не путать компилятор смешением переменных PChar и String, только если вы точно не знаете, что вы делаете. Компилятор не воспринимает PChar как String, поэтому он не будет менять счётчик ссылок строковых буферов, если вы нацелите на них PChar. Часто наилучшим решением будет отказ от подобного использования PChar. Просто используйте обычные строки, и делайте приведение типов только в последний момент. Функции, принимающие параметр PChar, должны копировать текст параметра в свои собственные переменные.

Обычно строковые буфера имеют размер достаточный только для того, чтобы вместить лежащий в них (присвоенный им) текст. Но используя SetLength, вы можете установить произвольный размер строки (в символах). Это делает строки полезными для использования в качестве буферов. Например, вызов функции Windows API, которая возвращает текст в символьном массиве, может выглядеть так:

Код:
function WindowsDirectory: string;
begin
  SetLength(Result, MAX_PATH);
  GetWindowsDirectory(PChar(Result), Length(Result));
  SetLength(Result, StrLen(PChar(Result)));
end;
Альтернативно, вы можете присвоить PChar-у String, и в результате у вас получится новая строка с копией текста. Поэтому вы можете установить длину строки с помощью такого эквивалентного кода:

Код:
Result := PChar(Result);
Последняя строка в функции устанавливает размер строки равный размеру нуль-терминированной C-строке, записанной в ней (длина C-строки всегда меньше или равна длине её String-хранилища – прим.пер.). Если вам нужен результат как PChar-строка для дальнейших действий (например для передачи в другие API-функции), вы могли бы попробовать использовать такой код:

Код:
// ПРЕДУПРЕЖДЕНИЕ: ПЛОХОЙ ПРИМЕР
function WindowsDirectoryAsPChar: PChar;
var
  Buffer: array[0..MAX_PATH] of Char;
begin
  GetWindowsDirectory(Buffer, MAX_PATH);
  Result := Buffer;
end;
Однако, это не будет работать. Потому что Buffer является локальной переменной, хранящейся целиком в локальной памяти (процессорном стеке). Как только вы покидаете эту функцию, память, которая была выделена под Buffer, начинает использоваться другими подпрограммами, так что текст, который лежал в буфере, становится мусором. Вы никогда не должны использовать локальные переменные для возвращаемых значений PChar.

Вы могли бы обойти это, делая динамическое выделения памяти для возвращаемого PChar, с помощью, например, StrAlloc, но тогда вызывающему пришлось бы руками освобождать выделенный вами буфер. Обычно, это не самый лучший подход. Лучше следовать примеру GetWindowsDirectory, и позволить вызывающему указать свой буфер и его размер. Тогда вы просто заполните уже готовый буфер (используя StrLCopy) своими данными до допустимого размера.

Есть и альтернативная реализация функции WindowsDirectory, которая может использовать локальный буфер. Это основывается на том, что вы можете присваивать PChar строке String напрямую. Чтобы сделать текст строкой Delphi (с служебными полями длины и счётчиком сылок), будет создан строковый буфер требуемой длины, а текст будет скопирован в него. Поэтому, даже если локальный буфер будет удалён, то текст в строковом буфере всё ещё будет с нами:

Код:
function WindowsDirectory: string;
var
  Buffer: array[0..MAX_PATH] of Char;
begin
  GetWindowsDirectory(Buffer, MAX_PATH);
  Result := Buffer; // Копируется StrLen(Buffer) символов!
end;
...

Последний раз редактировалось Stilet; 12.06.2011 в 11:37.
Alter вне форума Ответить с цитированием
Старый 12.06.2011, 00:39   #13
Alter
Старожил
 
Аватар для Alter
 
Регистрация: 06.08.2007
Сообщений: 2,183
По умолчанию

...
Цитата:
Но как вам написать функцию, например в DLL, которая должна возвращать данные как PChar? Я думаю, что вы снова можете следовать примеру GetWindowsDirectory. Вот пример простой функции из DLL, возвращающей строку версии:

Код:
// Иметь отдельную функцию для получения длины проще, 
// чем просить GetDLLVersion вернуть длину при nil аргументе.
function GetDLLVersionLength: Integer;
begin
  Result := Length(DLLVersion + IntToStr(VersionNum));
end;
 
// Возвращаем длину скопированных символом, исключая терминатор
function GetDLLVersion(Buffer: PChar; MaxLen: Integer): Integer;
begin
  if (Buffer <> nil) and (MaxLen > 1) then
begin
  StrLCopy(Buffer, PChar(DLLVersion +IntToStr(VersionNum)), MaxLen - 1);
  Result := StrLen(Buffer);
end
else
  Result := 0;
end;
Как вы можете видеть, строка просто копируется в предоставленный вызывающим буфер с помощью StrLCopy. Поскольку вызывающий обязан подготовить буфер, вы избегаете любых проблем с управлением памятью. Если вы предоставляете буфер, то вы и знаете, как его удалять. FreeMem не будет работать через границу DLL (в общем случае). Но даже если бы работала (например, с использованием общего менеджера памяти – прим.пер.), то пользователь вашей DLL, работающий в C или Visual Basic, не знал бы, как освободить буфер в своём языке, т.к. управления памятью индивидуально в каждом языке. Позволяя вызывающему указывать свой буфер, вы делаете его или её независимыми от вашей реализации.
PChars: сами строки не включены

Код:
// Иметь отдельную функцию для получения длины проще, 
// чем просить GetDLLVersion вернуть длину при nil аргументе.
function GetDLLVersionLength: Integer;
begin
  Result := Length(DLLVersion + IntToStr(VersionNum));
end;
 
// Возвращаем длину скопированных символом, исключая терминатор
function GetDLLVersion(Buffer: PChar; MaxLen: Integer): Integer;
begin
  if (Buffer <> nil) and (MaxLen > 1) then
begin
  StrLCopy(Buffer, PChar(DLLVersion +IntToStr(VersionNum)), MaxLen - 1);
  Result := StrLen(Buffer);
end
else
  Result := 0;
end;
__________________________________

Для удобства сделал такую функцию
Код:
function GetStrToBuffer(Txt :string; Buffer: PChar; MaxLen: Integer):Integer;
begin
 if (Buffer <> nil) and (MaxLen > 1) then
 begin
  StrLCopy(Buffer,
           PChar(Txt),
           MaxLen - 1);
  Result := StrLen(Buffer);
 end
  else
 Result := 0;
end;
внутри dll выглядит так, например
Код:
function AAA(Buffer :PChar; MaxLen: Integer):Integer; stdcall;
begin
  Result := GetStrToBuffer(TextString, Buffer, MaxLen);
end;

Последний раз редактировалось mihali4; 18.10.2011 в 22:57.
Alter вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

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

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как правильно передать несколько разнородных данных из одной формы в другую? tumanovalex C# (си шарп) 2 21.05.2011 10:05
Как передать значение пременной из одной функции в другую? mr.-parker Общие вопросы C/C++ 2 27.03.2010 15:01
C#: Передать значение переменной из одной формы в другую Veiron Общие вопросы .NET 3 29.06.2009 17:43
из одной процедуры в другую... Vremya-Dengy Общие вопросы Delphi 10 09.03.2009 23:51
DLL + Процедуры(не функции) LEKA Общие вопросы Delphi 1 02.05.2007 20:37