ページ「MediaWikiの「構文ハイライトエラー」」と「C♯のモジュールからC++のDLLを呼び出してみる」の間の差分

提供: とある社畜の頭脳整理
(ページ間の差分)
ナビゲーションに移動 検索に移動
 
 
1行目: 1行目:
さくらのレンタルサーバーで最新のMediaWikiを使用していることが前提なんだけど…<br/>
+
久しぶりにやったら、すっかり忘れていたので覚書…
「SyntaxHighlight」を使用すると、「構文ハイライトエラー」になってしまう…。
 
  
 +
== C++のDLLプロジェクト作成 ==
 +
まず、C++のDLLを作成するときの注意点…
 +
作成するプロジェクトは、「Win32プロジェクト」を選択するんだ。<br/>
 +
[[ファイル:CShapeToCppDll-005.jpg]]
  
原因は単純でさくらのレンタルサーバーのPythonは現時点で2.7…SyntaxHighlightはPython3が前提…<br/>
 
当然うまく動かないわけです…。
 
  
 +
あと…アプリケーションの設定では「DLL」と「空のプロジェクト」を選択してね。<br/>
 +
[[ファイル:CShapeToCppDll-001.jpg]]<br/>
  
そこで、ホームディレクトリにPython3を入れて、そちらを参照するようにSyntaxHighlightを書き換えちゃいます。
 
  
= Python3のインストール =
+
空のプロジェクトが作成されたら「cpp」「h」「def」ファイルを追加するんだ。今回は「CppDll.cpp」「CppDll.h」「CppDll.def」を追加したよ。
参考サイトに基づいて、Pythonの最新版(Python3)をインストールしていきます。<br/>
 
先ずはホームディレクトリに作業用のディレクトリを作成して移動します。
 
<syntaxhighlight lang="bash">mkdir ~/work
 
cd work</syntaxhighlight>
 
  
  
次に、wgetコマンドでPythonの公式サイトからモジュールをダウンロードします。
+
そしたら、プロジェクトのプロパティを開いて「構成プロパティ→リンカー→入力→モジュール定義ファイル」に「CppDll.def」を設定するんだ。<br/>
<syntaxhighlight lang="bash">wget https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tar.xz</syntaxhighlight>
+
(DebugとReleaseでそれぞれ設定する必要があるんだよ。)<br/>
(ダウンロードパスは適宜見直してください)
+
[[ファイル:CShapeToCppDll-002.jpg]]<br/>
  
 +
== DLLのコード ==
 +
=== ヘッダーファイル(*.h) ===
 +
<syntaxhighlight lang="cpp">
 +
#ifndef DLLAPI
 +
#define DLLAPI extern "C" __declspec(dllimport)
 +
#endif
  
ダウンロードしたらtarコマンドで解凍します。
+
DLLAPI long __stdcall _Sum(const long p_Number1, const long p_Number2);
<syntaxhighlight lang="bash">tar -xzf Python-3.7.4.tar.xz</syntaxhighlight>
+
</syntaxhighlight>
  
 +
=== コードファイル(*.cpp) ===
 +
<syntaxhighlight lang="cpp">
 +
#define DLLAPI
  
解凍すると「Python-3.7.4」ディレクトリが作成されますので、そこに移動します。
+
#include "CppDll.h"
<syntaxhighlight lang="bash">cd Python-3.7.4</syntaxhighlight>
 
  
 +
DLLAPI long __stdcall _Sum(const long p_Number1, const long p_Number2)
 +
{
 +
return p_Number1 + p_Number2;
 +
}
 +
</syntaxhighlight>
  
以下のコマンドでインストール先を変更します。
+
=== モジュール定義ファイル(*.def) ===
<syntaxhighlight lang="bash">./configure --prefix=$HOME/local/python/</syntaxhighlight>
+
<syntaxhighlight lang="text">
 +
LIBRARY CppDll
  
 +
EXPORTS
 +
_Sum
 +
</syntaxhighlight>
  
そしたらmakeしてインストールします。
+
== C♯のプロジェクト作成 ==
<syntaxhighlight lang="bash">make
+
ほとんどそのまま作るんだけど…ソリューションのコンパイル対策をしておくよ。
make install</syntaxhighlight>
 
  
 +
=== ビルドイベントの設定 ===
 +
C++のDLLはソリューションフォルダ直下の「Debug」や「Release」フォルダにDLLが格納されてしまうんだ。そうすると、デバッグするときにDLLが見つからないので、ビルドイベントを使ってコピーしてしまうよ。以下のように設定してね。(「Release」コンパイルするまでは「Release」フォルダがないのでコメントアウトしているよ)<br/>
 +
[[ファイル:CShapeToCppDll-004.jpg]]<br/>
  
インストールに使用したディレクトリは削除しちゃいます。
+
=== プロジェクトの依存関係の設定 ===
<syntaxhighlight lang="bash">cd ~
+
コピーするにもちゃんとリコンパイルされた資源をコピーしないといけないので、プロジェクトの依存関係を設定することで、ビルドの順番を設定するよ。<Br/>
rm -fr work</syntaxhighlight>
+
ソリューションエクスプローラーからC♯のプロジェクトを右クリックして「ビルド依存関係」→「プロジェクト依存関係」を選択してね。<br/>
 +
「依存関係」タブの依存先にC++のプロジェクトが表示されているはずだから、チェックを入れてOKボタンをクリックしてね。
  
= SyntaxHighlightの編集 =
+
== 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;
  
 +
//追加
 +
using System.Runtime.InteropServices;
  
