barus's diary

とても真面目なblogですにゃ

VC++本体から、コマンドライン(VC++)作成のDLL呼び出し、コッホ曲線 (第9回) for VS2015 Express

f:id:hatakeka:20160918185231p:plain

ファイルのメニュウ>DLL呼び出しテスト、コッホ曲線

 

f:id:hatakeka:20160918185414p:plain

にてDLL側に引数を渡して描画する。

 

 

今までは、int型やchar型をDLLと受け渡ししていたが、今回、

HWND hWnd, HDC hdcなどを受け渡し、DLL側で処理出来るか試してみた。

C#で(HWND)型の受け渡しをやろうとすると、

なんだか大変そうだったのでVC++でやることに・・・。

 

 

以下はそのやり方を記す。

 

 

 

 

 

空じゃない、Windowsのアプリケーションを作る。以下参照

VC++でグラフィック描画サンプルテスト (第7回) for VS2015 Express VC++ - barus's diary

 

フォルダ構成

f:id:hatakeka:20160918185615p:plain

 

同フォルダに、DLLファイル作成のフォルダ MyGrahicsを作成。

f:id:hatakeka:20160918185629p:plain

 

今回はDLL側をいじる。

 

コマンドライン(VC++)作成のDLL側

myGraphics.cpp

#include <windows.h>
#include <string.h>
#include <iostream>

 

#pragma comment(lib, "gdi32.lib")


#ifdef __cplusplus
#define DLLEXPORT extern "C" __declspec(dllexport)
#else
#define DLLEXPORT __declspec(dllexport)
#endif

using namespace std;

class MyPoint3D{
    public:
    int x;
    int y;
    int z;
    MyPoint3D::MyPoint3D( ){}
    MyPoint3D::MyPoint3D(int _x, int _y, int _z)
    {
    x = _x;
    y = _y;
    z = _z;
    }
};

 

void drawDragon_main(HDC hdc, int cnt);
void drawDragon(HDC hdc, MyPoint3D *a, MyPoint3D *b, int n);


//整数値を返す
DLLEXPORT int add(int a, int b) {
return a + b;
}

//文字列の参照値渡し
DLLEXPORT void test_str(char *str)
{
sprintf(str, "%sだにゃん♪", str);
}

 

//画像 ( Gdi32.lib User32.lib)
//CDCクラス使用
//https://msdn.microsoft.com/ja-jp/library/fxhhde73.aspx
DLLEXPORT void test_graphic(HWND hWnd, HDC hdc, int cnt) {

    HPEN hPen,hOldPen; 
    hPen= CreatePen(PS_SOLID,1,RGB(255,0,0)); // 幅5ピクセルの赤ペン
    hOldPen= (HPEN)SelectObject(hdc,hPen); // hPen を選択

     drawDragon_main(hdc, cnt);

     SelectObject(hdc,hOldPen); // hPen を戻す
     DeleteObject(hPen); // ペンを削除
}


//ドラゴン
void drawDragon_main(HDC hdc, int cnt)
{

      //出発点となる一対の点を指定します

      MyPoint3D *P = new MyPoint3D(170, 140, 0);
      MyPoint3D *Q = new MyPoint3D(400, 350, 0);

       //対となる二点の間にドラゴン曲線を描きます
       drawDragon(hdc, P, Q, cnt);

}

 

//ドラゴン曲線を描くメソッド
void drawDragon(HDC hdc, MyPoint3D *a, MyPoint3D *b, int n)
{
        MyPoint3D *c = new MyPoint3D();

        float xx, yy;
        xx = b->x - a->x;
        yy = -(b->y - a->y);

        c->x = a->x + (xx + yy) / 2;
        c->y = b->y + (xx + yy) / 2;

        POINT point[3] = { a->x, a->y, b->x, b->y, c->x, c->y };

        POINT *ppt = point;

        //最後なので、実際に線を引きます
       if (n <= 0)
       {
           Polyline(hdc, point, 1); //点Aから点Cへ
           Polyline(hdc, point, 2); //点Bから点Cへ
        }
       //最後ではないので、さらにメソッドを呼び出します(再帰処理)
       else
      {
           drawDragon(hdc, a, c, n - 1); //点Aから点Cへ
          drawDragon(hdc, b, c, n - 1); //点Bから点Cへ
      }
}

 

 

 

Polylineは、gdi32.dllを使用するので

 

#pragma comment(lib, "gdi32.lib")

 

を宣言している。 POINT型の配列が3になっていて、

