Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.02.20;
Скачать: CL | DM;

Вниз

Опять приведение PChar к String   Найти похожие ветки 

 
Ega23 ©   (2005-02-07 11:30) [0]

Есть DLL, в ней по данному Alias"у происходит коннект к БД, возвращает password для sa:

function GetKedrPwd(var pwd:String; var ErrMess:String;
                   const AliasName:String="KEDR" ):Boolean;

type
TGetNewParamFunction=function(AliasName:PChar):PChar; StdCall;
var
ss:string;
GetNewParamFunction:TGetNewParamFunction;
LibHandle:THandle;
aAliasName:PChar;
p:Pchar;
begin
Result:=False;
ErrMess:="";
@GetNewParamFunction:=nil;
pwd:="";
try
 LibHandle:=LoadLibrary("kedrlcd.dll");
 @GetNewParamFunction:=GetProcAddress(LibHandle, "GetNewParam");
 if @GetNewParamFunction<>nil then
  begin
   aAliasName:=StrAlloc(Length(AliasName)+1);
   aAliasName:=StrPCopy(aAliasName, AliasName);
   p:=GetNewParamFunction(aAliasName);
   ss:=String(p);
   StrDispose(aAliasName);
  end;

 FreeLibrary(LibHandle);
except on E:Exception do
 begin
  ErrMess:=E.Message;
  Exit;
 end;
end;
Result:=True;
pwd:=ss;
end;


Внутри библиотеки всё отрабатывается корректно, проверял.
На ss:=String(p); происходит вылет по AV.

В чём может быть причина?


 
Игорь Шевченко ©   (2005-02-07 11:35) [1]

SetString не проще ?


 
Ega23 ©   (2005-02-07 11:48) [2]

2 Игорь Шевченко ©   (07.02.05 11:35) [1]

