从Linux/Delphi 10.2控制台应用程序执行外部程序 [英] Execute external program from Linux/Delphi 10.2 console application

查看:69
本文介绍了从Linux/Delphi 10.2控制台应用程序执行外部程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何从在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控制台应用程序执行外部程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