サーバレス練習帳

着眼大局着手小局

【Delphi FMX】シェル実行

unit Unit1;

interface

uses
Winapi.Windows,
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.Controls.Presentation, FMX.StdCtrls,ShellAPI,FMX.Platform.Win;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { private 宣言 }
  public
    { public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
var
  LFile   : string;
  LParams : string;
  WindowHandle: HWND;
begin
  LFile   := 'cmd.exe';
  LParams := '';
  WindowHandle := WindowHandleToPlatform(Self.Handle).Wnd;
  ShellExecute(WindowHandle, 'open', PChar(LFile), PChar(LParams), nil, SW_SHOWNORMAL);
end;
end.

【参考】

◆シェル実行
http://mrxray.on.coocan.jp/Delphi/plSamples/490_CmdPrompt1.htm

FMXからウインドウハンドラの取得
https://ht-deko.com/techf014.html

【Python】py2exe, pyinstaller, embeddable python

◆2つを試してみます!
やってみます!
なんだか、python3.6では動かず、python3.4が必要だ、という噂がある。

cocodrips.hateblo.jp

こういうエラーが出たので、プログラムに対処が必要か?

RuntimeError: maximum recursion depth exceeded

e25ac05a9065c0bd9c03

こういう対処。

import sys
sys.setrecursionlimit(10000)

こういうエラーもでたので、インストール必要か?

Error: Namespace packages not yet supported: Skipping package 'win32com.gen_py'

yukun.info


ダメだ!分からない!
結局、速度が遅いと評判だけど、pyinstallerを使うことにした!

kconcon3.hatenablog.com

確かに、1ファイルにまとめると読み込みが遅い!
そして、まとめないと大量にファイルが吐き出されます!

◆pyinstallerを使うときの注意

% pyinstaller --onefile --windowed --icon=icon01.ico your_python_file.py 
    • onefileは関連ファイルを全て1つのファイルにまとめてくれ、--windowedは実行時にターミナルが立ち上がらないようにするオプションです。

とのことで、配布時にはこれが意外と重要です。--windowedね。
qiita.com

アイコンを使うには、さらにもう一工夫が必要な模様!
qiita.com



◆comtypes.genで詰まることがあるらしいのでメモ
qiita.com



そして、embeddable pythonという大技が期待できるかもしれない!(未検証)
qiita.com

【Delphi FMX】Drag&Dropでファイルを受け取る

(1) まずはDrag&Dropの設定
f:id:urbanplanner:20180820125432p:plain

これでパス 及び ファイル名を取得できる。
ListBox1に落とさせる場合、「AlloDrag」をTrueにしておくことが必要です。

procedure TForm1.ListBox1DragDrop(Sender: TObject;
  const [Ref] Data: TDragObject; const [Ref] Point: TPointF);
begin
  Label1.Text:=Data.Files[0];
end;


(2) ファイルの読み取り
最近はReadlnは流行っていないらしい。
serverless.hateblo.jp

が、コチラのリンクの3つの方式を比較すると、「ロックされたファイルの読込」可能なAssignFileで良いんじゃないか?と思う。
qiita.com

どうせ、1行目の取得と、ファイルのコピーしかしないしね。

古いページですが、AssignFileの読み取りは、こんこページが役に立つ。
http://www.geocities.co.jp/SiliconValley-SanJose/2560/delphi4/pascal/File.htm

・・・ダメだ!
AssignFileはUTF8を読めないっぽい!
(上記のリンクの下の方の比較表より)

では、TStreamReaderだな。
上記リンクより引用したTStreamReaderの使い方です。

  try
    sr := TStreamReader.Create(filename);
    str := sr.ReadToEnd();       //全文string読込(ここでも文字コードの例外が飛ぶ可能性あり)
    while not sr.EndOfStream do  //(ここでも文字コードの例外が飛ぶ可能性あり)
    begin
      line := sr.ReadLine;     //一行読込
    end;
  except
    on e: Exception do
    begin
      ShowMessage('ERROR:' + e.Message);
      exit;
    end;
  end;
  sr.Free();
  sl := TStringList.Create();
  sl.Text := str;            //全文TStringList読込はないのでstringを代入


ちなみに、1行目(ヘッダー行)だけ読み取りたいのなら、以下の様な感じです。

procedure TForm1.ListBox1DragDrop(Sender: TObject;
  const [Ref] Data: TDragObject; const [Ref] Point: TPointF);
var
  SR:TStreamReader;
  strHeaderAll:string;
  intColumnCount:integer;
  rcTableColumn:TTableColumnRec;
  SL:TStringList;
begin
  Label1.Text:=Data.Files[0];
  lsTableColumn:=TList<TTableColumnRec>.Create;
  //ヘッダー(1行目)の読み込み
  try
    intColumnCount:=0;
    SR := TStreamReader.Create(Data.Files[0]);
    SL := TStringList.Create();
    strHeaderAll := SR.ReadLine;
    while Pos(',',strHeaderAll) <> 0 do
    begin
      rcTableColumn.id:=intColumnCount;
      rcTableColumn.strColumnName:=Copy(strHeaderAll,1,Pos(',',strHeaderAll)-1);
      rcTableColumn.strColumnType:='';
      rcTableColumn.strElementId:='';
      lsTableColumn.Add(rcTableColumn);
      SL.Add(rcTableColumn.strColumnName);
      //FMX.Dialogs.ShowMessage(rcTableColumn.strColumnName);
      Delete(strHeaderAll,1,Pos(',',strHeaderAll));
      intColumnCount:=intColumnCount+1;
    end;
    SL.SaveToFile('./Columns.csv', TEncoding.UTF8);
  except
    on e: Exception do
    begin
      ShowMessage('ERROR:' + e.Message);
      exit;
    end;
  end;
  SL.Free();
  SR.Free();
  //ヘッダー(1行目)の書き込み
end;


(3) ファイルコピー
これは、このまま使えそう。
「System.IOUtils」を使う模様。
www.gesource.jp

【Delphi】ShowModalの後の処理

Main(Form1)からUnit2(Form2)をusesしています。

procedure TMainForm.Button1Click(Sender: TObject);
begin
  Form2.Left := Self.Left - 50;
  Form2.Top  := Self.Top  + 80;
  Form2.ShowModal;
  FMX.Dialogs.ShowMessage('ShowModalの後の処理!');
end;

この場合、Form2が閉じられるまでShoMessageは出てきません。
さらにいうと、Form2はForm1と一緒に起動時に生成されて、
例えForm2の「×」が押されたとしても、Form1がDestroyされるまで生き続けます。

つまり、Form2で取得したデータは、Form2に格納しておけるわけです。

Form2は、Form2内のボタンか何かから「Close;」だけで閉じる(=非表示にする)ことができます。
Closeにした時点では、まだForm2は生きています。