Проблема в том, что я в отладчике значения P не вижу....   :-(


 
Владислав ©   (2005-02-07 11:50) [3]

Покажу функцию из DLL.


 
Ega23 ©   (2005-02-07 12:04) [4]

Функция из DLL:
function GetNewParam(aAliasName:PChar):PChar; StdCall;
   function CodeIt(aStr,aKey:string):string;
   begin
     ................
     Result:=S;
   end;

const
stdsql="select LimitNum from dbo.paramsglb";
xkey="836519";

var
DB:TDataBase;
Qu:TQuery;
ss:string;

begin
Result:="";
try
  DB:=TDataBase.Create(nil);
  try
   With DB do
    begin
     AliasName := String(aAliasName);
     DatabaseName := "BD0";
     LoginPrompt:=False;
     Params.Clear;
     Params.Add("USER NAME=KEDR0");
     Params.Add("SQLQRYMODE=SERVER");
     Params.Add("PASSWORD=");
     Connected:=True;
    end; //With DB do
   Qu:=TQuery.Create(nil);
   try
    With Qu do
     begin
      DatabaseName:=DB.DatabaseName;
      RequestLive:=True;
      SQL.Text:=stdsql;
      Open;
      if (Active) and (not IsEmpty) then
       begin
        ss:=Fields[0].AsString;
        ss:=CodeIt(ss, xkey);
        Result:=PChar(ss);
       end;
     end;
   finally
    Qu.Active:=False;
    Qu.Free;
   end;
  finally
   DB.Connected:=False;
   DB.Free;
  end;
except

end;
end;

//*************************************************************************************

exports

GetNewParam    name    "GetNewParam";


 
Anatoly Podgoretsky ©   (2005-02-07 12:09) [5]

Ega23 ©   (07.02.05 11:30)  
приведение PChar к String не возможно, структура разная, возможно только преобразование из PChar в String.

Что такое Result:=S;


 
Ega23 ©   (2005-02-07 12:15) [6]

Что такое Result:=S;

Там кодирование-декодирование пароля происходит. S - внутренняя переменная функции function CodeIt(aStr,aKey:string):string;, раздел var и текст функции пропустил, экран засорять не стал.


 
Игорь Шевченко ©   (2005-02-07 12:16) [7]

Нельзя возвращать указатель на локальную в функции строку. Она же уничтожается.


 
Ega23 ©   (2005-02-07 12:23) [8]

2 Игорь Шевченко ©   (07.02.05 12:16) [7]

Да я вот тоже "нутром" чую, что всё неправильно делаю.

Хорошо, попытаюсь описать задачу:
Есть БД под MS SQL 2000. На базу существует 2 логина: первый входит в роль SA, второй имеет права на чтение одной единственной таблицы. В этой таблице лежит закодированный пароль для первого логина.

Действия клиента: коннект по второму логину (пароля на него нет), полуение пароля, ре-коннект под первым логином с полученным pwd.

Задача: написать DLL, которая по некоему алиасу соединяется с базой, получает пароль и возвращает его "наверх".

По-идее, это должна быть DLL с одной единственной функцией.

Вот как можно "изгольнуться" и получить этот чёртов пароль?


 
Ega23 ©   (2005-02-07 12:26) [9]

2 Игорь Шевченко ©   (07.02.05 12:16) [7]

Игорь, если я тебя правильно понял, то внутри библтотеки надо выделить память под Result, записать туда полученный пароль, после чего вернуть указатель на эту выделенную память.
Теперь вопрос: а где мне потом эту память высвобождать? На клиенте? Но так, вроде, нельзя делать, т.к. адресные пространства у DLL и клиента - разные...


 
SVM (Perm)   (2005-02-07 12:30) [10]

Используй, например, CoTaskMemAlloc/CoTaskMemFree или SysAllocString/SysFreeString или GlobalAlloc/GlobalFree...


 
Владислав ©   (2005-02-07 12:32) [11]

Тебе же уже отвечали, что выделять и освобождать память нужно в одном и том же месте, если использовать менеджер памяти borland"а.

Как пример:

function GetNewParam(aAliasName:PChar; var Pass: PChar; var PassLen: DWORD):PChar; StdCall;
begin
...
 GetMem(Pass, Length(ResultStr));
 Move(Pointer(ResultStr)^, Pass^, Length(ResultStr));
 PassLen := Length(ResultStr);
 Result := Pass;
...
end;

procedure FreePass(Pass: PChar);
begin
 FreeMem(Pass);
end;


Есть и другие варианты...


 
Ega23 ©   (2005-02-07 12:36) [12]

Тебе же уже отвечали, что выделять и освобождать память нужно в одном и том же месте, если использовать менеджер памяти borland"а.


Это я понимаю. фишка в том, что нужно по-возможности обойтись ОДНОЙ(!) экпортной функцией в DLL.

Есть, правда, вариант - освобождать память по данному указателю в секции finalization внутри DLL.
Но тут у меня тоже вопросы - с ней (секцией) никогда не работал, поэтому не знаю, насколько это корректно будет...


 
Владислав ©   (2005-02-07 12:39) [13]

CoTaskMemAlloc/CoTaskMemFree
Спасет отца русской демократии ;)


 
Ega23 ©   (2005-02-07 12:41) [14]

CoTaskMemAlloc/CoTaskMemFree

Сейчас попробую...


 
Ega23 ©   (2005-02-07 12:45) [15]

2 Владислав ©   (07.02.05 12:39) [13]

CoTaskMemAlloc - это получается, что кроме указателя мне ещё и длину в байтах возвращать надо?


 
Jay1982 ©   (2005-02-07 12:46) [16]

Можно изпользовать ShortString и никаких тебе указателей и неосвобождённой памяти


 
Ega23 ©   (2005-02-07 12:50) [17]

2 Jay1982 ©   (07.02.05 12:46) [16]

Теоретически - можно. Практически - не все клиенты на Delphi пишутся...


 
Ega23 ©   (2005-02-07 12:50) [18]

2 Jay1982 ©   (07.02.05 12:46) [16]

Теоретически - можно. Практически - не все клиенты на Delphi пишутся...


 
Игорь Шевченко ©   (2005-02-07 12:51) [19]

Олег, не извращайся, а передай вторым параметром буфер под нужную строку. Как делают все API-шные функции. И не нужно никаких CoTaskMem...

С уважением,


 
Anatoly Podgoretsky ©   (2005-02-07 13:02) [20]

Адресные пространства у DLL и клиента - одинаковые!