実際は6個書かれているが、1つで2つとみなしているみたいだ。

 

POINT point[3] = { a->x, a->y, b->x, b->y, c->x, c->y };


Polyline(hdc, point, 1); //点Aから点Cへ
Polyline(hdc, point, 2); //点Bから点Cへ

 

Polylineは、0番目から、3番目の引数番目へラインを引く関数。

ここらへんが、C#と記述がちょっと違う。

 

これのコンパイルは以下。

ソース中で、Gdi32を利用することを宣言しているがコマンドラインでも

宣言していい。どちらかで宣言していればOKポイ。

cl myGraphics.cpp Gdi32.lib /LD /EHsc
copy /y myGraphics.dll ..\Debug
 

 

VC++本体側

 

www.fxpower.net

を流用する。

 

メニュウの「DLL呼び出しテスト、コッホ曲線」を追加する。

f:id:hatakeka:20160918185414p:plain

 

3DGraphic.rc ファイルの赤い部分を追加する。

 

以下の青い部分は前回の追加部分。

赤い部分が今回の追加部分。

黒いところは、自動生成でそのまま利用。

 

/////////////////////////////////////////////////////////////////////////////
//
// メニュー
//

IDC_MY3DGRAPHIC MENU
BEGIN
POPUP "ファイル(&F)"
BEGIN
MENUITEM "DLL呼び出しテスト、コッホ曲線(&X)", IDM_KOHO
MENUITEM "DLL呼び出しテスト(&X)", IDM_TEST
MENUITEM "アプリケーションの終了(&X)", IDM_EXIT
END
POPUP "ヘルプ(&H)"
BEGIN
MENUITEM "バージョン情報(&A)...", IDM_ABOUT
END

 

Resource.h 

以下の青い部分は前回の追加部分。

赤い部分が今回の追加部分。

黒いところは、自動生成でそのまま利用。


#define IDS_APP_TITLE 103

#define IDR_MAINFRAME 128
#define IDD_MY3DGRAPHIC_DIALOG 102
#define IDD_ABOUTBOX 103
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDI_MY3DGRAPHIC 107
#define IDI_SMALL 108
#define IDC_MY3DGRAPHIC 109
#define IDM_TEST 200
#define IDM_KOHO 201
#define IDC_MYICON 2
#ifndef IDC_STATIC
#define IDC_STATIC -1
#endif

 

3DGraphic.h 

以下の青い部分は前回の追加部分。

赤い部分が今回の追加部分。

黒いところは、自動生成でそのまま利用。

#pragma once

#include "resource.h"

#include <iostream>
using namespace std;

typedef int(*FUNC)(int x, int y);
typedef void(*FUNC2)(char *str);
typedef void(*test_graphic)(HWND hWnd, HDC hdc, int cnt);


static int paint_sw; //描画の切替フラグ
void dlltest(HWND hWnd, HDC hdc);
LPCWSTR StringToUnicode(string str); //string型からLPCWSTR型へ
void dlltest_koho(HWND hWnd, HDC hdc, int cnt); //DLLから描画テスト

 

 

 

 

 

3DGraphic.cpp

 

以下の青い部分は前回の追加部分。

赤い部分が今回の追加部分。

黒いところは、自動生成でそのまま利用。

 

// 3DGraphic.cpp : アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"
#include "3DGraphic.h"

#define MAX_LOADSTRING 100

// グローバル変数:
HINSTANCE hInst;                                // 現在のインターフェイス
WCHAR szTitle[MAX_LOADSTRING];                  // タイトル バーのテキスト
WCHAR szWindowClass[MAX_LOADSTRING];            // メイン ウィンドウ クラス名

// このコード モジュールに含まれる関数の宣言を転送します:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: ここにコードを挿入してください。

    // グローバル文字列を初期化しています。
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_MY3DGRAPHIC, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // アプリケーションの初期化を実行します:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MY3DGRAPHIC));

    MSG msg;

    // メイン メッセージ ループ:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}



//
//  関数: MyRegisterClass()
//
//  目的: ウィンドウ クラスを登録します。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MY3DGRAPHIC));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_MY3DGRAPHIC);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   関数: InitInstance(HINSTANCE, int)
//
//   目的: インスタンス ハンドルを保存して、メイン ウィンドウを作成します。
//
//   コメント:
//
//        この関数で、グローバル変数インスタンス ハンドルを保存し、
//        メイン プログラム ウィンドウを作成および表示します。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // グローバル変数インスタンス処理を格納します。

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);//Window を表示
   UpdateWindow(hWnd); //表示を初期化

   return TRUE;
}

