ページ「Dropboxのインストール/ArchLinux」と「C♯のモジュールからC++のDLLを呼び出してみる」の間の差分

提供: とある社畜の頭脳整理
(ページ間の差分)
ナビゲーションに移動 検索に移動
 
 
1行目: 1行目:
Dropboxをインストールします。<br/>
+
久しぶりにやったら、すっかり忘れていたので覚書…
Debianのときに懲りたので、「nautilus-dropbox」を入れていこうと思ったのですが…<br/>
 
  
普通にDropboxの公式サイトに載っている方法で動きました(^_^;)<br/>
+
== C++のDLLプロジェクト作成 ==
 +
まず、C++のDLLを作成するときの注意点…
 +
作成するプロジェクトは、「Win32プロジェクト」を選択するんだ。<br/>
 +
[[ファイル:CShapeToCppDll-005.jpg]]
  
ここに公式サイトの内容を載せても面白くないので、CUIインストール&バックグラウンド起動までやってみようかと思います。<br/>
 
(Debianで挫折したやつですね…)
 
  
= ダウンロード =
+
あと…アプリケーションの設定では「DLL」と「空のプロジェクト」を選択してね。<br/>
まずは、ドロップボックスを利用したいユーザーでsshログインします。<br/>
+
[[ファイル:CShapeToCppDll-001.jpg]]<br/>
もちろんsuしてもOKです。<br/>
 
  
  
そこから、公式サイトの通り以下のコマンドを実行します。
+
空のプロジェクトが作成されたら「cpp」「h」「def」ファイルを追加するんだ。今回は「CppDll.cpp」「CppDll.h」「CppDll.def」を追加したよ。
<syntaxhighlight lang="bash">cd ~ && wget -O - "https://www.dropbox.com/download?plat=lnx.x86_64" | tar xzf -</syntaxhighlight>
 
するとホームディレクトリに「.dropbox-dist」ディレクトリが作成されます。<br/>
 
  
  
次に操作しやすくするためにパイソンのツールを以下のコマンドでダウンロードします。<br/>
+
そしたら、プロジェクトのプロパティを開いて「構成プロパティ→リンカー→入力→モジュール定義ファイル」に「CppDll.def」を設定するんだ。<br/>
(実行権が付いていないので、実行権も付与します。)
+
(DebugとReleaseでそれぞれ設定する必要があるんだよ。)<br/>
<syntaxhighlight lang="bash">wget "https://linux.dropbox.com/packages/dropbox.py"
+
[[ファイル:CShapeToCppDll-002.jpg]]<br/>
chmod +x ~/dropbox.py</syntaxhighlight>
 
  
= 起動 =
+
== DLLのコード ==
== ひとまず手順通りに ==
+
=== ヘッダーファイル(*.h) ===
最初の起動でデーモンの登録やアカウントとのリンクをするので、公式サイトの手順通りに以下のコマンドを実行します。
+
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="bash">~/.dropbox-dist/dropboxd</syntaxhighlight>
+
#ifndef DLLAPI
 +
#define DLLAPI extern "C" __declspec(dllimport)
 +
#endif
  
すると…以下のメッセージが出続けます。
+
DLLAPI long __stdcall _Sum(const long p_Number1, const long p_Number2);
<syntaxhighlight lang="text"> Dropbox ...
+
</syntaxhighlight>
https://www.dropbox.com/cli_link_nonce?nonce=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</syntaxhighlight>
 
  
パソコンからでもよいので、表示されているURLにアクセスして、ドロップボックスのユーザーIDとパスワードを入力します。<br/>
+
=== コードファイル(*.cpp) ===
予めログインしている場合はリンクの確認画面が出るので「リンクする」をクリックします。
+
<syntaxhighlight lang="cpp">
 +
#define DLLAPI
  
 +
#include "CppDll.h"
  
これで、デーモンの登録とアカウントのリンクの完了です。<br/>
+
DLLAPI long __stdcall _Sum(const long p_Number1, const long p_Number2)
(sshの画面はメッセージは止まりますが…プロンプトに戻りません…「Ctrl+C」で抜けます)
+
{
 +
return p_Number1 + p_Number2;
 +
}
 +
