С этой функцией у меня возникли проблемы , GUI приложения отказываются нормально работать (испытывал на mplayer ) возникают сбои ( mplayer выводит видео через fbdev). В тоже время консольные программы работают нормально
Код "пускателя"
- Код: Выделить всё
program applaunch;
{$mode objfpc}{$H+}
uses
{$IFDEF Linux}
cthreads,
{$ENDIF}
Classes,sysutils, uapplaunch;
var
path:string;
data:portb_env;
id:integer;
begin
path:=GetCurrentDirEx+PathDelim+'settings.ini';
writeln('path='+path);
if fileexists(path) then
begin
data:=ReadAppData(Path);
data.curpath:=GetCurrentDirEx;
writeln('data.curpath+PathDelim+data.namebin='+data.curpath+PathDelim+data.namebin);
writeln('data.curpath+PathDelim+data.libdir='+data.curpath+PathDelim+data.libdir);
writeln('data.curpath+PathDelim+data.homedir='+data.curpath+PathDelim+data.homedir);
id:=RunApp(
data.curpath+PathDelim+data.namebin,
data.curpath+PathDelim+data.libdir,
data.curpath+PathDelim+data.homedir,
data.locale)
end
else
begin
writeln('Settings file not found')
end;
while CheckRunApp(id)=true do
begin
Sleep(100);
end;
CloseAppDesc(id);
writeln('applaunch terminated');
end.
- Код: Выделить всё
unit uapplaunch;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils,IniFiles,libc;
type
portb_env=record
homedir:string;
curpath:string;
libdir:string;
locale:string;
namebin:string;
end;
function CheckRunApp(id_process:integer): Boolean;
function CloseAppDesc(id_process:integer): Boolean;
function RunApp(PathToBin,PathToLib,HomeDir,LocaleStr:string):integer;
function ReadAppData(PathToDesctopFile: string):portb_env;
function OverWriteEnv(PathToLib,HomeDir,LocaleStr:string):PPchar;
function GetParams():PPChar;
function GetCurrentDirEx():string;
implementation
function CheckRunApp(id_process:integer): boolean;
begin
Result:=DirectoryExists('/proc/'+inttostr(id_process));
end;
function CloseAppDesc(id_process:integer): Boolean;
begin
Result:=True;
//0-running
//-1-not running
if waitpid(id_process, nil, WNOHANG) = -1 then
begin
Result := False;
end;
end;
function GetCurrentDirEx():string;
begin
Result:=ExtractFileDir(ParamStr(0));
end;
function RunApp(PathToBin, PathToLib, HomeDir, LocaleStr: string): integer;
var
ChildPid:integer;
begin
ChildPid:=libc.fork;
case ChildPid of
-1:
begin
writeln('error fork')
end;
0:
begin
execve(PChar(PathToBin),GetParams,OverWriteEnv(PathToLib,HomeDir,LocaleStr));
end;
end;
Result:=ChildPid;
end;
function ReadAppData(PathToDesctopFile: string):portb_env;
var
df:TIniFile;
begin
df:=TIniFile.Create(PathToDesctopFile);
Result.namebin:=df.ReadString('app','namebin','');
Result.libdir:=df.ReadString('app','libdir','');
Result.homedir:=df.ReadString('app','homedir','');
Result.locale:=df.ReadString('app','locale','');
Result.curpath:='';
df.Free;
end;
function OverWriteEnv(PathToLib, HomeDir, LocaleStr: string): PPchar;
var
i,ec:integer;
env_ar__: array of Pchar;
tmpstr:string;
begin
Result:=nil;
ec:=GetEnvironmentVariableCount;
SetLength(env_ar__,ec-1);
if ec=0 then begin exit end;
for i:=0 to ec-1 do
begin
tmpstr:=GetEnvironmentString(i);
if tmpstr='HOME' then begin tmpstr:=HomeDir end;
if tmpstr='LD_LIBRARY_PATH' then begin tmpstr:=PathToLib end;
if tmpstr='LANG' then begin tmpstr:=LocaleStr end;
env_ar__[i]:=Pchar(tmpstr);
end;
env_ar__[ec]:=nil;
GetMem(Result,ec*sizeOf(PChar));
Result:=@env_ar__[0];
end;
function GetParams(): PPChar;
var
ArgArray: array of PChar;
i: integer;
parc:integer;
begin
parc:=Paramcount;
writeln('Paramcount='+inttostr(Paramcount));
if parc > 0 then
begin
SetLength(argArray, parc + 2);
Getmem(Result,(parc+2)*SizeOf(Pchar));
argArray[0] := '';
for i := 1 to parc do
begin
argArray[i] :=Pchar(ParamStr(i));
end;
argArray[parc+1] := nil;
Result := @argArray[0];
end
else
begin
SetLength(argArray, 2);
argArray[0] := '';
argArray[1] := nil;
Getmem(Result,2*SizeOf(Pchar));
Result := @argArray[0];
end;
end;
end.
PS: Пишу аналог AppRun http://portablelinuxapps.org/
Добавлено спустя 14 часов 42 минуты 12 секунд:
Ошибка явно в функции OverWriteEnv. Неправильная работа с PPchar
Как правильно передать новые значения переменных окружения в execve?
Переделал так
- Код: Выделить всё
function OverWriteEnv(PathToLib, HomeDir, LocaleStr: string): PPchar;
var
i,ec:integer;
env_ar__: array of Pchar;
tmpstr:string;
OverWrite_LD_LIBRARY_PATH:Boolean;
begin
Result:=nil;
ec:=GetEnvironmentVariableCount;
SetLength(env_ar__,ec+1);
if ec=0 then begin exit end;
OverWrite_LD_LIBRARY_PATH:=False;
for i:=0 to ec-1 do
begin
tmpstr:=GetEnvironmentString(i);
if pos('HOME=',tmpstr)>0 then
begin
tmpstr:='HOME='+HomeDir;
end;
if pos('LD_LIBRARY_PATH=',tmpstr)>0 then
begin
OverWrite_LD_LIBRARY_PATH:=True;
tmpstr:='LD_LIBRARY_PATH='+PathToLib;
end;
if (pos('LANG=',tmpstr)>0) and (LocaleStr<>'') then
begin
tmpstr:='LANG='+LocaleStr;
end;
//writeln(tmpstr+' <> '+inttostr(i));
env_ar__[i]:=Pchar(tmpstr);
end;
if OverWrite_LD_LIBRARY_PATH=false then
begin
tmpstr:='LD_LIBRARY_PATH='+PathToLib;
env_ar__[ec]:=Pchar(tmpstr);
GetMem(Result,(ec+1)*sizeOf(PChar));
end else
begin
SetLength(env_ar__,ec);
//env_ar__[ec]:=#0; ???
GetMem(Result,ec*sizeOf(PChar));
end;
Result:=@env_ar__[0];
end;
Добавлено спустя 53 минуты 45 секунд:
Проблема была в том что нужно выделить память под каждый элемент
- Код: Выделить всё
function OverWriteEnv(PathToLib, HomeDir, LocaleStr: string): PPchar;
var
i,ec:integer;
env_ar__: array of Pchar;
tmpstr:string;
OverWrite_LD_LIBRARY_PATH:Boolean;
begin
Result:=nil;
ec:=GetEnvironmentVariableCount;
SetLength(env_ar__,ec+2);
if ec=0 then begin exit end;
OverWrite_LD_LIBRARY_PATH:=False;
for i:=0 to ec-1 do
begin
tmpstr:=GetEnvironmentString(i);
if pos('HOME=',tmpstr)>0 then
begin
tmpstr:='HOME='+HomeDir;
end;
if pos('LD_LIBRARY_PATH=',tmpstr)>0 then
begin
OverWrite_LD_LIBRARY_PATH:=True;
tmpstr:='LD_LIBRARY_PATH='+PathToLib;
end;
if (pos('LANG=',tmpstr)>0) and (LocaleStr<>'') then
begin
tmpstr:='LANG='+LocaleStr;
end;
getmem(env_ar__[i],length(tmpstr));
env_ar__[i]:=Pchar(tmpstr);
//writeln(string(env_ar__[i])+' <> '+inttostr(i));
end;
if OverWrite_LD_LIBRARY_PATH=false then
begin
tmpstr:='LD_LIBRARY_PATH='+PathToLib;
env_ar__[ec]:=Pchar(tmpstr);
env_ar__[ec+1]:=nil;
GetMem(Result,(ec+2)*sizeOf(PChar));
end else
begin
SetLength(env_ar__,ec+1);
env_ar__[ec]:=nil;
GetMem(Result,(ec+1)*sizeOf(PChar));
end;
Result:=@env_ar__[0];
end;
Но всё равно работает неправильно вот вывод env запущенного через applaunch
- Код: Выделить всё
ORBIT_SOCKETDIR=/tmp...
ORBIT_SOCKETDIR=/tmp...
USERNAME=...
USERNAME=...
USERNAME=...
XDG_SESSION_COOKIE=...
USERNAME=...
PWD=/home/...
GTK_MODULES=canberra-gtk-module
USERNAME=...
PWD=/home/...
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/...
USERNAME=...
PWD=/home/...
PWD=/home/...
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/...
DESKTOP_SESSION=gnome
PWD=/home/...
GNOME_KEYRING_PID=...
LANG=ru_RU.utf8
GNOME_KEYRING_PID=...
DISPLAY=:0.0
LD_LIBRARY_PATH=...
DISPLAY=:0.0
DISPLAY=:0.0
DISPLAY=:0.0
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
DISPLAY=:0.0
LD_LIBRARY_PATH=...
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/....
DISPLAY=:0.0
LD_LIBRARY_PATH=/home/...
COLORTERM=gnome-terminal
LD_LIBRARY_PATH=/home/...