//
//  関数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的:    メイン ウィンドウのメッセージを処理します。
//
//  WM_COMMAND  - アプリケーション メニューの処理
//  WM_PAINT    - メイン ウィンドウの描画
//  WM_DESTROY  - 中止メッセージを表示して戻る
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // 選択されたメニューの解析:
            switch (wmId)
            {
			
			//テスト
			case IDM_TEST:
				paint_sw = 1;
				InvalidateRect(hWnd, NULL, true); //画面全体に再描画を要求 false(上書き)
				break;
				//コッホ曲線
			case IDM_KOHO:
				paint_sw = 2;
				InvalidateRect(hWnd, NULL, true); //画面全体に再描画を要求 false(上書き)
				break;
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {

            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: HDC を使用する描画コードをここに追加してください...
			// ---- ここから 追加
			switch (paint_sw)
			{
			case 1:
				dlltest(hWnd, hdc);
				break;
			case 2:
				dlltest_koho(hWnd, hdc, 10);
				break;
			default:

				RECT rc;
				POINT aptPentagon[6] = { 50,2, 98,35, 79,90, 21,90, 2,35, 50,2 },
					aptHexagon[7] = { 50,2, 93,25, 93,75, 50,98, 7,75, 7,25, 50,2 };
				POINT *ppt = aptPentagon;
				int cpt = 6;

				GetClientRect(hWnd, &rc);
				SetMapMode(hdc, MM_ANISOTROPIC);
				SetWindowExtEx(hdc, 100, 100, NULL);
				SetViewportExtEx(hdc, rc.right, rc.bottom, NULL);
				Polyline(hdc, ppt, cpt);

				break;
			}

			// ---- ここまで

            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// バージョン情報ボックスのメッセージ ハンドラーです。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

void dlltest_koho(HWND hWnd, HDC hdc, int cnt)
{
	//DLLのパスを指定します。
	LPCWSTR lpBuffer = L"myGraphics.dll";
	HMODULE hModule = LoadLibrary(lpBuffer);
	if (NULL == hModule)
	{
		cout << "err LoadLibrary()" << endl;
		return;
	}

	//関数アドレスの取得
	test_graphic func = (test_graphic)GetProcAddress(hModule, "test_graphic");
	if (NULL == func)
	{
		cout << "err GetProcAddress()" << endl;
		return;
	}

	func(hWnd, hdc, cnt);

}

void dlltest(HWND hWnd, HDC hdc) {

	//DLLのパスを指定します。
	LPCWSTR lpBuffer = L"myGraphics.dll";
	HMODULE hModule = LoadLibrary(lpBuffer);
	if (NULL == hModule)
	{
		cout << "err LoadLibrary()" << endl;
		return;
	}

	//関数アドレスの取得
	FUNC func = (FUNC)GetProcAddress(hModule, "add");
	if (NULL == func)
	{
		cout << "err GetProcAddress()" << endl;
		return;
	}

	int ret;
	TCHAR wstr[1024];

	ret = func(1, 2);	
	wsprintf(wstr, L"add() = %d", ret);
    TextOutW(hdc, 100, 170, wstr, lstrlenW(wstr));

	
	
	//関数アドレスの取得
	FUNC2 func2 = (FUNC2)GetProcAddress(hModule, "test_str");
	if (NULL == func)
	{
		cout << "err GetProcAddress()" << endl;
		return;
	}
	
	char strdll[1024] = "\0";
	func2(strdll);
	
	string strd = strdll;
	string str = "DLL側の文字列は" + strd + "です。";
	LPCWSTR wstr2 = StringToUnicode(str);
	TextOutW(hdc, 100, 200, wstr2, lstrlenW(wstr2));

}


//マルチバイト文字列(Shift_JISEUC-JP)をワイド文字列(Unicode)に変換する
//string型からLPCWSTR型へ
LPCWSTR StringToUnicode(string str)
{

	wchar_t *wcs = new wchar_t[str.length() + 1];
	size_t ret;

	setlocale(LC_CTYPE, "jpn");

	//	mbstowcs_s(&ret, wcs, str.length() + 1, str.c_str(), _TRUNCATE);
	mbstowcs_s(&ret, wcs, str.length() + 1, str.c_str(), str.length());

	return wcs;
}

 

 

 

 

 

終わり。