![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Опять приведение PChar к String [D5]
Ega23 © (2005-02-07 11:30:00)Есть 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 15:28:00) [1]> Anatoly Podgoretsky © (07.02.05 14:52) [25]
Это знают все до начальника подразделения информационных технологий (выше только ген. директор). Тем не менее живут с этим и по сей день.
К слову сказать, это авторизация в большом финансовом (стороннем) программном продукте. SCALA называется. Как они на это пошли?..
Anatoly Podgoretsky (2005-02-07 14:52:00) [2]При такой методе, враги сожгут родную хату.
Владислав (2005-02-07 13:32:00) [3]На прежней работе авторизация к базе была построена на подобной криворукой системе. И там тоже ничего изменить было нельзя :(
Anatoly Podgoretsky (2005-02-07 13:17:00) [4]Забыл про приведение к PChar
GetPwd(PChar(Pwd), LG, 'AliasName');
Ega23 (2005-02-07 13:12:00) [5]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:10:00) [6]Пример функции
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);
Anatoly Podgoretsky (2005-02-07 13:02:00) [7]Адресные пространства у DLL и клиента - одинаковые!
Судя по скромному описанию задачи ты что то делаешь неправильно, не надо никого включать в роль SA, надо просто задуматься над правильной раздачей прав, чтобы клиент всегда работал под самим собой, а не под администратором. Как разграничить права только ты можешь решить.
По поводу памяти уже много описали, правила простые выделять и освобождать должен тот кто требует. Ограничиться только простыми типами, типа PChar, в функцию передавать размер выделенной памяти -1. Если размера недостаточно то возвращать ошибку, в качестве ошибки использовать требуемый размер для результата, в случае успешного исполнения возвращать 0. Данный механизм хорошо себя зарекомендовал в АПИ, где он широко использувется.
А насчет прав и хранения паролей серьезно подумай еще раз. Система становится небезопасной.
Игорь Шевченко (2005-02-07 12:51:00) [8]Олег, не извращайся, а передай вторым параметром буфер под нужную строку. Как делают все API-шные функции. И не нужно никаких CoTaskMem...
С уважением,
Ega23 (2005-02-07 12:50:00) [9]2 Jay1982 © (07.02.05 12:46) [16]
Теоретически - можно. Практически - не все клиенты на Delphi пишутся...
Ega23 (2005-02-07 12:50:00) [10]2 Jay1982 © (07.02.05 12:46) [16]
Теоретически - можно. Практически - не все клиенты на Delphi пишутся...
Jay1982 (2005-02-07 12:46:00) [11]Можно изпользовать ShortString и никаких тебе указателей и неосвобождённой памяти
Ega23 (2005-02-07 12:45:00) [12]2 Владислав © (07.02.05 12:39) [13]
CoTaskMemAlloc - это получается, что кроме указателя мне ещё и длину в байтах возвращать надо?
Ega23 (2005-02-07 12:41:00) [13]CoTaskMemAlloc/CoTaskMemFree
Сейчас попробую...
Владислав (2005-02-07 12:39:00) [14]CoTaskMemAlloc/CoTaskMemFree
Спасет отца русской демократии ;)
Ega23 (2005-02-07 12:36:00) [15]Тебе же уже отвечали, что выделять и освобождать память нужно в одном и том же месте, если использовать менеджер памяти borland'а.
Это я понимаю. фишка в том, что нужно по-возможности обойтись ОДНОЙ(!) экпортной функцией в DLL.
Есть, правда, вариант - освобождать память по данному указателю в секции finalization внутри DLL.
Но тут у меня тоже вопросы - с ней (секцией) никогда не работал, поэтому не знаю, насколько это корректно будет...
Владислав (2005-02-07 12:32:00) [16]Тебе же уже отвечали, что выделять и освобождать память нужно в одном и том же месте, если использовать менеджер памяти 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;
Есть и другие варианты...
SVM (Perm) (2005-02-07 12:30:00) [17]Используй, например, CoTaskMemAlloc/CoTaskMemFree или SysAllocString/SysFreeString или GlobalAlloc/GlobalFree...
Ega23 (2005-02-07 12:26:00) [18]2 Игорь Шевченко © (07.02.05 12:16) [7]
Игорь, если я тебя правильно понял, то внутри библтотеки надо выделить память под Result, записать туда полученный пароль, после чего вернуть указатель на эту выделенную память.
Теперь вопрос: а где мне потом эту память высвобождать? На клиенте? Но так, вроде, нельзя делать, т.к. адресные пространства у DLL и клиента - разные...
Ega23 (2005-02-07 12:23:00) [19]2 Игорь Шевченко © (07.02.05 12:16) [7]
Да я вот тоже "нутром" чую, что всё неправильно делаю.
Хорошо, попытаюсь описать задачу:
Есть БД под MS SQL 2000. На базу существует 2 логина: первый входит в роль SA, второй имеет права на чтение одной единственной таблицы. В этой таблице лежит закодированный пароль для первого логина.
Действия клиента: коннект по второму логину (пароля на него нет), полуение пароля, ре-коннект под первым логином с полученным pwd.
Задача: написать DLL, которая по некоему алиасу соединяется с базой, получает пароль и возвращает его "наверх".
По-идее, это должна быть DLL с одной единственной функцией.
Вот как можно "изгольнуться" и получить этот чёртов пароль?
Игорь Шевченко (2005-02-07 12:16:00) [20]Нельзя возвращать указатель на локальную в функции строку. Она же уничтожается.