先ずは編集するコードが有るところまで移動します。<br/>
+
namespace CSharpToCDLL
ターゲットは「create_pygmentize_bundle」ファイルです。
+
{
<syntaxhighlight lang="bash">cd [MdiaWikiのディレクトリ]/extensions/SyntaxHighlight_GeSHi/pygments</syntaxhighlight>
+
    /// <summary>
[MdiaWikiのディレクトリ]は自分の環境に合わせて書き換えてください。
+
    /// 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>
<syntaxhighlight lang="bash">cp create_pygmentize_bundle create_pygmentize_bundle_bk
+
        /// ボタンクリックイベントハンドラ
mv pygmentize pygmentize_bk</syntaxhighlight>
+
        /// </summary>
(「pygmentize」ファイルは作成し直すので、mvしています)
+
        /// <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>
  
「create_pygmentize_bundle」ファイルを修正します。<br/>
+
=== ビュー ===
以下の様に修正してください
+
<source lang="xml">
<syntaxhighlight lang="python" line highlight="1,19,60">#!/home/[userid]/local/python/bin/python3
+
<Window x:Class="CSharpToCDLL.MainWindow"
# -*- coding: utf-8 -*-
+
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
"""
+
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Create a standalone, executable 'pygmentize' bundle.
+
        Title="MainWindow"
  Author: Ori Livneh
+
        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;
  
"""
+
//追加
import hashlib
+
using System.ComponentModel;
import io
 
import os
 
import stat
 
import textwrap
 
import urllib.request
 
import xmlrpc.client
 
import zipfile
 
  
 +
namespace CSharpToCDLL
 +
{
 +
    class MainWindowViewModel : INotifyPropertyChanged
 +
    {
 +
        /// <summary>
 +
        /// ラベル表示用変数
 +
        /// </summary>
 +
        private String m_Label_Content;
  
PYGMENTIZE_LAUNCHER = textwrap.dedent('''\
+
        /// <summary>
  #!/home/[userid]/local/python/bin/python3
+
        /// ラベル表示文字列
 +
        /// </summary>
 +
        public String Label_Content
 +
        {
 +
            set
 +
            {
 +
                this.m_Label_Content = value;
 +
                this.OnPropertyChanged("Label_Content");
 +
            }
 +
            get { return this.m_Label_Content; }
 +
        }
  
  import sys
+
        /// <summary>
  import pygments.cmdline
+
        /// プロパティ変更イベントハンドラ
  try:
+
        /// </summary>
      sys.exit(pygments.cmdline.main(sys.argv))
+
        public event PropertyChangedEventHandler PropertyChanged;
  except KeyboardInterrupt:
 
      sys.exit(1)
 
''')
 
  
 +
        /// <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>
  
print('Querying PyPI for the latest Pygments release...')
+
[[Category:C♯]]
pypi = xmlrpc.client.ServerProxy('https://pypi.python.org/pypi')
+
[[Category:C++]]
latest_version = pypi.package_releases('Pygments')[0]
+
[[Category:dll]]
url = None
 
for release in pypi.release_urls('Pygments', latest_version):
 
    if (release['packagetype'] == 'bdist_wheel' and
 
            release['python_version'].startswith('py2')):
 
        url = release['url']
 
        md5_digest = release['md5_digest']
 
        break
 
 
 
if not url:
 
        raise RuntimeError('No suitable package found.')
 
 
 
print('Retrieving version %s (%s)...' % (latest_version, url))
 
req = urllib.request.urlopen(url)
 
buf = io.BytesIO(req.read())
 
 
 
print('Verifying...')
 
if hashlib.md5(buf.getvalue()).hexdigest() != md5_digest:
 
    raise RuntimeError('MD5 checksum mismatch.')
 
 
 
print('Creating executable ZIP bundle...')
 
with zipfile.ZipFile(buf, 'a') as zf:
 
    zf.writestr('__main__.py', PYGMENTIZE_LAUNCHER)
 
 
 
data = buf.getvalue()
 
script_dir = os.path.dirname(os.path.abspath(__file__))
 
file_path = os.path.join(script_dir, 'pygmentize')
 
with open(file_path, 'wb') as f:
 
    f.write(b'#!/home/[userid]/local/python/bin/python3\n')
 
    f.write(data)
 
 
 
file_st = os.stat(file_path)
 
os.chmod(file_path, file_st.st_mode | stat.S_IEXEC)
 
 
 
with open(os.path.join(script_dir, 'VERSION'), 'w') as f:
 
    f.write(latest_version + '\n')
 
 
 
print('Done. Wrote %s bytes to %s' % (len(data), file_path))</syntaxhighlight>
 
([userid]は書き直してください)
 
 
 
 
 
最後に「pygmentize」を作成し直します。
 
<syntaxhighlight lang="bash">/home/[userid]/local/python/bin/python3 ./create_pygmentize_bundle</syntaxhighlight>
 
([userid]は書き直してください)
 
 
 
= WEBブラウザのキャッシュ =
 
WEBブラウザのキャッシュが残っていると、なかなか変わった感じがしないかもしれません。<br/>
 
そんな時は例えば「<syntaxhighlight lang="bash">」を「<syntaxhighlight lang="bash" line>」などに書き直してみてください。<br/>
 
これで、行番号が表示されればOKです。
 
 
 
= 参考サイト =
 
[https://emptypage.jp/notes/pymods-on-sakura.html さくらのレンタルサーバで Python 外部モジュールを使う]<br/>
 
[https://affitips.com/pages/65.html さくらにPython3をインストールしたときのメモ - アフィリエイト&ウェブ制作のtips]
 
 
 
[[Category:さくらサーバー]]
 
[[Category:MediaWiki]]
 
[[Category:Python3]]
 
[[Category:SyntaxHighlight]]
 

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