ページ「ReadyMedia(旧名 MiniDLNA) のインストール」と「C♯のモジュールからC++のDLLを呼び出してみる」の間の差分

提供: とある社畜の頭脳整理
(ページ間の差分)
ナビゲーションに移動 検索に移動
 
 
1行目: 1行目:
<amp/>
+
久しぶりにやったら、すっかり忘れていたので覚書…
= インストール =
 
とても簡単で、以下のコマンドを実行して、ReadyMediaをインストールするだけです。
 
<pre>sudo apt-get install minidlna</pre>
 
  
= 準備 =
+
== C++のDLLプロジェクト作成 ==
DLNAで共有?するためのディレクトリを適当に作成します。<br/>
+
まず、C++のDLLを作成するときの注意点…
今回は、「/share」ディレクトリを作成し、その配下に「movies」「photos」「musics」のディレクトリを作成し、それを共有するようにしてみます。<br/>
+
作成するプロジェクトは、「Win32プロジェクト」を選択するんだ。<br/>
以下のコマンドを実行して、それぞれのディレクトリを作成します。
+
[[ファイル:CShapeToCppDll-005.jpg]]
<syntaxhighlight lang="bash">sudo mkdir /share
 
sudo mkdir /share/movies
 
sudo mkdir /share/photos
 
sudo mkdir /share/musics</syntaxhighlight>
 
※ディレクトリパスは環境に合わせて変更してください。
 
  
また、ReadyMediaがアクセスできるように各ディレクトリの所有権を変更します。
 
<syntaxhighlight lang="bash">sudo chown pi:pi /share
 
sudo chown pi:pi /share/movies
 
sudo chown pi:pi /share/photos
 
sudo chown pi:pi /share/musics</syntaxhighlight>
 
  
= 設定 =
+
あと…アプリケーションの設定では「DLL」と「空のプロジェクト」を選択してね。<br/>
「/etc」ディレクトリに「minidlna.conf」ファイルが作成されるので、「nano」等のエディタで設定を変更します。<br/>
+
[[ファイル:CShapeToCppDll-001.jpg]]<br/>
(デフォルトで「media_dir=/var/lib/minidlna」が設定されています。必要に応じてコメントアウトしてください。)
 
  
== 共有設定 ==
 
=== 動画の共有 ===
 
明示的に動画を共有したい場合は、「minidlna.conf」に以下の行を追記します。
 
<pre>media_dir=V,/share/movies</pre>
 
  
=== 画像の共有 ===
+
空のプロジェクトが作成されたら「cpp」「h」「def」ファイルを追加するんだ。今回は「CppDll.cpp」「CppDll.h」「CppDll.def」を追加したよ。
動画と同様に、画像を共有したい場合は、「minidlna.conf」に以下の行を追記します。
 
<pre>media_dir=P,/share/photos</pre>
 
  
=== 音楽の共有 ===
 
音楽を共有したい場合は、「minidlna.conf」に以下の行を追記します。
 
<pre>media_dir=M,/share/musics</pre>
 
  
=== 組み合わせ ===
+
そしたら、プロジェクトのプロパティを開いて「構成プロパティ→リンカー→入力→モジュール定義ファイル」に「CppDll.def」を設定するんだ。<br/>
例えばディレクトリに動画と画像が保存されていて、両方共有したい場合は、以下の様に設定します。
+
(DebugとReleaseでそれぞれ設定する必要があるんだよ。)<br/>
<pre>media_dir=VP,/share/MoviesAndPhotos</pre>
+
[[ファイル:CShapeToCppDll-002.jpg]]<br/>
  
== 新しいファイルの監視 ==
+
== DLLのコード ==
ファイルを格納したときに、自動的に共有する設定をします。<br/>
+
=== ヘッダーファイル(*.h) ===
【修正前】
+
<syntaxhighlight lang="cpp">
<pre>#inotify=yes</pre>
+
#ifndef DLLAPI
【修正後】
+
#define DLLAPI extern "C" __declspec(dllimport)
<pre>inotify=yes</pre>
+
#endif
  
 +
DLLAPI long __stdcall _Sum(const long p_Number1, const long p_Number2);
 +
</syntaxhighlight>
  
