2024年6月18日火曜日

コマンドの横取り

 ARESのログファイルは実行したコマンド名しか記録しません。コマンド履歴ウィンドウの内容を取得する方法があれば便利です。

カスタムコマンドを CFx (C++)で作成してみました。

準備

  1. 信頼できるフォルダに TeeCommand_24.7_17.tx を置いてください。
  2. アドインとしてアプリケーションを追加します。

使い方

  1. TEEコマンドを実行します。
  2. 実行するファイル名を指定します。
  3. 出力先のファイル名を指定します。そのままでよければEnterを押します。
  4. コマンドが実行され、正常終了、キャンセルに関わらず、コマンドの出力内容がファイルに出力されます。

プログラムの説明

teecommand.h

class TeeCommand : public CFxCommand, CFxOutputDevice
{
public:
	virtual const OdString groupName() const { return "TEE_GROUP_NAME"; }
	virtual const OdString globalName() const { return "_TEE"; }
	virtual const OdString localName() const { return "TEE"; }
	virtual int Execute(CFxCommandContext* pCmdCtx);

	virtual void CommandOutput(const CFxString& message, const CFxDocument* document);
	virtual void SystemOutput(const CFxString& message, const CFxDocument* document);

protected:
	TeeCommand(void) {}
	~TeeCommand(void) {}
private:
	//QString getCoordinates(const OdGePoint3dArray& inp);
	QStringList m_output;
	int m_prec;
};

teecommand.cpp

void TeeCommand::CommandOutput(const CFxString& message, const CFxDocument* document)
{
    m_output.append(message);
}

void TeeCommand::SystemOutput(const CFxString& message, const CFxDocument* document)
{
    //m_output.append(message);
}

int TeeCommand::Execute(CFxCommandContext* pCmdCtx)
{
    CFxHostAppServicesPtr svc = GetFxSystemServices()->GetHostAppServices();
    CFxDocumentPtr doc = pCmdCtx->GetFxDocument();
    CFxDatabasePtr db = doc->GetFxDatabase();
    CFxUserIO* io = doc->GetFxUserIO();
    m_output.clear();
    // Specify command.
    CFxString command;
    CFxString prompt = io->GetPrompt(L"Command name");
    int rc = io->GetString(false, prompt, L"", &command);
    if (rc != RTNORM)
        return RTNORM;
    // Specify filename.
    QFileInfo fi;
    if (db->getDWGTITLED())
    {
        fi.setFile(QString::fromUtf16(db->getFilename().c_str()));
    }
    else
    {
        fi.setFile(
            QString::fromUtf16(svc->getMYDOCUMENTSPREFIX().c_str()),
            QString::fromUtf16(db->getDWGNAME().c_str())
        );
    }   
    CFxString inputname = QString("%1/%2.txt").arg(fi.absolutePath()).arg(fi.completeBaseName());
    CFxString filename;
    prompt = io->GetPromptString(L"File name", &inputname);
    rc = io->GetString(true, prompt, inputname, &filename);
    if (rc != RTNORM)
        return RTNORM;
    // Run command
    GetFxSystemServices()->AddOutputDevice(this);
    OdResBufPtr cmd = OdResBuf::newRb(OdResBuf::kRtString, command.wide_strU());
    GetFxSystemServices()->SendStringToExecute(nullptr, cmd);
    GetFxSystemServices()->RemoveOutputDevice(this);
    // Write file
    QFile fOut(filename);
    if (fOut.open(QFile::WriteOnly | QFile::Text)) 
    {
        QTextStream s(&fOut);
        s.setCodec("shift-jis");
        for (int i = 0; i < m_output.size(); ++i)
        {
            s << m_output.at(i);
        }
        s.flush();
        fOut.close();
    }
    else 
    {
        io->Write(L"File open error.\n");
    }
    return RTNORM;
}
  • 最初の GetString( )でコマンド名を入力します。最初の引数が false なのでスペースで入力が終了します。
  • Qt のQFileInfo クラスはディレクトリ、ファイル、拡張子を処理するのに便利なクラスです。
  • 保存済みの図面の場合は CFxDatabase::getFilename() にDWGファイルの完全パスがあるのでそれを使い、未保存の図面の場合はシステム変数 MYDOCUMENTPREFIX と DWGNAME からファイル名を生成します。
  • 最初の GetString( )でファイル名を入力します。最初の引数が true なのでEnterで入力が終了し、ファイル名にスペースを含めることが可能です。
  • AddOutputDevice() でコマンド出力内容の横取りが開始します。
  • SendStringToExecute() でコマンドをただちに実行して、終了まで待ちます。リザルトバッファにコマンドの追加の引数が指定できますが、足りない場合はユーザー入力待ちになります。
  • RemoveOutputDevice() でコマンド出力内容の横取りを終了します。
  • Qtの QFile クラス、QTextStream クラスによってテキストファイルを出力しています。setCodec() によって出力する文字コードをシフトJIS (日本語)に切り替えています。setCodec() がないとユニコード(UTF-8)での出力になります。
  • コマンド出力内容を横取りするためには、CFxOutputDevice クラスを継承する必要があります。TEE コマンドは、CFxCommand と CFxOutputDevice クラスを継承しているのでコマンド出力内容を横取りできるコマンドになります。
  • CFxOutputDevice クラスを継承すると、commandOutput() と systemOutput() を実装する必要があります。今回システムからの出力は不要なので、commandOutput() が呼び出されたら、m_output に文字列をためるようにします。

ARESのコマンド履歴ウィンドウやコマンドプロンプトウィンドウはQtのウィジェットになっているので text() で内容を取ってくることは可能なのですが、コマンド出力内容が更新されるのは ARES のタイミング次第なので、text() ではうまくいきません。CFx APIに提供されている CFxOutputDevice クラスを利用することで確実にコマンド出力内容を横取りすることができます。

0 件のコメント:

コメントを投稿

ARESのトリニティ(三位一体)

 ARESのトリニティ戦略、どこがトリニティなんでしょう。 まずはデスクトップCADが、WindowsにもMacにもLinux版もあるというトリニティ。 デスクトップCADと、モバイルCAD(ARES Touch)と、ブラウザとサーバーCAD(ARES Kudo)のトリニティ。 ...