「C++の応用 - C Sharp DLLの使用」の版間の差分
(→デバッグ) |
|||
200行目: | 200行目: | ||
return 0; | return 0; | ||
} | } | ||
</syntaxhighlight> | |||
<br><br> | |||
== C# DLLをCOM参照可能にしてC++ EXEから使用する == | |||
まず、C# DLLプロジェクトを作成して、アセンブリ情報を設定する。<br> | |||
# C# DLLプロジェクトのプロパティを開く。 | |||
# プロパティ画面左にある[アプリケーション]タブを選択して、[アセンブリ情報]ボタンを押下する。 | |||
# [アセンブリをCOM参照可能にする]チェックボックスにチェックを入力して、[OK]ボタンを押下する。 | |||
<br> | |||
次に、ビルドの設定を行う。<br> | |||
# C# DLLプロジェクトのプロパティを開く。 | |||
# プロパティ画面左にある[ビルド]タブを選択して、[COM相互運用機能の登録]チェックボックスにチェックを入力する。 | |||
# C# DLLプロジェクトのプロパティを保存する。 | |||
<br> | |||
<u>※注意1</u><br> | |||
<u>[COM相互運用機能の登録]は、<code>regasm</code>コマンドによるCOMのレジストリ登録を、ビルド時に自動で行う機能と思われる。</u><br> | |||
<u>そのため、開発時(デバッグ時)は有効にした方が便利であるが、インストール時はCOMのレジストリ登録が自動で行われないため注意すること。</u><br> | |||
<br> | |||
<u>※注意2</u><br> | |||
<u>Windowsにログインしているアカウントの権限によっては、ビルド時にレジストリへの登録に失敗するエラーが発生することがある。</u><br> | |||
<u>その時は、Visual Studioを管理者権限で実行すれば登録できる。</u><br> | |||
<br> | |||
C# DLLでは、以下のような内容のソースコードを記述する。<br> | |||
この時、C++ EXE側から呼ぶクラスには、以下の属性を付加する。<br> | |||
* ComVisible | |||
* ClassInterface | |||
* Guid (Visual Studioの[ツール]メニューバー - [GUIDの作成]を選択する) | |||
<syntaxhighlight lang="c#"> | |||
// CSharpCOMDLL.csファイル | |||
using System; | |||
using System.Runtime.InteropServices; | |||
namespace CSharpCOMDLL | |||
{ | |||
[ComVisible(true)] | |||
[ClassInterface(ClassInterfaceType.AutoDual)] | |||
[Guid("85555B74-E2E0-4493-9869-3CE95F13CB99")] // Visual Studioの[ツール]メニューバー - [GUIDの作成]を選択する | |||
public class CSharpCOMDLLClass | |||
{ | |||
public Int32 Add(Int32 iParam1, Int32 iParam2) | |||
{ | |||
int iRet = iParam1 + iParam2; | |||
return (Int32)iRet; | |||
} | |||
public Int32 AddStr([MarshalAs(UnmanagedType.BStr)]string str) // 文字列を指定する場合はマーシャリングする | |||
{ | |||
Console.WriteLine(str); | |||
return (Int32)0; | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
C++ EXEプロジェクトを作成して、以下のような内容のソースコードを記述する。<br> | |||
<syntaxhighlight lang="c++"> | |||
// main.cppファイル | |||
#include <iostream> | |||
#include <Windows.h> | |||
IDispatch *pIDisp = NULL; | |||
IUnknown *pIUnk = NULL; | |||
long Init(void); | |||
long Finalize(void); | |||
long AddInt(long p_Number1, long p_Number2); | |||
long AddStr(); | |||
int main() | |||
{ | |||
// COMの初期化処理 | |||
Init(); | |||
// C# DLLのメソッドを呼ぶ | |||
int l_Result = Add(300, 500); | |||
//後処理 | |||
Finalize(); | |||
printf("Calc Result : %d", l_Result); | |||
return 0; | |||
} | |||
// 初期化関数 | |||
long Init(void) | |||
{ | |||
// COMの初期化 | |||
::CoInitialize(NULL); | |||
// ProcIDからCLSIDを取得(ネームスペース名.クラス名) | |||
CLSID clsid; | |||
HRESULT h_result = CLSIDFromProgID(L"CSharpCOMDLL.CSharpCOMDLLClass", &clsid); // 第1引数は、呼び出すC# DLLの<名前空間名>.<クラス名>にすること | |||
if (FAILED(h_result)) | |||
{ | |||
return -1; | |||
} | |||
// インスタンスの生成 | |||
h_result = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pIUnk); | |||
if (FAILED(h_result)) | |||
{ | |||
return -2; | |||
} | |||
// インターフェースの取得(pIDispは共通変数) | |||
h_result = pIUnk->QueryInterface(IID_IDispatch, (void**)&pIDisp); | |||
if (FAILED(h_result)) | |||
{ | |||
return -3; | |||
} | |||
return 0; | |||
} | |||
// COMの終了処理 | |||
long Finalize() | |||
{ | |||
// インスタンスの開放 | |||
pIDisp->Release(); | |||
// インターフェイスの開放 | |||
pIUnk->Release(); | |||
// COMの開放 | |||
::CoUninitialize(); | |||
return 0; | |||
} | |||
// C# DLLのメソッドを呼ぶ | |||
long AddInt(long p_Number1, long p_Number2) | |||
{ | |||
// メソッド名からID(DISPID)を取得(関数名の設定) | |||
DISPID dispid = 0; | |||
OLECHAR *Func_Name[] = { SysAllocString (L"Add") }; // C# DLLの呼び出すメソッド名を指定する | |||
HRESULT h_result = pIDisp->GetIDsOfNames(IID_NULL, Func_Name, 1, LOCALE_SYSTEM_DEFAULT, &dispid); | |||
if (FAILED(h_result)) | |||
{ | |||
return -1; | |||
} | |||
// メソッドに渡すパラメータを作成(DISPPARAMS、 VariantInit等) | |||
DISPPARAMS params = {0}; | |||
params.cNamedArgs = 0; | |||
params.rgdispidNamedArgs = NULL; | |||
params.cArgs = 2; // 呼び出す関数の引数の数 | |||
// 引数の指定 (順番が逆になることに注意すること) | |||
VARIANTARG* pVarg = new VARIANTARG[params.cArgs]; | |||
pVarg[0].vt = VT_I4; | |||
pVarg[0].lVal = p_Number2; | |||
pVarg[1].vt = VT_I4; | |||
pVarg[1].lVal = p_Number1; | |||
params.rgvarg = pVarg; | |||
VARIANT vRet; | |||
VariantInit(&vRet); | |||
// C# DLLのメソッドを呼ぶ(pIDisp->Invoke) | |||
pIDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, ¶ms, &vRet, NULL, NULL); | |||
delete[] pVarg; | |||
return vRet.lVal; | |||
} | |||
long AddStr() | |||
{ | |||
// メソッド名からID(DISPID)を取得(関数名の設定) | |||
DISPID dispid = 0; | |||
OLECHAR *Func_Name[] = { SysAllocString (L"AddStr") }; | |||
HRESULT h_result = pIDisp->GetIDsOfNames(IID_NULL, Func_Name, 1, LOCALE_SYSTEM_DEFAULT, &dispid); | |||
if (FAILED(h_result)) | |||
{ | |||
return -1; | |||
} | |||
// メソッドに渡すパラメータを作成(DISPPARAMS、 VariantInit等) | |||
DISPPARAMS params = {0}; | |||
params.cNamedArgs = 0; | |||
params.rgdispidNamedArgs = NULL; | |||
params.cArgs = 1; // 呼び出すメソッドの引数の数 | |||
// 引数の指定 (順番が逆になることに注意すること) | |||
VARIANT var; | |||
DISPPARAMS dispParams; | |||
var.vt = VT_BSTR; // 引数に渡すデータ型をBSTRにする | |||
var.bstrVal = SysAllocString(L"あいうえお"); // 引数に渡す文字列 | |||
dispParams.cArgs = 1; | |||
dispParams.rgvarg = &var; | |||
dispParams.cNamedArgs = 0; | |||
dispParams.rgdispidNamedArgs = NULL; | |||
VARIANT vRet; | |||
VariantInit(&vRet); | |||
// C# DLLのメソッドを呼ぶ(pIDisp->Invoke) | |||
printf("[OK] Invoke start\r\n"); | |||
h_result = pIDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispParams, &vRet, NULL, NULL); | |||
if (FAILED(h_result)) | |||
{ | |||
printf("[NG] Invoke failed\r\n"); | |||
return -2; | |||
} | |||
return vRet.lVal; | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
管理者権限でPowerShellまたはコマンドプロンプトを実行する。<br> | |||
次に、<code>regasm</code>コマンドを使用して、C# DLL(COM)を登録する。<br> | |||
C# DLLのプラットフォーム(x86/x64)により、x86/x64向けの<code>regasm</code>と合致させる必要があることに注意する。<br> | |||
<br> | |||
また、regasm.exeをC++ EXE側のプロジェクトディレクトリにコピーして実行しても構わない。<br> | |||
# プロジェクトがx86の場合 | |||
C:\Windows\Microsoft.NET\Framework\<.NETのバージョン>\regasm /codebase <C# DLLのファイル名>.dll | |||
# プロジェクトがx64の場合 | |||
C:\Windows\Microsoft.NET\Framework64\<.NETのバージョン>\regasm /codebase <C# DLLのファイル名>.dll | |||
<br> | |||
C++ EXEを実行する場合、以下の内容のバッチファイルを作成して、管理者権限で実行する。<br> | |||
常に<code>regasm</code>コマンドを実行する場合、C# DLLプロジェクトの[COM相互運用機能の登録]の設定は不要である。<br> | |||
<u>ただし、デバッグ時においては有効にした方が便利である。</u><br> | |||
<syntaxhighlight lang="bat"> | |||
rem exerun.batファイル | |||
@echo off | |||
cd %~dp0 | |||
regasm /codebase <C# DLLのファイル名>.dll | |||
start /wait <C++ EXEのファイル名>.exe | |||
echo exeからの戻り値は %ERRORLEVEL% です | |||
pause | |||
</syntaxhighlight> | </syntaxhighlight> | ||
<br><br> | <br><br> |
2021年12月12日 (日) 17:59時点における版
概要
C++ EXEからC# DLLの関数を呼び出す方法は、幾つか方法が存在しており、各々にメリットとデメリットがある。
下記の表1に代表的な4種類の方法を示す。
表1. C++ EXEからC# DLLの関数を呼び出す方法
方法 | メリット | デメリット |
---|---|---|
C++/CLIを使う | 最も簡単 VisualStudioのIntelliSenseも使用可能 |
プロジェクトの設定で[CLIを使う]に変更する必要がある |
C# DLL側で関数をエクスポートする | [CLIを使う]に変更しなくてよいGetProcAddress 関数が使用できるため、よく知られた方法で関数を呼び出す事が出来る |
C# DLL側のソースコードが無い場合は利用できない |
C# DLL側をCOM 参照可能にする | [CLIを使う]に変更しなくてよい | C++ EXEのコード量が増えて面倒である |
C# DLLに対するC++/CLIの ラッパープロジェクトを 作成して、C++ EXEから使う |
[CLIを使う]に変更しなくてよい COMを使用しない場合において、 元のプロジェクトの設定を変更したくない場合に使用可能 |
やり方がスマートではない |
上記の表1において、C++/CLIを使う方法とC# DLL側で関数をエクスポートする方法、C++/CLIのラッパープロジェクトを作成する方法を
下記にて紹介する。
C++/CLIを使う方法
// SampleDLL.cs
namespace SampleDLL
{
public class Class1
{
public static int Sum(int a, int b)
{
return a + b;
}
}
}
Visual C++のプロジェクト設定を開いて、[共通言語ランタイム サポート (/clr)]に変更する。
// SampleEXE.cpp
#include <Windows.h>
#include <iostream>
#using "SampleDLL.dll"
using namespace SampleDLL;
int main()
{
std::cout << Class1::Sum(1, 2) << std::endl;
return 0;
}
C# DLL側で関数をエクスポートする方法
まず、プロジェクトを作成してソースコードを記述する。
// SampleDLL.cs
namespace SampleDLL
{
public class Class1
{
[DllExport]
public static int Sum(int a, int b)
{
return a + b;
}
}
}
// SampleEXE.cpp
#include <Windows.h>
#include <iostream>
typedef int (*Sum)(int a, int b);
int main()
{
auto hModule = LoadLibrary(L"DllExportTest.dll");
auto sum = reinterpret_cast<Sum>(GetProcAddress(hModule, "Sum"));
std::cout << sum(1, 2) << std::endl;
return 0;
}
次に、DllExport.batをダウンロードして、DllExport.batをC# DLLのslnファイルと同じ階層に配置する。
続いて、コマンドプロンプトを開いて以下のコマンドを実行して、.NET DLLExportを起動する。
DllExport.bat -action Configure
.NET DLLExportダイアログにて、[Installed]チェックボックスにチェックを入力して、[Apply]ボタンを押下する。
最後に、C# DLLのプロジェクトをリビルドすると、作成した関数がエクスポートされる。
C++/CLIのラッパープロジェクトを使用する方法
まず、以下に示すソースコードのC# DLLを作成する。
// CSharpDLL.cs
namespace CSharpDLL
{
public static class CSharpDLLClass
{
public static void ShowValue(ref int value)
{
DialogResult result = MessageBox.Show("C# Message Box", "C# Message Box", MessageBoxButtons.OKCancel);
if (result == DialogResult.OK)
{
value = 1;
}
else
{
value = 2;
}
return;
}
}
}
次に、以下に示すようなソースコードのC++/CLI DLLを作成する。
その時、ソリューションエクスプローラからC++/CLIプロジェクトを右クリックして[参照の追加]を選択、上記で作成したC# DLLファイルを追加する。
また、Visual C++のプロジェクト設定を開いて、[構成プロパティ] - [全般] - [共通言語ランタイム サポート (/clr)]に変更する。
同様に、[構成プロパティ] - [C/C++] - [プリプロセッサ] - [プリプロセッサの定義]項目に、DLL
プリプロセッサを追加する。
// CppCLIDLL.cpp
#include "stdafx.h"
#include "CppCLIDLL.h"
using namespace System;
using namespace System::Reflection;
using namespace CSharpDLL;
namespace CppCLIDll
{
public ref class CppCLIClass
{
public:void ShowCSharpMessageBox(int *value)
{
CSharpDLLClass::ShowValue(*value);
return;
}
};
}
void ShowMessageBox(int *value)
{
CppCLIDll::CppCLIClass clsCLI;
clsCLI.ShowCSharpMessageBox(value);
}
// CppCLIDLL.h
#pragma once
#ifdef DLL
__declspec(dllexport) void ShowMessageBox(int *value);
#else
__declspec(dllimport) void ShowMessageBox(int *value);
#endif
最後に、以下に示すようなC++のソースコードのプロジェクトを作成する。
その時、メニューバーから[Visual C++のプロジェクト設定]を選択して、[構成プロパティ] - [C/C++] - [全般] - [追加のインクルードディレクトリ]項目に、
CppCLIDLL.hが存在するディレクトリを追加する。
同様に、[構成プロパティ] - [リンカー] - [全般] - [追加のライブラリディレクトリ]項目に、CppCLIDLL.libが存在するディレクトリを追加する。
さらに、[構成プロパティ] - [リンカー] - [入力] - [追加の依存ファイル]項目に、CppCLIDLL.libを追加する。
// CppEXE.cpp
#include "stdafx.h"
#include <windows.h>
#include "TestApp.h"
#include "CppCLI.h"
int _tmain()
{
int result = 0;
ShowMessageBox(&result);
if (result == 1)
{
printf("Ok Was Pressed \n");
printf("%d\n", result);
}
else if (result == 2)
{
printf("Cancel Was Pressed \n");
printf("%d\n", result);
}
else
{
printf("Unknown result \n");
}
system("pause");
return 0;
}
C# DLLをCOM参照可能にしてC++ EXEから使用する
まず、C# DLLプロジェクトを作成して、アセンブリ情報を設定する。
- C# DLLプロジェクトのプロパティを開く。
- プロパティ画面左にある[アプリケーション]タブを選択して、[アセンブリ情報]ボタンを押下する。
- [アセンブリをCOM参照可能にする]チェックボックスにチェックを入力して、[OK]ボタンを押下する。
次に、ビルドの設定を行う。
- C# DLLプロジェクトのプロパティを開く。
- プロパティ画面左にある[ビルド]タブを選択して、[COM相互運用機能の登録]チェックボックスにチェックを入力する。
- C# DLLプロジェクトのプロパティを保存する。
※注意1
[COM相互運用機能の登録]は、regasm
コマンドによるCOMのレジストリ登録を、ビルド時に自動で行う機能と思われる。
そのため、開発時(デバッグ時)は有効にした方が便利であるが、インストール時はCOMのレジストリ登録が自動で行われないため注意すること。
※注意2
Windowsにログインしているアカウントの権限によっては、ビルド時にレジストリへの登録に失敗するエラーが発生することがある。
その時は、Visual Studioを管理者権限で実行すれば登録できる。
C# DLLでは、以下のような内容のソースコードを記述する。
この時、C++ EXE側から呼ぶクラスには、以下の属性を付加する。
- ComVisible
- ClassInterface
- Guid (Visual Studioの[ツール]メニューバー - [GUIDの作成]を選択する)
// CSharpCOMDLL.csファイル
using System;
using System.Runtime.InteropServices;
namespace CSharpCOMDLL
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("85555B74-E2E0-4493-9869-3CE95F13CB99")] // Visual Studioの[ツール]メニューバー - [GUIDの作成]を選択する
public class CSharpCOMDLLClass
{
public Int32 Add(Int32 iParam1, Int32 iParam2)
{
int iRet = iParam1 + iParam2;
return (Int32)iRet;
}
public Int32 AddStr([MarshalAs(UnmanagedType.BStr)]string str) // 文字列を指定する場合はマーシャリングする
{
Console.WriteLine(str);
return (Int32)0;
}
}
}
C++ EXEプロジェクトを作成して、以下のような内容のソースコードを記述する。
// main.cppファイル
#include <iostream>
#include <Windows.h>
IDispatch *pIDisp = NULL;
IUnknown *pIUnk = NULL;
long Init(void);
long Finalize(void);
long AddInt(long p_Number1, long p_Number2);
long AddStr();
int main()
{
// COMの初期化処理
Init();
// C# DLLのメソッドを呼ぶ
int l_Result = Add(300, 500);
//後処理
Finalize();
printf("Calc Result : %d", l_Result);
return 0;
}
// 初期化関数
long Init(void)
{
// COMの初期化
::CoInitialize(NULL);
// ProcIDからCLSIDを取得(ネームスペース名.クラス名)
CLSID clsid;
HRESULT h_result = CLSIDFromProgID(L"CSharpCOMDLL.CSharpCOMDLLClass", &clsid); // 第1引数は、呼び出すC# DLLの<名前空間名>.<クラス名>にすること
if (FAILED(h_result))
{
return -1;
}
// インスタンスの生成
h_result = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pIUnk);
if (FAILED(h_result))
{
return -2;
}
// インターフェースの取得(pIDispは共通変数)
h_result = pIUnk->QueryInterface(IID_IDispatch, (void**)&pIDisp);
if (FAILED(h_result))
{
return -3;
}
return 0;
}
// COMの終了処理
long Finalize()
{
// インスタンスの開放
pIDisp->Release();
// インターフェイスの開放
pIUnk->Release();
// COMの開放
::CoUninitialize();
return 0;
}
// C# DLLのメソッドを呼ぶ
long AddInt(long p_Number1, long p_Number2)
{
// メソッド名からID(DISPID)を取得(関数名の設定)
DISPID dispid = 0;
OLECHAR *Func_Name[] = { SysAllocString (L"Add") }; // C# DLLの呼び出すメソッド名を指定する
HRESULT h_result = pIDisp->GetIDsOfNames(IID_NULL, Func_Name, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
if (FAILED(h_result))
{
return -1;
}
// メソッドに渡すパラメータを作成(DISPPARAMS、 VariantInit等)
DISPPARAMS params = {0};
params.cNamedArgs = 0;
params.rgdispidNamedArgs = NULL;
params.cArgs = 2; // 呼び出す関数の引数の数
// 引数の指定 (順番が逆になることに注意すること)
VARIANTARG* pVarg = new VARIANTARG[params.cArgs];
pVarg[0].vt = VT_I4;
pVarg[0].lVal = p_Number2;
pVarg[1].vt = VT_I4;
pVarg[1].lVal = p_Number1;
params.rgvarg = pVarg;
VARIANT vRet;
VariantInit(&vRet);
// C# DLLのメソッドを呼ぶ(pIDisp->Invoke)
pIDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, ¶ms, &vRet, NULL, NULL);
delete[] pVarg;
return vRet.lVal;
}
long AddStr()
{
// メソッド名からID(DISPID)を取得(関数名の設定)
DISPID dispid = 0;
OLECHAR *Func_Name[] = { SysAllocString (L"AddStr") };
HRESULT h_result = pIDisp->GetIDsOfNames(IID_NULL, Func_Name, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
if (FAILED(h_result))
{
return -1;
}
// メソッドに渡すパラメータを作成(DISPPARAMS、 VariantInit等)
DISPPARAMS params = {0};
params.cNamedArgs = 0;
params.rgdispidNamedArgs = NULL;
params.cArgs = 1; // 呼び出すメソッドの引数の数
// 引数の指定 (順番が逆になることに注意すること)
VARIANT var;
DISPPARAMS dispParams;
var.vt = VT_BSTR; // 引数に渡すデータ型をBSTRにする
var.bstrVal = SysAllocString(L"あいうえお"); // 引数に渡す文字列
dispParams.cArgs = 1;
dispParams.rgvarg = &var;
dispParams.cNamedArgs = 0;
dispParams.rgdispidNamedArgs = NULL;
VARIANT vRet;
VariantInit(&vRet);
// C# DLLのメソッドを呼ぶ(pIDisp->Invoke)
printf("[OK] Invoke start\r\n");
h_result = pIDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispParams, &vRet, NULL, NULL);
if (FAILED(h_result))
{
printf("[NG] Invoke failed\r\n");
return -2;
}
return vRet.lVal;
}
管理者権限でPowerShellまたはコマンドプロンプトを実行する。
次に、regasm
コマンドを使用して、C# DLL(COM)を登録する。
C# DLLのプラットフォーム(x86/x64)により、x86/x64向けのregasm
と合致させる必要があることに注意する。
また、regasm.exeをC++ EXE側のプロジェクトディレクトリにコピーして実行しても構わない。
# プロジェクトがx86の場合 C:\Windows\Microsoft.NET\Framework\<.NETのバージョン>\regasm /codebase <C# DLLのファイル名>.dll
# プロジェクトがx64の場合 C:\Windows\Microsoft.NET\Framework64\<.NETのバージョン>\regasm /codebase <C# DLLのファイル名>.dll
C++ EXEを実行する場合、以下の内容のバッチファイルを作成して、管理者権限で実行する。
常にregasm
コマンドを実行する場合、C# DLLプロジェクトの[COM相互運用機能の登録]の設定は不要である。
ただし、デバッグ時においては有効にした方が便利である。
rem exerun.batファイル
@echo off
cd %~dp0
regasm /codebase <C# DLLのファイル名>.dll
start /wait <C++ EXEのファイル名>.exe
echo exeからの戻り値は %ERRORLEVEL% です
pause
デバッグ
C++プロジェクトからC#プロジェクトに対するデバッグを有効にする手順を記載する。
- [ソリューションエクスプローラー]に表示されているC++プロジェクトを右クリックして、[プロパティ]を選択する。
- [<プロジェクト名> プロパティページ]画面にて、[構成プロパティ] - [デバッグ]を選択する。
- [デバッガーの種類]項目を、[混合]または[自動]に設定して、[OK]ボタンを押下する。