また監視間隔を設定します。<br/>
+
=== コードファイル(*.cpp) ===
【修正前】
+
<syntaxhighlight lang="cpp">
<pre>#notify_interval=895</pre>
+
#define DLLAPI
【修正後】
 
<pre>notify_interval=60</pre>
 
(単位は「秒」です。上記の例では1分間隔で監視します)
 
  
 +
#include "CppDll.h"
  
監視が必要なファイル数が非常に多い場合は、以下のコマンドを実行してファイル数を増やしておく必要があります。<br/>
+
DLLAPI long __stdcall _Sum(const long p_Number1, const long p_Number2)
(デフォルトは8192です)
+
{
<syntaxhighlight lang="bash">sudo sysctl fs.inotify.max_user_watches=100000</syntaxhighlight>
+
return p_Number1 + p_Number2;
 +
}
 +
</syntaxhighlight>
  
 +
=== モジュール定義ファイル(*.def) ===
 +
<syntaxhighlight lang="text">
 +
LIBRARY CppDll
  
ただ…このままだと再起動すると値がもとに戻ってしまいます。<br/>
+
EXPORTS
そこで「/etc/sysctl.conf」に以下の行を追記します。
+
_Sum
<syntaxhighlight lang="bash">fs.inotify.max_user_watches=100000</syntaxhighlight>
+
</syntaxhighlight>
  
 +
== C♯のプロジェクト作成 ==
 +
ほとんどそのまま作るんだけど…ソリューションのコンパイル対策をしておくよ。
  
= コマンド =
+
=== ビルドイベントの設定 ===
インストールした状態でサービスは有効になっていますが…各コマンドは以下のとおりです。
+
C++のDLLはソリューションフォルダ直下の「Debug」や「Release」フォルダにDLLが格納されてしまうんだ。そうすると、デバッグするときにDLLが見つからないので、ビルドイベントを使ってコピーしてしまうよ。以下のように設定してね。(「Release」コンパイルするまでは「Release」フォルダがないのでコメントアウトしているよ)<br/>
== 起動 ==
+
[[ファイル:CShapeToCppDll-004.jpg]]<br/>
<syntaxhighlight lang="bash">sudo /etc/init.d/minidlna start</syntaxhighlight>
 
== 終了 ==
 
<syntaxhighlight lang="bash">sudo /etc/init.d/minidlna stop</syntaxhighlight>
 
== 状態確認 ==
 
<syntaxhighlight lang="bash">sudo /etc/init.d/minidlna status</syntaxhighlight>
 
  
= 参考サイト =
+
=== プロジェクトの依存関係の設定 ===
[http://www.lanhome.co.jp/device/raspberry-pi.html Raspberry Piを用いたDLNAホームサーバー|Lanhome]<br/>
+
コピーするにもちゃんとリコンパイルされた資源をコピーしないといけないので、プロジェクトの依存関係を設定することで、ビルドの順番を設定するよ。<Br/>
[https://wiki.archlinux.jp/index.php/ReadyMedia ReadyMedia - ArchWiki]<br/>
+
ソリューションエクスプローラーからC♯のプロジェクトを右クリックして「ビルド依存関係」→「プロジェクト依存関係」を選択してね。<br/>
[https://www.wassyoi-hack.com/solve_no_space/ ラズパイのNo space left on deviceに対処する方法]
+
「依存関係」タブの依存先にC++のプロジェクトが表示されているはずだから、チェックを入れてOKボタンをクリックしてね。
  
[[Category:Debian]]
+
== C♯のコード ==
[[Category:Raspbian]]
+
MVVMモデルでサンプルを作ったからビューモデルが入っているけど…DLLを呼ぶには必要ないから無視してね。
[[Category:Raspberry Pi]]
+
=== モデル ===
[[Category:DLNA]]
+
<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;
 +
 
 +
//追加
 +
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());
 +
        }
 +
    }
 +
}
 +
</syntaxhighlight>
 +
 
 +
=== ビュー ===
 +
<source lang="xml">
 +
<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;
 +
 
 +
//追加
 +
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));
 +
            }
 +
        }
 +
    }
 +
}
 +
</source>
 +
 
 +
[[Category:C♯]]
 +
[[Category:C++]]
 +
[[Category:dll]]

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));
            }
        }
    }
}