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

提供: とある社畜の頭脳整理
(ページ間の差分)
ナビゲーションに移動 検索に移動
 
 
1行目: 1行目:
色々事情がありまして…Dropboxを動作させるユーザーIDとSambaで共有するためのユーザーIDは同一のものにしようとしています。<br/>
+
久しぶりにやったら、すっかり忘れていたので覚書…
また、PC(Windows10)及びRaspbianと共有することが前提となっています。<br/>
 
そこらあたり前提の手順となっておりますが、ご了承ください。
 
  
= Sambaのインストール =
+
== C++のDLLプロジェクト作成 ==
以下のコマンドを実行して、Sambaをインストールします。
+
まず、C++のDLLを作成するときの注意点…
<syntaxhighlight lang="bash">pacman -S samba</syntaxhighlight>
+
作成するプロジェクトは、「Win32プロジェクト」を選択するんだ。<br/>
 +
[[ファイル:CShapeToCppDll-005.jpg]]
  
  
上記でインストールしても設定ファイルが作成されないようです…。<br/>
+
あと…アプリケーションの設定では「DLL」と「空のプロジェクト」を選択してね。<br/>
なので、下記コマンドで設定ファイル「smb.conf」をダウンロードします。
+
[[ファイル:CShapeToCppDll-001.jpg]]<br/>
<syntaxhighlight lang="bash">wget "https://git.samba.org/samba.git/?p=samba.git;a=blob_plain;f=examples/smb.conf.default;hb=HEAD" -O /etc/samba/smb.conf</syntaxhighlight>
 
※wgetがインストールされていない場合は「pacman -S wget」でインストールしてください。
 
  
= 設定 =
 
ここからが難題です…。<br/>
 
Sambaですが汎用性が高いからか、設定が非常に煩雑?です…。<br/>
 
細かいところまで手が届くと言えばそうなのですが…家で適当に使用するにはオーバースペックな感じを受けます…。<br/>
 
  
そこで、できるだけ最小限の設定を目指します。
+
空のプロジェクトが作成されたら「cpp」「h」「def」ファイルを追加するんだ。今回は「CppDll.cpp」「CppDll.h」「CppDll.def」を追加したよ。
  
「nano」等のエディタで「/etc/samba/smb.conf」を開きます。
 
  
== ログの出力先 ==
+
そしたら、プロジェクトのプロパティを開いて「構成プロパティ→リンカー→入力→モジュール定義ファイル」に「CppDll.def」を設定するんだ。<br/>
はじめに…参考サイトにも書かれていますがログの出力先を、一般的な場所に変更します。
+
(DebugとReleaseでそれぞれ設定する必要があるんだよ。)<br/>
 +
[[ファイル:CShapeToCppDll-002.jpg]]<br/>
  
変更前
+
== DLLのコード ==
<syntaxhighlight lang="text">log file = /usr/local/samba/var/log.%m</syntaxhighlight>
+
=== ヘッダーファイル(*.h) ===
 +
<syntaxhighlight lang="cpp">
 +
#ifndef DLLAPI
 +
#define DLLAPI extern "C" __declspec(dllimport)
 +
#endif
  
変更後
+
DLLAPI long __stdcall _Sum(const long p_Number1, const long p_Number2);
<syntaxhighlight lang="text">log file = /var/log/samba/%m.log</syntaxhighlight>
+
</syntaxhighlight>
  
== とりあえず書いてある通りに設定してみる ==
+
=== コードファイル(*.cpp) ===
=== ワークグループの設定 ===
+
<syntaxhighlight lang="cpp">
「workgroup」に「WORKGROUP」を設定します。
+
#define DLLAPI
  
=== ホームディレクトリの設定 ===
+
#include "CppDll.h"
「valid users = %S」だけ書かれていないので追記します。
 
<syntaxhighlight lang="text">[homes]
 
  comment = Home Directories
 
  browseable = no
 
  writable = yes
 
  valid users = %S</syntaxhighlight>
 
ちなみに…「%S」ですが、ユーザーIDが入るようです。<br/>
 
で「valid users」は許可するユーザーなので…<br/>
 