Судя по скромному описанию задачи ты что то делаешь неправильно, не надо никого включать в роль SA, надо просто задуматься над правильной раздачей прав, чтобы клиент всегда работал под самим собой, а не под администратором. Как разграничить права только ты можешь решить.

По поводу памяти уже много описали, правила простые выделять и освобождать должен тот кто требует. Ограничиться только простыми типами, типа PChar, в функцию передавать размер выделенной памяти -1. Если размера недостаточно то возвращать ошибку, в качестве ошибки использовать требуемый размер для результата, в случае успешного исполнения возвращать 0. Данный механизм хорошо себя зарекомендовал в АПИ, где он широко использувется.

А насчет прав и хранения паролей серьезно подумай еще раз. Система становится небезопасной.


 
Anatoly Podgoretsky ©   (2005-02-07 13:10) [21]

Пример функции

function GetPwd(Pwd: PChar; BufLen: Integer; AliasName: PChar): Integer;

Вызов может выглядеть так

SetLength(Pwd, 16);
LG := GetPwd(Pwd, Length(Pwd), "AliasName");
if LG = 0 then Pwd := PChar(Pwd) else Error;

Нужный размер и пароль можно еще получить так
LG := GetPwd(Pwd, 0, "AliasName");
SetLength(Pwd, LG);
GetPwd(Pwd, LG, "AliasName");
Pwd := PChar(Pwd);


 
Ega23 ©   (2005-02-07 13:12) [22]

2 Anatoly Podgoretsky ©   (07.02.05 13:02) [20]
По поводу памяти уже много описали, правила простые выделять и освобождать должен тот кто требует. Ограничиться только простыми типами, типа PChar, в функцию передавать размер выделенной памяти -1. Если размера недостаточно то возвращать ошибку, в качестве ошибки использовать требуемый размер для результата, в случае успешного исполнения возвращать 0. Данный механизм хорошо себя зарекомендовал в АПИ, где он широко использувется.

Так. Насколько я понял, функция в DLL тогда приобретает следующий вид:

function GetNewParam(aAliasName:PChar; aPass:PChar; BuffLength:Cardinal):Cardinal; StdCall;


aPass:PChar  -  указатель на область памяти, выделенной в клиенте
BuffLength - размер выделенной памяти.

Тогда задача на выделение и освобождение памяти ложится на клиента...

Идея мне нравится!

А насчет прав и хранения паролей серьезно подумай еще раз. Система становится небезопасной.

Боюсь, что в данной ситуации я ничего не могу сделать - не я это решаю...  :-(


 
Anatoly Podgoretsky ©   (2005-02-07 13:17) [23]

Забыл про приведение к PChar
GetPwd(PChar(Pwd), LG, "AliasName");


 
Владислав ©   (2005-02-07 13:32) [24]

На прежней работе авторизация к базе была построена на подобной криворукой системе. И там тоже ничего изменить было нельзя :(


 
Anatoly Podgoretsky ©   (2005-02-07 14:52) [25]

При такой методе, враги сожгут родную хату.


 
Владислав ©   (2005-02-07 15:28) [26]

> Anatoly Podgoretsky ©   (07.02.05 14:52) [25]

Это знают все до начальника подразделения информационных технологий (выше только ген. директор). Тем не менее живут с этим и по сей день.
К слову сказать, это авторизация в большом финансовом (стороннем) программном продукте. SCALA называется. Как они на это пошли?..



Страницы: 1 вся ветка

Текущий архив: 2005.02.20;
Скачать: CL | DM;

Наверх




Память: 0.54 MB
Время: 0.034 c
8-1099699905
Лёха
2004-11-06 03:11
2005.02.20
JpegImage в TFileStream


4-1100806177
Anis
2004-11-18 22:29
2005.02.20
shut down,restart windows for ws XP,NT


4-1104775713
Комбинатор
2005-01-03 21:08
2005.02.20
Запрет на удаление процесса по средвам ACL


3-1106300120
juice
2005-01-21 12:35
2005.02.20
Вставка записи.


1-1107514581
Brenagwynn
2005-02-04 13:56
2005.02.20
Распарсить большой текстовый файл