VC++で.NET Framework 内のクラスを利用する方法を紹介します。今回は、文字列のハッシュ化を行うSHA256Managedクラスの使い方です。
MFC DLLを使った実装
今回は、VC++で作成されたアプリケーションで古くから使われているMFCを使った実装方法を紹介していきます。サンプルコードでは、後で再利用しやすいようにDLLとしてエクスポートを行っています。
プロジェクト作成
[ファイル|新規作成|プロジェクト]メニューを選択して、[新しいプロジェクト]として[MFC DLL]を選択します。
[MFC DLL]プロジェクトのテンプレートが無い場合には、[Visual Studio インストーラーを開く]リンクをクリックして、表示された[Visual Studio インストーラー]画面で[C++によるデスクトップ開発]のオプションで[x86用とx64用のVisual C++ MFC]を追加します。
プロジェクトを作成する途中で表示される[MFC DLL]画面では、既定値のまま[OK]ボタンをクリックします。
プロパティ変更
VC++で開発するアプリケーションはアンマネージドコードと呼ばれる、通常のSDKなどのライブラリを駆使して作成することが多いため、既定値では、MFCプロジェクトは.NET Frameworkのクラスを利用するための設定になっていません。
次の手順で変更を行います。
- [プロジェクト|<プロジェクト>のプロパティ]メニューを選択します。
- 表示された[<プロジェクト> プロパティ ページ]画面で[構成プロパティ|全般|共通言語ランタイム サポート]を[共通言語ランタイム サポート(/clr)]に変更します。
- [OK]ボタンをクリックして[<プロジェクト> プロパティ ページ]を閉じます。
コードの編集
共通言語ランタイム サポートの変更を行ったら、いよいよコードを追加していきます。
最初に行う手順は、アセンブリの追加です。
作成したプロジェクトのソースファイル(拡張子.cpp ファイル)の先頭部分に以下のコードを追加します。
using namespace System;
using namespace System::Text;
using namespace System::Collections;
C#の構文に似ていますが、若干違う形で利用するクラスのアセンブリを追加していきます。
次に、インスタンス初期化の直後くらいに実行する部分の本体を追加します。今回は[sha256]という関数名にしました。
CString sha256(CString sMessage)
{
String^ sSourceString = gcnew String(sMessage);
sSourceString = sSourceString->Trim();
ASCIIEncoding^ ascii = gcnew ASCIIEncoding();
array<Byte>^ aSource = ascii->GetBytes(sSourceString);
array<Byte>^ aHash = (gcnew System::Security::Cryptography::SHA256Managed())->ComputeHash(aSource);
StringBuilder^ sOutput = gcnew StringBuilder(aHash->Length);
for (int i = 0; i < aHash->Length; i++)
{
sOutput->Append(aHash[i].ToString("x2"));
}
return sOutput->ToString();
}
gcnewと呼ばれる部分が多く見えますが、これはマネージドのクラスを利用する場合の変数の確保として一般的な方法で、通常のC++のポインタ変数をnewで確保する部分に似ています。
マネージドの場合は、こんな感じで
String^ sSourceString = gcnew String(sMessage);
アンマネージドの場合は、こんな感じになります。
char* pChar = new char[16];
VC++を普段使っている方は、アンマネージドの方法で変数を確保しているはずです。
また。分かりやすいように、SHA256Managedまでのアセンブリを残して記載していますが、先述の冒頭部分に、[using namespace System::Security::Cryptography;]と書いても大丈夫です。今回は”ComputeHash”メソッドは1回しか使わないので、労力は同じですので、どちらでも構いません。
最後に、DLLで利用できるようにエクスポート部分を追加します。
extern "C" __declspec(dllexport) long hashsha256(char* pSourceString, char* pHashString)
{
int nSize = 0;
if (pSourceString == NULL)
{
return nSize;
}
CString sSourceString = CString(pSourceString);
CString sHashString = sha256(sSourceString);
nSize = sHashString.GetLength();
if (pHashString == NULL)
{
return nSize;
}
memset(pHashString, 0x00, nSize);
memcpy(pHashString, sHashString.GetBuffer(), nSize);
sHashString.ReleaseBuffer();
return nSize;
}
すべての追加したコードは、こんな感じになります。
// MFCLibrary1.cpp : DLL の初期化ルーチンを定義します。
//
#include "stdafx.h"
#include "MFCLibrary1.h"
using namespace System;
using namespace System::Text;
using namespace System::Collections;
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
//
//TODO: この DLL が MFC DLL に対して動的にリンクされる場合、
// MFC 内で呼び出されるこの DLL からエクスポートされたどの関数も
// 関数の最初に追加される AFX_MANAGE_STATE マクロを
// 持たなければなりません。
//
// 例:
//
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
// // 通常関数の本体はこの位置にあります
// }
//
// このマクロが各関数に含まれていること、MFC 内の
// どの呼び出しより優先することは非常に重要です。
// it は、次の範囲内で最初のステートメントとして表示されるべきです
// らないことを意味します、コンストラクターが MFC
// DLL 内への呼び出しを行う可能性があるので、オブ
// ジェクト変数の宣言よりも前でなければなりません。
//
// 詳細については MFC テクニカル ノート 33 および
// 58 を参照してください。
//
// CMFCLibrary1App
BEGIN_MESSAGE_MAP(CMFCLibrary1App, CWinApp)
END_MESSAGE_MAP()
// CMFCLibrary1App の構築
CMFCLibrary1App::CMFCLibrary1App()
{
// TODO: この位置に構築用コードを追加してください。
// ここに InitInstance 中の重要な初期化処理をすべて記述してください。
}
// 唯一の CMFCLibrary1App オブジェクト
CMFCLibrary1App theApp;
// CMFCLibrary1App の初期化
BOOL CMFCLibrary1App::InitInstance()
{
CWinApp::InitInstance();
return TRUE;
}
CString sha256(CString sMessage)
{
String^ sSourceString = gcnew String(sMessage);
sSourceString = sSourceString->Trim();
ASCIIEncoding^ ascii = gcnew ASCIIEncoding();
array<Byte>^ aSource = ascii->GetBytes(sSourceString);
array<Byte>^ aHash = (gcnew System::Security::Cryptography::SHA256Managed())->ComputeHash(aSource);
StringBuilder^ sOutput = gcnew StringBuilder(aHash->Length);
for (int i = 0; i < aHash->Length; i++)
{
sOutput->Append(aHash[i].ToString("x2"));
}
return sOutput->ToString();
}
extern "C" __declspec(dllexport) long hashsha256(char* pSourceString, char* pHashString)
{
int nSize = 0;
if (pSourceString == NULL)
{
return nSize;
}
CString sSourceString = CString(pSourceString);
CString sHashString = sha256(sSourceString);
nSize = sHashString.GetLength();
if (pHashString == NULL)
{
return nSize;
}
memset(pHashString, 0x00, nSize);
memcpy(pHashString, sHashString.GetBuffer(), nSize);
sHashString.ReleaseBuffer();
return nSize;
}
まとめ
DLL化する利点としては、アンマネージドなプロジェクトとして作成したアプリケーションから、マネージドクラスを利用した部分が使いたい場合に、その部分だけをエクスポートしておくことで、使うことができます。
本体プロジェクトをすべてアンマネージドに設定することなく、セキュリティなどのデメリットを最小限にとどめることができます。
スポンサーリンク
最後までご覧いただき、ありがとうございます。