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

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

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

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 18.02.2012, 22:45   #1
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию XE2 DLL < = > EXE. Убийственная передача строк.

Доброго времени суток!

Накопал информации по поводу этого.
Понял 2 вещи:
1. для передачи строк из/в dll использовать PChar(ShareMem нужен? Если да, то как без него можно обойтись?)
2. внутри функций exe/dll приводить PChar к строке.

Играюсь на xe2..

Есть такой код:
Код:
function InitDLL(aPEFile: PChar): NativeInt; cdecl;
var
 str:string;
begin
  str:=WideCharToString(aPEFile); //Привожу PWideChar к WideString
  if FileExists(str) then
  begin
    sHLPath := ExtractFilePath(str); //Вот тут ацкий бзик Incompatible types: 'PWideChar' and 'string'
    Result := fRESULT_OK;
  end
  else
  begin
    Result := fRESULT_ERROR;
  end;
end;
почему, когда я в ExtractFilePath передаю WideString он орет, что там PWideChar. Ведь я привел PWideChar к WideString, и все это в str переменной.
Человек_Борща вне форума Ответить с цитированием
Старый 18.02.2012, 22:57   #2
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию

гм, sHLPath было PChar..
Строку внутрь я передаю...

как вернуть её из dll?
Код:
function GetHLPath: PChar; cdecl;
var
s:PWideChar;
begin
  Result := fRESULT_ERROR_s;
  if (sHLPath = '') then
    Exit
  else
  begin
    StringToWideChar(sHLPath,s,Length(sHLPath));
    Result :=s;
  end;
end;
возвращает пустоту.
Человек_Борща вне форума Ответить с цитированием
Старый 18.02.2012, 23:10   #3
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

думаем почему GetWindowText нуждается в размере буфера и так же применяет strcpy(wcscpy если юникод).

http://programmersforum.ru/showthread.php?t=185064
правда там С++ в ДЛЛ, но надеюсь идея понятна.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 19.02.2012, 00:14   #4
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию

хоть убейте, не понимаю как правильно привести WideString к PWideChar
Код:
function GetHLPath: PChar; cdecl;
var
 Buff:array[0..MAX_PATH] of PChar;
begin
  Result := fRESULT_ERROR_s;
  if (sHLPath = '') then
    Exit
  else
  begin
    StringToWideChar(sHLPath,Buff,Length(Buff));
    Result :=Buff;
  end;
end;
Человек_Борща вне форума Ответить с цитированием
Старый 19.02.2012, 00:21   #5
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

у вас не константа, но есть известный лимит, потому можно применить код из поста №9 по ссылке.
далее ошибка в коде, вы память не выделаете под строку в PWideChar.
далее если у вас юникод Делфи то эта функция не нужна, а просто CopyMemory.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 19.02.2012, 00:36   #6
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию

Воспользовался копированием памяти...
Код:
function GetHLPath: PChar; cdecl;
begin
  Result := fRESULT_ERROR_s;
  if (sHLPath = '') then
    Exit
  else
  begin
      CopyMemory(@Result, @sHLPath, Length(sHLPath));
  end;
end;
В этом случае, через WatchList я вижу, что в Result поподает моя строка. Это мне и надо. Но программа вылетает в 0xffffffff т.е. в никуда. Из этого следует, что при копировании куда-то, надо выделить память под это что-то в этом куда-то.

Поступил так:
Код:
function GetHLPath: PChar; cdecl;
var
  s: PChar;
begin
  Result := fRESULT_ERROR_s;
  if (sHLPath = '') then
    Exit
  else
  begin
    try
      s := AllocMem(Length(sHLPath));
      CopyMemory(@s, @sHLPath, Length(sHLPath));
      Result := s;
    finally
      FreeMem(s);
    end;
  end;
end;
Вылетаю опять в AV при FreeMem. И в результате абро-кодабро.
Человек_Борща вне форума Ответить с цитированием
Старый 19.02.2012, 00:45   #7
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

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

как вы думаете, почему функция из тему так же как и GetWindowText принимают буфер?
потому что только пользователь(функции) ответственнен за свой буфер(см код 1), а не программа его навязывает(см код 2).
1)
Код:
function GetHLPath(buf:PWideChar):integer;cdecl;//указал строго тип
begin
  Result := 0;
  if (sHLPath = '') then
    Exit
  else
   begin
      CopyMemory(buf, @sHLPath[1], (Length(sHLPath)+1)*SizeOF(WideChar));
      Result:=sHLPath;
   end;
end;
тут же вызывающий сам выделяет память своими методами.
2)
Код:
function GetHLPath: PWideChar; cdecl;
var
  s: PChar;
begin
  Result := fRESULT_ERROR_s;
  if (sHLPath = '') then
    Exit
  else
  begin
    try
      Result:= AllocMem((Length(sHLPath)+1)*SizeOf(WideChar));
      CopyMemory(s, @sHLPath[1], (Length(sHLPath)+1)*SizeOF(WideChar));
    finally
    end;
  end;
end;
тут то кто вызовет эту функцию должен будет вызвать FreeMem(причем именно от вашего менагера)
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 19.02.2012, 01:02   #8
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию

Цитата:
Result:= AllocMem((Length(sHLPath)+1)*SizeOf (WideChar));
интересный момент, почему так? разве просто длинны строки мало?
Человек_Борща вне форума Ответить с цитированием
Старый 19.02.2012, 01:13   #9
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

1)там количество байт, а WideChar весит 2.
2)а терминальный нуль писать не надо?
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 19.02.2012, 01:18   #10
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию

Понял.

Теперь другая проблема..
FreeMem посылает меня лесом..


DLL
Код:
function GetHLPath: PChar; cdecl;
var
  s: PChar;
begin
  Result := fRESULT_ERROR_s;
  if (sHLPath = '') then
    Exit
  else
  begin
    Result := AllocMem((Length(sHLPath) + 1) * SizeOF(WideChar));
    CopyMemory(Result, @sHLPath[1], (Length(sHLPath) + 1) * SizeOF(WideChar));
  end;
end;
Приложение:
Код:
procedure TForm1.Button2Click(Sender: TObject);
var
  s: string;
  p:PChar;
begin
  p:=GetHLPath;
  s:=WideCharToString(p); //Финт ушами, чтобы не держать место в куче.. 
  FreeMem(@p);  //EXCEPTION

  if s = fRESULT_ERROR_s then
    Memo1.Lines.Add('Call GetHLPath result = ERROR')
  else
  begin
    Memo1.Lines.Add('Call GetHLPath result = ' + s);
  end;
end;
cdecl не самый удобный для соглашения вызова c++ и delphi?

p.s. для использования дельфийской dll в с++, по прежнему нужны танцы с бубном(*.def), при сборке dll в delphi?
Человек_Борща вне форума Ответить с цитированием
Ответ


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Embarcadero Delphi XE2 Partner DVD (Зборник компонентов для XE2) volod3000 Софт 2 01.11.2011 02:26
Передача переменной в EXE Evgen1503 Общие вопросы Delphi 6 03.05.2010 15:56
Передача строк из dll sprofxx Общие вопросы Delphi 9 02.04.2010 07:41
Передача строки exe (с формой (API)) ↔ exe (форма скрыта) Alex Cones Общие вопросы Delphi 16 04.10.2009 15:26
Запуск Load.dll (бывшая Load.exe) в дереве проц-ов, Как запустить прогой на C# .dll-ку kapustin Общие вопросы .NET 10 23.09.2009 22:20