みんな許可するってことになるかと思います。
 
  
=== サービスの起動 ===
+
DLLAPI long __stdcall _Sum(const long p_Number1, const long p_Number2)
以下のコマンドで2つのサービスを起動します。
+
{
<syntaxhighlight lang="bash">systemctl start smb
+
return p_Number1 + p_Number2;
systemctl start nmb</syntaxhighlight>
+
}
 +
</syntaxhighlight>
  
== ユーザーの追加 ==
+
=== モジュール定義ファイル(*.def) ===
Sambaに接続するためのユーザーを追加します。
+
<syntaxhighlight lang="text">
 +
LIBRARY CppDll
  
Sambaで利用するユーザーはArchLinuxのユーザーとして登録されている必要があります。<br/>
+
EXPORTS
今回は「dropbox-test」というユーザーを追加してみます。
+
_Sum
 +
</syntaxhighlight>
  
=== ArchLinuxにユーザーを追加 ===
+
== C♯のプロジェクト作成 ==
まず、ArchLinuxにユーザーを追加します。
+
ほとんどそのまま作るんだけど…ソリューションのコンパイル対策をしておくよ。
<syntaxhighlight lang="bash">useradd -m dropbox-test</syntaxhighlight>
 
続けてパスワードを設定します。
 
<syntaxhighlight lang="bash">passwd dropbox-test</syntaxhighlight>
 
  
 +
=== ビルドイベントの設定 ===
 +
C++のDLLはソリューションフォルダ直下の「Debug」や「Release」フォルダにDLLが格納されてしまうんだ。そうすると、デバッグするときにDLLが見つからないので、ビルドイベントを使ってコピーしてしまうよ。以下のように設定してね。(「Release」コンパイルするまでは「Release」フォルダがないのでコメントアウトしているよ)<br/>
 +
[[ファイル:CShapeToCppDll-004.jpg]]<br/>
  
これで、Smabaのユーザーを登録する準備が整いました。<br/>
+
=== プロジェクトの依存関係の設定 ===
 +
コピーするにもちゃんとリコンパイルされた資源をコピーしないといけないので、プロジェクトの依存関係を設定することで、ビルドの順番を設定するよ。<Br/>
 +
ソリューションエクスプローラーからC♯のプロジェクトを右クリックして「ビルド依存関係」→「プロジェクト依存関係」を選択してね。<br/>
 +
「依存関係」タブの依存先にC++のプロジェクトが表示されているはずだから、チェックを入れてOKボタンをクリックしてね。
  
=== Sambaにユーザーを追加 ===
+
== C♯のコード ==
引き続き、以下のコマンドでSambaにユーザーを登録します。
+
MVVMモデルでサンプルを作ったからビューモデルが入っているけど…DLLを呼ぶには必要ないから無視してね。
<syntaxhighlight lang="bash">pdbedit -a -u dropbox-test</syntaxhighlight>
+
=== モデル ===
「-a」はユーザーの追加、「-u」はユーザー名を指定する、という意味です。
+
<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;
  
登録したときに以下のようなメッセージが表示されれば成功です。
+
//追加
<syntaxhighlight lang="text">Unix username:        dropbox-test
+
using System.Runtime.InteropServices;
NT username:         
 
Account Flags:        [U          ]
 
User SID:            S-1-5-21-3457465057-3604410224-1916174006-1000
 
Primary Group SID:    S-1-5-21-3457465057-3604410224-1916174006-513
 
Full Name:           
 
Home Directory:      \\archlinux\dropbox-test
 
HomeDir Drive:       
 
Logon Script:       
 
Profile Path:        \\archlinux\dropbox-test\profile
 
Domain:              ARCHLINUX
 
Account desc:       
 
Workstations:       
 
Munged dial:         
 
Logon time:          0
 
Logoff time:          木, 07  2月 2036 00:06:39 JST
 
Kickoff time:        木, 07  2月 2036 00:06:39 JST
 
Password last set:    金, 05  7月 2019 14:51:27 JST
 
Password can change:  金, 05  7月 2019 14:51:27 JST
 
Password must change: never
 
Last bad password  : 0
 
Bad password count  : 0
 