</syntaxhighlight>
  
== 手動で起動 ==
+
=== モジュール定義ファイル(*.def) ===
手動で起動する場合はツールを利用して以下のコマンドで実行します。
+
<syntaxhighlight lang="text">
<syntaxhighlight lang="bash">~/dropbox.py start</syntaxhighlight>
+
LIBRARY CppDll
  
停止は以下のコマンド
+
EXPORTS
<syntaxhighlight lang="bash">~/dropbox.py stop</syntaxhighlight>
+
_Sum
 +
</syntaxhighlight>
  
状態の確認は以下です。
+
== C♯のプロジェクト作成 ==
<syntaxhighlight lang="bash">~/dropbox.py status</syntaxhighlight>
+
ほとんどそのまま作るんだけど…ソリューションのコンパイル対策をしておくよ。
  
その他のコマンドは以下を参照してください。<br/>
+
=== ビルドイベントの設定 ===
[https://help.dropbox.com/ja-jp/installs-integrations/desktop/linux-commands Linux で Dropbox を利用する:ソース、コマンド、リポジトリからのインストール - Dropbox ヘルプ – Dropbox ヘルプ]
+
C++のDLLはソリューションフォルダ直下の「Debug」や「Release」フォルダにDLLが格納されてしまうんだ。そうすると、デバッグするときにDLLが見つからないので、ビルドイベントを使ってコピーしてしまうよ。以下のように設定してね。(「Release」コンパイルするまでは「Release」フォルダがないのでコメントアウトしているよ)<br/>
 +
[[ファイル:CShapeToCppDll-004.jpg]]<br/>
  
== 特定ユーザーでバックグラウンドで自動起動 ==
+
=== プロジェクトの依存関係の設定 ===
ここまで来れば、バックグラウンドで…しかもユーザー指定で動かしたくなります。<br/>
+
コピーするにもちゃんとリコンパイルされた資源をコピーしないといけないので、プロジェクトの依存関係を設定することで、ビルドの順番を設定するよ。<Br/>
(Debianの時は、GNOMEの自動ログインを使用していました…)<br/>
+
ソリューションエクスプローラーからC♯のプロジェクトを右クリックして「ビルド依存関係」→「プロジェクト依存関係」を選択してね。<br/>
 +
「依存関係」タブの依存先にC++のプロジェクトが表示されているはずだから、チェックを入れてOKボタンをクリックしてね。
  
 +
== C♯のコード ==
 +
MVVMモデルでサンプルを作ったからビューモデルが入っているけど…DLLを呼ぶには必要ないから無視してね。
 +
=== モデル ===
 +
<syntaxhighlight lang="C#">
 +
using System;
 +
using System.Collections.Generic;
 +
using System.Linq;
 +
using System.Text;
 +
using System.Threading.Tasks;
 +
using System.Windows;
 +
using System.Windows.Controls;
 +
using System.Windows.Data;
 +
using System.Windows.Documents;
 +
using System.Windows.Input;
 +
using System.Windows.Media;
 +
using System.Windows.Media.Imaging;
 +
using System.Windows.Navigation;
 +
using System.Windows.Shapes;
  
早速サービスファイルを作成します。<br/>
+
//追加
以下のコマンドでサービスファイルを作成します。
+
using System.Runtime.InteropServices;
<syntaxhighlight lang="bash">nano /etc/systemd/system/dropbox@.service</syntaxhighlight>
 
  
ファイルの内容は以下の通りです。
+
namespace CSharpToCDLL
<syntaxhighlight lang="bash">[Unit]
+
{
Description=Dropbox Service
+
    /// <summary>
After=network-online.target
+
    /// MainWindow.xaml の相互作用ロジック
Wants=network-online.target
+
    /// </summary>
 +
    public partial class MainWindow : Window
 +
    {
 +
        /// <summary>
 +
        /// DLLの関数定義
 +
        /// </summary>
 +
        /// <param name="p_Number1">数値1</param>
 +
        /// <param name="p_Number2">数値2</param>
 +
        /// <returns>合計</returns>
 +
        [DllImport("CppDll.dll")]
 +
        private extern static Int32 _Sum(Int32 p_Number1,Int32 p_Number2);
  
[Service]
+
        /// <summary>
ExecStart=/home/%i/dropbox.py start
+
        /// 標準のコンストラクタ
ExecReload=/home/%i/dropbox.py stop && /home/%i/dropbox.py start
+
        /// </summary>
ExecStop=/home/%i/dropbox.py stop
+
        public MainWindow()
Type=oneshot
+
        {
RemainAfterExit=yes
+
            InitializeComponent();
User=%i
+
        }
  
[Install]
+
        /// <summary>
WantedBy=multi-user.target</syntaxhighlight>
+
        /// ボタンクリックイベントハンドラ
 +
        /// </summary>
 +
        /// <param name="sender">イベント送信元</param>
 +
        /// <param name="e">イベント情報</param>
 +
        private void Button_Click(object sender, RoutedEventArgs e)
 +
        {
 +
            //DLLの関数を呼び出す
 +
            Int32 l_Result = _Sum(300, 500);
  
ポイントはネットワーク起動後に起動しているくらいでしょうか…<br/>
+
            //計算結果の表示
「%i」はサービス起動時に「@」の後ろに記入した文字列に置き換えられます。<br/>
+
            MessageBox.Show("計算結果:" + l_Result.ToString());
 +
        }
 +
    }
 +
}
 +
</syntaxhighlight>
  
サービスファイルを作成したら、さっそく以下のコマンドで起動してみます。
+
=== ビュー ===
<syntaxhighlight lang="bash">systemctl start dropbox@[userid]</syntaxhighlight>
+
<source lang="xml">
[userid]はドロップボックスで使用する(先ほどリンクした)ArchLinuxのユーザーIDに置き換えてください。
+
<Window x:Class="CSharpToCDLL.MainWindow"
 +
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 +
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 +
        Title="MainWindow"
 +
        Height="77.056"
 +
        Width="525">
 +
    <Grid>
 +
        <Grid.RowDefinitions>
 +
            <RowDefinition Height="5"/>
 +
            <RowDefinition Height="24"/>
 +
            <RowDefinition/>
 +
            <RowDefinition Height="5"/>
 +
        </Grid.RowDefinitions>
 +
        <Grid.ColumnDefinitions>
 +
            <ColumnDefinition Width="5"/>
 +
            <ColumnDefinition/>
 +
            <ColumnDefinition Width="5"/>
 +
            <ColumnDefinition Width="75"/>
 +
            <ColumnDefinition Width="5"/>
 +
        </Grid.ColumnDefinitions>
 +
        <Label
 +
            Grid.Row="1"
 +
            Grid.Column="1"
 +
            Content="{Binding Label_Content}"/>
 +
        <Button
 +
            Grid.Row="1"
 +
            Grid.Column="3"
 +
            Content="実行"
 +
            Click="Button_Click"/>
 +
    </Grid>
 +
</Window>
 +
</source>
 +
=== ビューモデル ===
 +
<source lang="csharp">
 +
using System;
 +
using System.Collections.Generic;
 +
using System.Linq;
 +
using System.Text;
 +
using System.Threading.Tasks;
  
以下コマンドを実行して「Active: active (exited)」と出ていればOKです。
+
//追加
<syntaxhighlight lang="bash">systemctl status dropbox@[userid]</syntaxhighlight>
+
using System.ComponentModel;
  
止めるときは
+
namespace CSharpToCDLL
<syntaxhighlight lang="bash">systemctl stop dropbox@[userid]</syntaxhighlight>
+
{
です。
+
    class MainWindowViewModel : INotifyPropertyChanged
 +
    {
 +
        /// <summary>
 +
        /// ラベル表示用変数
 +
        /// </summary>
 +
        private String m_Label_Content;
  
再起動後も有効にしたいので、以下のコマンドを実行します。
+
        /// <summary>
<syntaxhighlight lang="bash">systemctl enable dropbox@[userid]</syntaxhighlight>
+
        /// ラベル表示文字列
 +
        /// </summary>
 +
        public String Label_Content
 +
        {
 +
            set
 +
            {
 +
                this.m_Label_Content = value;
 +
                this.OnPropertyChanged("Label_Content");
 +
            }
 +
            get { return this.m_Label_Content; }
 +
        }
  
再起動しても「Active: active (exited)」と出ていればOKです。<br/>
+
        /// <summary>
 +
        /// プロパティ変更イベントハンドラ
 +
        /// </summary>
 +
        public event PropertyChangedEventHandler PropertyChanged;
  
= 蛇足 =
+
        /// <summary>
== 外付けHDDに同期させる ==
+
        /// プロパティ変更通知
「/mnt」にマウントしたHDDに「Dropbox」ディレクトリを作成して、シンボリックリンクを張りたいと思います。<br/>
+
        /// </summary>
(以下Dropbox用のユーザーで作業します)
+
        /// <param name="p_PropertyName">プロパティ名</param>
 +
        public void OnPropertyChanged(String p_PropertyName)
 +
        {
 +
            if (this.PropertyChanged != null)
 +
            {
 +
                this.PropertyChanged(this, new PropertyChangedEventArgs(p_PropertyName));
 +
            }
 +
        }
 +
    }
 +
}
 +
</source>
  
 
+
[[Category:C♯]]
まずは以下のコマンドでディレクトリを作成します。
+
[[Category:C++]]
<syntaxhighlight lang="bash">mkdir /mnt/Dropbox</syntaxhighlight>
+
[[Category:dll]]
 
 
念のためにサービスを停止させます。
 
<syntaxhighlight lang="bash">systemctl stop dropbox@[userid]</syntaxhighlight>
 
 
 
次に、自動で作成されたホームディレクトリの「Dropbox」ディレクトリの名前を以下のコマンドで変更します。
 
<syntaxhighlight lang="bash">mv ~/Dropbox ~/Dtopbox_old</syntaxhighlight>
 
 
 
シンボリックリンクを張ります。
 
<syntaxhighlight lang="bash">ln -s /mnt/Dropbox ~/Dropbox</syntaxhighlight>
 
 
 
最後にサービスを起動します。
 
<syntaxhighlight lang="bash">systemctl start dropbox@[userid]</syntaxhighlight>
 
 
 
= 参考サイト =
 
[https://www.dropbox.com/install?os=lnx インストール - Dropbox]<br/>
 
[https://help.dropbox.com/ja-jp/installs-integrations/desktop/linux-commands Linux で Dropbox を利用する:ソース、コマンド、リポジトリからのインストール - Dropbox ヘルプ – Dropbox ヘルプ]<br/>
 
[https://wiki.archlinux.jp/index.php/Netctl#network-online.target_.E3.81.AE.E6.9C.89.E5.8A.B9.E5.8C.96 network-online.target の有効化]<br/>
 
 
 
[[Category:ArchLinux]]
 
[[Category:Dropbox]]
 

2019年7月26日 (金) 07:46時点における版

久しぶりにやったら、すっかり忘れていたので覚書…

C++のDLLプロジェクト作成

まず、C++のDLLを作成するときの注意点… 作成するプロジェクトは、「Win32プロジェクト」を選択するんだ。
CShapeToCppDll-005.jpg


あと…アプリケーションの設定では「DLL」と「空のプロジェクト」を選択してね。
CShapeToCppDll-001.jpg


空のプロジェクトが作成されたら「cpp」「h」「def」ファイルを追加するんだ。今回は「CppDll.cpp」「CppDll.h」「CppDll.def」を追加したよ。


そしたら、プロジェクトのプロパティを開いて「構成プロパティ→リンカー→入力→モジュール定義ファイル」に「CppDll.def」を設定するんだ。
(DebugとReleaseでそれぞれ設定する必要があるんだよ。)
CShapeToCppDll-002.jpg

DLLのコード

ヘッダーファイル(*.h)

#ifndef DLLAPI
#define DLLAPI extern "C" __declspec(dllimport)
#endif

DLLAPI long __stdcall _Sum(const long p_Number1, const long p_Number2);

コードファイル(*.cpp)

#define DLLAPI

#include "CppDll.h"

DLLAPI long __stdcall _Sum(const long p_Number1, const long p_Number2)
{
	return p_Number1 + p_Number2;
}

モジュール定義ファイル(*.def)

LIBRARY	CppDll

EXPORTS
	_Sum

C♯のプロジェクト作成

ほとんどそのまま作るんだけど…ソリューションのコンパイル対策をしておくよ。

ビルドイベントの設定

C++のDLLはソリューションフォルダ直下の「Debug」や「Release」フォルダにDLLが格納されてしまうんだ。そうすると、デバッグするときにDLLが見つからないので、ビルドイベントを使ってコピーしてしまうよ。以下のように設定してね。(「Release」コンパイルするまでは「Release」フォルダがないのでコメントアウトしているよ)
CShapeToCppDll-004.jpg

プロジェクトの依存関係の設定

コピーするにもちゃんとリコンパイルされた資源をコピーしないといけないので、プロジェクトの依存関係を設定することで、ビルドの順番を設定するよ。
ソリューションエクスプローラーからC♯のプロジェクトを右クリックして「ビルド依存関係」→「プロジェクト依存関係」を選択してね。
「依存関係」タブの依存先にC++のプロジェクトが表示されているはずだから、チェックを入れてOKボタンをクリックしてね。

C♯のコード

MVVMモデルでサンプルを作ったからビューモデルが入っているけど…DLLを呼ぶには必要ないから無視してね。

モデル

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

//追加
using System.Runtime.InteropServices;

namespace CSharpToCDLL
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        /// <summary>
        /// DLLの関数定義
        /// </summary>
        /// <param name="p_Number1">数値1</param>
        /// <param name="p_Number2">数値2</param>
        /// <returns>合計</returns>
        [DllImport("CppDll.dll")]
        private extern static Int32 _Sum(Int32 p_Number1,Int32 p_Number2);

        /// <summary>
        /// 標準のコンストラクタ
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// ボタンクリックイベントハンドラ
        /// </summary>
        /// <param name="sender">イベント送信元</param>
        /// <param name="e">イベント情報</param>
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            //DLLの関数を呼び出す
            Int32 l_Result = _Sum(300, 500);

            //計算結果の表示
            MessageBox.Show("計算結果:" + l_Result.ToString());
        }
    }
}

ビュー

<Window x:Class="CSharpToCDLL.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Height="77.056"
        Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="5"/>
            <RowDefinition Height="24"/>
            <RowDefinition/>
            <RowDefinition Height="5"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="5"/>
            <ColumnDefinition/>
            <ColumnDefinition Width="5"/>
            <ColumnDefinition Width="75"/>
            <ColumnDefinition Width="5"/>
        </Grid.ColumnDefinitions>
        <Label
            Grid.Row="1"
            Grid.Column="1"
            Content="{Binding Label_Content}"/>
        <Button
            Grid.Row="1"
            Grid.Column="3"
            Content="実行"
            Click="Button_Click"/>
    </Grid>
</Window>

ビューモデル

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

//追加
using System.ComponentModel;

namespace CSharpToCDLL
{
    class MainWindowViewModel : INotifyPropertyChanged
    {
        /// <summary>
        /// ラベル表示用変数
        /// </summary>
        private String m_Label_Content;

        /// <summary>
        /// ラベル表示文字列
        /// </summary>
        public String Label_Content
        {
            set
            {
                this.m_Label_Content = value;
                this.OnPropertyChanged("Label_Content");
            }
            get { return this.m_Label_Content; }
        }

        /// <summary>
        /// プロパティ変更イベントハンドラ
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// プロパティ変更通知
        /// </summary>
        /// <param name="p_PropertyName">プロパティ名</param>
        public void OnPropertyChanged(String p_PropertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(p_PropertyName));
            }
        }
    }
}