问题描述
如何从在Delphi 10.2 Tokyo中创建的Linux控制台应用程序中执行外部程序?
How can I execute an external program from a Linux console application created in Delphi 10.2 Tokyo?
我想做的是使用
/home/test/qrencode -o /tmp/abc.png '08154711'
我不需要程序的输出,但是应该同步执行.
I do not need the output of the program but it should be executed synchronously.
在Windows环境中很容易,但是由于Delphi(在Kylix之后)对64位Linux的支持还很新,所以我现在在网上找不到任何提示.
It is easy in Windows environments but as 64 bit Linux support in Delphi (after Kylix) is quite new, I could not find any hints on the Web by now.
任何帮助我解决问题的技巧都非常感谢.
Any tip helping me to solve that is very appreciated.
提前谢谢!
推荐答案
Davids的提示为我提供了一个有助于创建解决方案的示例.最棘手的部分是找到如何将Delphi字符串转换为MarshaledAString的示例,该示例使用const字符串作为popen的参数.我在RHEL 7.3上进行了测试,运行起来很吸引人.
Davids hint pointed me to an example that helped creating the solution. The most tricky part was finding out how to convert a Delphi string to a MarshaledAString as the example used a const string as argument for popen. I tested on RHEL 7.3, runs like a charm.
uses
...
System.SysUtils,
Posix.Base,
Posix.Fcntl,
...;
type
TStreamHandle = pointer;
function popen(const command: MarshaledAString; const _type: MarshaledAString): TStreamHandle; cdecl;
external libc name _PU + 'popen';
function pclose(filehandle: TStreamHandle): int32; cdecl; external libc name _PU + 'pclose';
function fgets(buffer: pointer; size: int32; Stream: TStreamHandle): pointer; cdecl; external libc name _PU + 'fgets';
function runCommand(const acommand: MarshaledAString): String;
// run a linux shell command and return output
// Adapted from http://chapmanworld.com/2017/04/06/calling-linux-commands-from-delphi/
var
handle: TStreamHandle;
data: array [0 .. 511] of uint8;
function bufferToString(buffer: pointer; maxSize: uint32): string;
var
cursor: ^uint8;
endOfBuffer: nativeuint;
begin
if not assigned(buffer) then
exit;
cursor := buffer;
endOfBuffer := nativeuint(cursor) + maxSize;
while (nativeuint(cursor) < endOfBuffer) and (cursor^ <> 0) do
begin
result := result + chr(cursor^);
cursor := pointer(succ(nativeuint(cursor)));
end;
end;
begin
result := '';
handle := popen(acommand, 'r');
try
while fgets(@data[0], sizeof(data), handle) <> nil do
begin
result := result + bufferToString(@data[0], sizeof(data));
end;
finally
pclose(handle);
end;
end;
function createQRCode(id, fn: string): string;
// Create qr-code using qrencode package
begin
deletefile(fn);
if fileExists(fn) then
raise Exception.create('Old file not deleted!');
// I am targeting rhel for now, so I know the path for sure
result := runCommand(MarshaledAString(UTF8STring('/usr/bin/qrencode -o ' + fn + ' ''' + id + '''')));
if not fileExists(fn) then
raise Exception.create('New file not created!');
end;
function testqr: String;
// Test QR Code creation with error handling
// QREncode does not output anything but who knows ;-)
begin
try
result := createQRCode('08154711', '/tmp/myqrcode.png');
except
on e: Exception do
begin
result := 'Error: ' + e.message;
end;
end;
end;
这篇关于从Linux/Delphi 10.2控制台应用程序执行外部程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!