Logon hours        : FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</syntaxhighlight>
 
  
= 接続 =
+
namespace CSharpToCDLL
== Windowsの場合 ==
+
{
ホームディレクトリの設定しかしていませんが…Windowsから接続してみます。<br/>
+
    /// <summary>
エクスプローラーのアドレス欄に、サーバーのIPアドレスを入力します。<br/>
+
    /// MainWindow.xaml の相互作用ロジック
すると、以下の様にIDとパスワードを聞かれます。<br/>
+
    /// </summary>
(画面がWindows10では無いですが…)<br/>
+
    public partial class MainWindow : Window
[[ファイル:archlinux-samba-001.png | 400px]]
+
    {
 +
        /// <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);
  
Samba用に登録したユーザーIDとパスワードを入力します。<br/>
+
        /// <summary>
ログインすると、ユーザーIDと同じ名前の共有フォルダがあるかと思います。
+
        /// 標準のコンストラクタ
 +
        /// </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);
  
== Linuxの場合 ==
+
            //計算結果の表示
=== コマンド接続 ===
+
            MessageBox.Show("計算結果:" + l_Result.ToString());
クライアント側で以下のコマンドを実行します。
+
        }
<syntaxhighlight lang="bash">mkdir /mnt/Homes
+
    }
mount.cifs -o username=[userid],password=[password],iocharset=utf8,rw,vers=3.0 //[ip address]/Homes /mnt/Homes</syntaxhighlight>
+
}
 +
</syntaxhighlight>
  
=== 起動時接続 ===
+
=== ビュー ===
「nano」等のエディタで「/etc/fstab」を以下の行を追記します。
+
<source lang="xml">
<syntaxhighlight lang="bash">//[ip address]/Homes /mnt/Homes cifs username=[userid],password=[password],iocharset=utf8,rw,x-systemd.automount,_netdev,vers=3.0 0 2</syntaxhighlight>
+
<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;
  
= 任意のディレクトリを共有 =
+
//追加
今度は任意のディレクトリを共有してみます。<br/>
+
using System.ComponentModel;
共有するディレクトリは「/mnt/Dropbox」ですwww。<br/>
 
ドロップボックスのディレクトリを共有します。
 
  
== 共有ディレクトリの作成 ==
+
namespace CSharpToCDLL
まぁ書くほどのことは無いですが…
+
{
<syntaxhighlight lang="bash">mkdir /mnt/Dropbox</syntaxhighlight>
+
    class MainWindowViewModel : INotifyPropertyChanged
でディレクトリを作成します。<br/>
+
    {
また、所有者を以下のコマンドで「dropbox-test」に変更します。
+
        /// <summary>
<syntaxhighlight lang="bash">chown dropbox-test:dropbox-test /mnt/Dropbox</syntaxhighlight>
+
        /// ラベル表示用変数
 +
        /// </summary>
 +
        private String m_Label_Content;
  
== 共有設定 ==
+
        /// <summary>
先ほどと同じく「/etc/samba/smb.conf」を編集していきます。<br/>
+
        /// ラベル表示文字列
ファイルの最後に以下を追記します。
+
        /// </summary>
<syntaxhighlight lang="text">[Dropbox]
+
        public String Label_Content
  comment = Dropbox Directory
+
        {
  path = /mnt/Dropbox
+
            set
  writable = yes
+
            {
  valid users = dropbox-test</syntaxhighlight>
+
                this.m_Label_Content = value;
 +
                this.OnPropertyChanged("Label_Content");
 +
            }
 +
            get { return this.m_Label_Content; }
 +
        }
  
== サービスの読み込み直し ==
+
        /// <summary>
以下のコマンドで読み込み直します。
+
        /// プロパティ変更イベントハンドラ
<syntaxhighlight lang="bash">systemctl reload smb
+
        /// </summary>
systemctl reload nmb</syntaxhighlight>
+
        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]]
= 参考サイト =
 
[https://wiki.archlinux.jp/index.php/Samba Samba - ArchWiki]<br/>
 
[http://www.samba.gr.jp/doc/samba2.0_and_linux.html 日本Sambaユーザ会 - SambaによるWindowsファイルサーバ構築]<br/>
 
 
 
[[Category:ArchLinux]]
 
[[Category:Samba]]
 

2019年7月26日 (金) 16: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));
            }
        }
    }
}