【C#】C#からC言語のDLLの呼び出し&作成方法を詳しく説明します 第2回 【C#】【C/C++】【DLL】【初心者】【C# DLL呼び出し】

C#からC言語DLLの呼び出し方法 プログラム

第一部「プロジェクト作成&デバッグ方法の説明」の続き、第2部「HSV色変換DLLの作成」を説明していきます。

C#プロジェクトのプログラム実装、C言語のDLLプロジェクトのプログラム実装の順で説明していきます。

C#プロジェクトのプログラム実装

第一回で作成した「hsv_test」プロジェクトにプログラム実装をします。

表示用画像の準備

表示用画像はBMP画像をデバッグフォルダに準備します。

ここでは赤枠のBMPファイルをコピーしています。


実際に用意した画像はブログのアイコンを少し変更した300x300のBMP画像です。


フォームへコントロールの配置

フォームへ「pictureBox」を2つ、「trackBar」を1つ、「label」は元々のlabelを移動して配置します。

プロパティーのNameは張り付けたままの状態でOKです。


各種プロパティーの設定です。

「pictureBox1」、「pictureBox2」のプロパティー設定。
・SizeMode : Zoom

「label1」のプロパティー設定。
・AutoSize : false
・BorderStyle : FixedSingle
・TextAlign : MiddleCenter


プロパティーの設定後、タイマーの貼り付けを行い、「trackBar1」と「timer1」のコントロールをダブルクリックし、イベントを作成して下さい。

タイマーを配置後の画面はこの様になります。


Form1.csへプログラムの実装

先ずはプログラム全体です。(100行目以降は行数が表示されません)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace hsv_test
{
    public partial class Form1 : Form
    {
        private const string BMP_FILE_NAME = "test_image.bmp";          //画像ファイル名

        private bool image_flash_flag;                                  //画像更新フラグ
        private byte[] img_bs;                                          //ベース画像バッファ
        private System.Drawing.Bitmap bmp_bf_bs;                        //ベース画像BMP
        private System.Drawing.Bitmap bmp_bf_change;                    //カラー変更画像BMP

        public Form1()
        {
            InitializeComponent();
        }

        //フォームロード
        private void Form1_Load(object sender, EventArgs e)
        {
            string fname;

            fname = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + BMP_FILE_NAME;
            image_flash_flag = true;

            //画像読み込み
            using (FileStream fs = new FileStream(fname, FileMode.Open, FileAccess.Read))
            {
                img_bs = new byte[fs.Length];
                fs.Read(img_bs, 0, img_bs.Length);
            }

            //jpeg画像またはpng画像を読み込む場合はコメントアウトの4行を使用する
            //Bitmap tmp = new Bitmap(AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "jpeg or png FileName");
            //MemoryStream tms = new MemoryStream();
            //tmp.Save(tms,System.Drawing.Imaging.ImageFormat.Bmp);
            //img_bs = tms.ToArray();

            //pictureBox1に画像をセット
            MemoryStream ms = new MemoryStream(img_bs);
            bmp_bf_bs = new Bitmap(ms);
            ms.Close();
            ms = null;
            pictureBox1.Image = bmp_bf_bs;

            label1.Text = "0";
            trackBar1.Maximum = 359;

            timer1.Interval = 1000 / 60;
            timer1.Start();
        }

        //タイマーイベント
        private void timer1_Tick(object sender, EventArgs e)
        {
            timer1.Enabled = false;

            if (image_flash_flag)
            {
                image_flash_flag = false;

                //HSV色変換
                Dll_Import.HSV_ChangeColor_Wk wk;

                wk.angle = (UInt16)trackBar1.Value;
                wk.src_bmp_ptr = img_bs;
                wk.dst_bmp_ptr = new byte[0];
                Dll_Import.HSV_ChangeColor(ref wk);

                //HSV色変換画像の更新
                if (wk.dst_bmp_ptr.Length != 0)
                {
                    //古い画像の破棄
                    if (bmp_bf_change != null)
                    {
                        bmp_bf_change.Dispose();
                        bmp_bf_change = null;
                        pictureBox2.Image = null;
                    }

                    //新しい画像のセット
                    MemoryStream ms = new MemoryStream(wk.dst_bmp_ptr);
                    bmp_bf_change = new Bitmap(ms);
                    ms.Close();
                    ms = null;
                    pictureBox2.Image = bmp_bf_change;
                }
            }
            timer1.Enabled = true;
        }

        //トラックバースクロールイベント
        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            if (img_bs != null)
            {
                label1.Text = ((TrackBar)sender).Value.ToString();
                image_flash_flag = true;
            }
        }
    }
}


フォームロードではBMP画像の読み込み等を行っています。

使用する画像をjpegやpngにしたい場合は44行から47行のコメントアウトを外してプログラムを有効にして下さい。

タイマーイベントでは画面の更新フラグのセット時に、画像のHSV色変換を行い表示をしています。

トラックバースクロールイベントではHSV色変換用の角度の表示と画面の更新フラグのセットを行っています。


ここでプログラムを実行して、このような画面が表示されればOKです。


DLLプロジェクトのプログラム実装

前回作成した「msf_util」プロジェクトにプログラム実装をします。

「malloc_ex」、「m_util」、「HSV_ChangeColor」の順で作成します。

malloc_exの作成

malloc_exはメモリーリークを防ぐためのクラスとなります。

mallocでカウントアップ、freeでカウントダウンをする単純なプログラムです。

全ての処理の終了時にこのカウントが0ならば、メモリーリークは発生しないという事になります。

「malloc_ex.h」の記述です。

#include <Windows.h>

#pragma once

typedef struct {
    BOOL use;                                       // 使用フラグ
    void* adr;                                      // 確保アドレス
    INT16 count;                                    // カウンター
}	M_Dic_St;

ref class malloc_ex
{
public:
    static const int M_DIC_MAX = 30;                // バッファ確保数

    INT16 malloc_count;                             // メモリー確保数
    M_Dic_St* m_dic_buff;                           // 使用状況

    //----- プロトタイプ -----
    void* ex_malloc(LONG sz);                       // メモリー確保
    void ex_free(void* ptr);                        // メモリー解放
    INT16 get_count();

    malloc_ex();                                    // コンストラクター
    ~malloc_ex();                                   // デストラクター
};


続いて、「malloc_ex.cpp」の記述です。

#include "pch.h"
#include <malloc.h>
#include "malloc_ex.h"

//****************************************************************************************************************
//*
//* void *malloc_ex::ex_malloc(LONG sz)
//*
//* メモリー確保
//*
//* in.		LONG					sz										確保サイズ
//*
//* out.	void *															メモリーアドレス
//*
//****************************************************************************************************************
void* malloc_ex::ex_malloc(LONG sz)
{
    void* ptr;

    ptr = malloc(sz);
    if (ptr != NULL) {
        malloc_count++;

        int		i;
        M_Dic_St* tmp = m_dic_buff;
        for (i = 0; i < M_DIC_MAX; i++) {
            if (tmp->use == FALSE) {
                tmp->use = TRUE;
                tmp->adr = ptr;
                tmp->count = malloc_count;
                break;
            }
            tmp++;
        }
    }

    return ptr;
}

//****************************************************************************************************************
//*
//* void malloc_ex::ex_free(void *ptr)
//*
//* メモリー解放
//*
//* in.		void					*ptr									mallocポインタ
//*
//* out.	なし
//*
//****************************************************************************************************************
void malloc_ex::ex_free(void* ptr)
{
    int		i;

    M_Dic_St* tmp = m_dic_buff;
    for (i = 0; i < M_DIC_MAX; i++) {
        if (tmp->use == TRUE && tmp->adr == ptr) {
            tmp->use = FALSE;
            tmp->adr = NULL;
            tmp->count = 0;
            break;
        }
        tmp++;
    }
    free(ptr);
    malloc_count--;
}

//****************************************************************************************************************
//*
//* INT16 malloc_ex::get_count()
//*
//* メモリー確保数を返す
//*
//* in.		なし
//*
//* out.	INT16															メモリー確保数
//*
//****************************************************************************************************************
INT16 malloc_ex::get_count()
{
    return malloc_count;
}

//----- コンストラクター -----
malloc_ex::malloc_ex()
{
    malloc_count = 0;

    m_dic_buff = (M_Dic_St*)malloc(sizeof(M_Dic_St) * M_DIC_MAX);

    if (m_dic_buff != NULL) {
        memset(m_dic_buff, 0, _msize(m_dic_buff));
    }
}

//----- デストラクター -----
malloc_ex::~malloc_ex()
{
    free(m_dic_buff);
}

malloc_ex::ex_malloc(LONG sz)がメモリーの確保。

malloc_ex::ex_free(void* ptr)がメモリーの解放。

malloc_ex::get_count()がメモリーの確保回数。


m_utilの作成

m_utilはHSV色変換用のユーティリティープログラムです。

「m_util.h」の記述です。

#pragma once

#include <windows.h>
#include "malloc_ex.h"

//------------------------------------------------------------------------------------------------------------------------------
//構造体定義
//------------------------------------------------------------------------------------------------------------------------------
//HSV構造体
typedef struct
{
    UINT16 h;                                           // 色相 0 - 360度
    double s;                                           // 彩度 0.0 - 1.0
    UINT16 v;                                           // 明度 0-255
}	Hsv;

//----- Color MAP 定義用構造体 -----
typedef struct {
    //----- 入力用メンバー -----
    RGBTRIPLE* data_ptr;                                // RGB DATA pointer
    INT32 x_size;                                       // X Size
    INT32 y_size;                                       // Y Size
    INT16 h_range;                                      // 許容色相レンジ± 0-179 基本は0-60までの範囲

    //----- 出力用メンバー(選択可能カラーのインデックスに1が入る) -----
    BYTE* map_r;                                        // R Color Map 256Byteを確保したポインタを入れる
    BYTE* map_g;                                        // G Color Map 256Byteを確保したポインタを入れる
    BYTE* map_b;                                        // B Color Map 256Byteを確保したポインタを入れる

}Color_Map_Work;

#define	COLOR_MAP_SIZE 256                              // カラーマップサイズ(1チャンネル分)

//------------------------------------------------------------------------------------------------------------------------------
//prototype
//------------------------------------------------------------------------------------------------------------------------------
void rgb_2_hsv(RGBTRIPLE* rgb_ptr, Hsv* hsv_ptr);									// RGB → HSV 変換
void hsv_2_rgb(Hsv* hsv_ptr, RGBTRIPLE* rgb_ptr);									// HSV → RGB 変換
UINT8* reverse_image(UINT8* ptr, malloc_ex^ malloc_ptr, BOOL free_flag = TRUE);		// BMPの反転
UINT8* mk_bmp_buffer(INT32 sx, INT32 sy, INT32 color, malloc_ex^ malloc_ptr);		// BMPバッファ生成


続いて「m_util.cpp」の記述です。

#include "pch.h"
#include <math.h>

#include "m_util.h"

//*************************************************************************************
//
// RGB → HSV変換
//
// rgb_2_hsv()
// in:	RGBTRIPLE		*rgb_ptr				BMP DATA Pointer(B,G,Rの順)
//		Hsv				*hsv_ptr				HSV DATA Pointer(HSVデータが入る)
//
// out:	なし
//
//*************************************************************************************
void rgb_2_hsv(RGBTRIPLE* rgb_ptr, Hsv* hsv_ptr)
{
    INT16				c_max, c_min, c_code;
    double				ans_d, ans, cal_r, cal_g, cal_b;

    hsv_ptr->h = 0;
    hsv_ptr->s = 0;
    hsv_ptr->v = 0;
    c_code = 0;
    c_max = rgb_ptr->rgbtRed;
    c_min = c_max;
    if (c_max < rgb_ptr->rgbtGreen) {
        c_max = rgb_ptr->rgbtGreen;
        c_code = 1;
    }
    if (c_max < rgb_ptr->rgbtBlue) {
        c_max = rgb_ptr->rgbtBlue;
        c_code = 2;
    }
    if (c_min > rgb_ptr->rgbtGreen) {
        c_min = rgb_ptr->rgbtGreen;
    }
    if (c_min > rgb_ptr->rgbtBlue) {
        c_min = rgb_ptr->rgbtBlue;
    }

    if (c_max > 0) {
        hsv_ptr->v = c_max;
        ans_d = (double)(c_max - c_min);
        hsv_ptr->s = (double)ans_d / (double)c_max;
        cal_r = (double)(c_max - rgb_ptr->rgbtRed) / ans_d;
        cal_g = (double)(c_max - rgb_ptr->rgbtGreen) / ans_d;
        cal_b = (double)(c_max - rgb_ptr->rgbtBlue) / ans_d;
        switch (c_code)
        {
        case 0:
            ans = 6 + cal_b - cal_g;
            break;
        case 1:
            ans = 6 + 2 + cal_r - cal_b;
            break;
        case 2:
            ans = 6 + 4 + cal_g - cal_r;
            break;
        }
        hsv_ptr->h = (UINT16)fmod(((ans * 60.0) + 0.5), 360);
    }

}

//*************************************************************************************
//
// HSV → RGB変換
//
// hsv_2_rgb()
// in:	Hsv				*hsv_ptr				HSV DATA Pointer
//		RGBTRIPLE		*rgb_ptr				BMP DATA Pointer(RGBデータが入る B,G,Rの順)
//
// out:	なし
//
//*************************************************************************************
void hsv_2_rgb(Hsv* hsv_ptr, RGBTRIPLE* rgb_ptr)
{
    INT16	tmp_i, tmp_m, tmp_n, tmp_k;
    double	tmp_f;

    if (hsv_ptr->s == 0.0) {
        rgb_ptr->rgbtRed = rgb_ptr->rgbtGreen = rgb_ptr->rgbtBlue = (UINT8)hsv_ptr->v;
    }
    else {
        tmp_i = (INT16)floor((double)hsv_ptr->h / 60.0);
        tmp_f = (double)hsv_ptr->h / 60.0 - tmp_i;
        tmp_m = (INT16)((double)hsv_ptr->v * (1.0 - hsv_ptr->s / 1.0));
        tmp_n = (INT16)((double)hsv_ptr->v * (1.0 - (hsv_ptr->s / 1.0) * (double)tmp_f) + 0.5);
        tmp_k = (INT16)((double)hsv_ptr->v * (1.0 - (hsv_ptr->s / 1.0) * (1.0 - (double)tmp_f)) + 0.5);

        switch (tmp_i) {
        case 0:
            rgb_ptr->rgbtRed = (BYTE)hsv_ptr->v;
            rgb_ptr->rgbtGreen = (BYTE)tmp_k;
            rgb_ptr->rgbtBlue = (BYTE)tmp_m;
            break;

        case 1:
            rgb_ptr->rgbtRed = (BYTE)tmp_n;
            rgb_ptr->rgbtGreen = (BYTE)hsv_ptr->v;
            rgb_ptr->rgbtBlue = (BYTE)tmp_m;
            break;

        case 2:
            rgb_ptr->rgbtRed = (BYTE)tmp_m;
            rgb_ptr->rgbtGreen = (BYTE)hsv_ptr->v;
            rgb_ptr->rgbtBlue = (BYTE)tmp_k;
            break;

        case 3:
            rgb_ptr->rgbtRed = (BYTE)tmp_m;
            rgb_ptr->rgbtGreen = (BYTE)tmp_n;
            rgb_ptr->rgbtBlue = (BYTE)hsv_ptr->v;
            break;

        case 4:
            rgb_ptr->rgbtRed = (BYTE)tmp_k;
            rgb_ptr->rgbtGreen = (BYTE)tmp_m;
            rgb_ptr->rgbtBlue = (BYTE)hsv_ptr->v;
            break;

        case 5:
            rgb_ptr->rgbtRed = (BYTE)hsv_ptr->v;
            rgb_ptr->rgbtGreen = (BYTE)tmp_m;
            rgb_ptr->rgbtBlue = (BYTE)tmp_n;
            break;
        }
    }
}

//****************************************************************************************************************
//*
//* UINT8 *reverse_image(UINT8 *ptr, malloc_ex ^malloc_ptr, BOOL free_flag)
//*
//* BMP画像の上下反転(free_flag=FALSEの場合、元のバッファは開放)
//*
//* in.		UINT8							*ptr							BMPデータポインタ
//*			malloc_ex						^malloc_ptr						メモリ確保クラスポインタ
//*			BOOL							free_flag						元バッファ解放フラグ デフォルト=TRUE
//*
//* out.	UINT8 *															上下反転BMPバッファポインタ
//*
//****************************************************************************************************************
UINT8* reverse_image(UINT8* ptr, malloc_ex^ malloc_ptr, BOOL free_flag)
{
    BITMAPFILEHEADER* bmp_file_header;
    BITMAPINFOHEADER* bmp_info_header;
    DWORD				x_line_size;
    WORD				rgb_size;
    UINT8* new_bmp_ptr, * set_ptr, * data_ptr;
    INT32				i;


    bmp_file_header = (BITMAPFILEHEADER*)ptr;
    bmp_info_header = (BITMAPINFOHEADER*)(ptr + sizeof(BITMAPFILEHEADER));
    rgb_size = bmp_info_header->biBitCount / 8;

    x_line_size = bmp_info_header->biWidth * rgb_size;
    if ((x_line_size & 3) != 0) {
        x_line_size = ((x_line_size + 4) & -4);
    }

    new_bmp_ptr = mk_bmp_buffer(bmp_info_header->biWidth, bmp_info_header->biHeight, rgb_size, malloc_ptr);
    set_ptr = new_bmp_ptr + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    data_ptr = ptr + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    if (rgb_size == 1) {
        data_ptr += sizeof(RGBQUAD) * 256;									// パレット分進める
        set_ptr += sizeof(RGBQUAD) * 256;									// パレット分進める
    }

    for (i = bmp_info_header->biHeight - 1; i >= 0; i--) {
        UINT8* tmp_ptr;

        tmp_ptr = data_ptr + x_line_size * i;
        memcpy_s(set_ptr, x_line_size, tmp_ptr, x_line_size);
        set_ptr += x_line_size;
    }

    if (free_flag == TRUE) {
        malloc_ptr->ex_free(ptr);
    }

    return new_bmp_ptr;
}

//****************************************************************************************************************
//*
//* UINT8 *mk_bmp_buffer(INT32 sx,INT32 sy,INT32 color, malloc_ex ^malloc_ptr)
//*
//* BMPバッファの作成
//*
//* in.		INT32							sx								x size
//*			INT32							sy								y size
//*			INT32							color							color size (8BitColor = 1 , 24Bitcolor = 3 , 32Bitcolor = 4)
//*			malloc_ex						^malloc_ptr						メモリ確保クラスポインタ
//*
//* out.	UINT8 *															BMPバッファポインタ
//*
//****************************************************************************************************************
UINT8* mk_bmp_buffer(INT32 sx, INT32 sy, INT32 color, malloc_ex^ malloc_ptr)
{
    UINT8* bmp_buff, * set_ptr;
    DWORD	bmp_fheader_size, bmp_iheader_size, bmp_total_size, image_offset;
    LONG	x_line_size;
    UINT32	i;

    bmp_fheader_size = sizeof(BITMAPFILEHEADER);
    bmp_iheader_size = sizeof(BITMAPINFOHEADER);
    image_offset = bmp_fheader_size + bmp_iheader_size;

    //----- x sizeを4の倍数にする -----
    x_line_size = sx * color;
    if ((x_line_size & 3) != 0) {
        x_line_size = ((x_line_size + 4) & -4);
    }

    bmp_total_size = bmp_fheader_size + bmp_iheader_size + x_line_size * sy;
    if (color == 1) {
        bmp_total_size += sizeof(RGBQUAD) * 256;
        image_offset += sizeof(RGBQUAD) * 256;
    }
    bmp_buff = (UINT8*)malloc_ptr->ex_malloc(bmp_total_size);
    memset(bmp_buff, 0, bmp_total_size);

    set_ptr = bmp_buff;
    *set_ptr++ = 'B';
    *set_ptr++ = 'M';

    *set_ptr++ = (unsigned char)(bmp_total_size);						// file size
    *set_ptr++ = (unsigned char)(bmp_total_size >> 8);
    *set_ptr++ = (unsigned char)(bmp_total_size >> 16);
    *set_ptr++ = (unsigned char)(bmp_total_size >> 24);

    *set_ptr++ = 0;														// 予約 1,2
    *set_ptr++ = 0;
    *set_ptr++ = 0;
    *set_ptr++ = 0;

    *set_ptr++ = (unsigned char)(image_offset);							// file size
    *set_ptr++ = (unsigned char)(image_offset >> 8);
    *set_ptr++ = (unsigned char)(image_offset >> 16);
    *set_ptr++ = (unsigned char)(image_offset >> 24);

    //----- BMP INFO HEADER セット -----
    *set_ptr++ = (unsigned char)(bmp_iheader_size);						// info header size
    *set_ptr++ = (unsigned char)(bmp_iheader_size >> 8);
    *set_ptr++ = (unsigned char)(bmp_iheader_size >> 16);
    *set_ptr++ = (unsigned char)(bmp_iheader_size >> 24);

    *set_ptr++ = (unsigned char)(sx);									// x size
    *set_ptr++ = (unsigned char)(sx >> 8);
    *set_ptr++ = (unsigned char)(sx >> 16);
    *set_ptr++ = (unsigned char)(sx >> 24);

    *set_ptr++ = (unsigned char)(sy);									// y size
    *set_ptr++ = (unsigned char)(sy >> 8);
    *set_ptr++ = (unsigned char)(sy >> 16);
    *set_ptr++ = (unsigned char)(sy >> 24);

    *set_ptr++ = (unsigned char)(1);									// プレーン数 1
    *set_ptr++ = (unsigned char)(0);

    *set_ptr++ = (unsigned char)(color * 8);								// 1画素のビット数
    *set_ptr++ = (unsigned char)(0);

    *set_ptr++ = 0;														// 圧縮タイプ
    *set_ptr++ = 0;
    *set_ptr++ = 0;
    *set_ptr++ = 0;

    *set_ptr++ = (unsigned char)(x_line_size * sy);						// 画像データサイズ
    *set_ptr++ = (unsigned char)((x_line_size * sy) >> 8);
    *set_ptr++ = (unsigned char)((x_line_size * sy) >> 16);
    *set_ptr++ = (unsigned char)((x_line_size * sy) >> 24);

    *set_ptr++ = 0;														// 水平解像度
    *set_ptr++ = 0;
    *set_ptr++ = 0;
    *set_ptr++ = 0;

    *set_ptr++ = 0;														// 垂直解像度
    *set_ptr++ = 0;
    *set_ptr++ = 0;
    *set_ptr++ = 0;

    if (color == 1) {
        *set_ptr++ = 0;													// カラーパレット index数
        *set_ptr++ = 1;
        *set_ptr++ = 0;
        *set_ptr++ = 0;
    }
    else {
        *set_ptr++ = 0;													// カラーパレット index数
        *set_ptr++ = 0;
        *set_ptr++ = 0;
        *set_ptr++ = 0;
    }

    *set_ptr++ = 0;														// 重要 index数
    *set_ptr++ = 0;
    *set_ptr++ = 0;
    *set_ptr++ = 0;

    if (color == 1) {
        for (i = 0; i < 256; i++) {
            *set_ptr++ = i;												// カラーパレット
            *set_ptr++ = i;
            *set_ptr++ = i;
            *set_ptr++ = i;
        }
    }

    return bmp_buff;
}

void rgb_2_hsv(RGBTRIPLE* rgb_ptr, Hsv* hsv_ptr)がRGB → HSV変換。

void hsv_2_rgb(Hsv* hsv_ptr, RGBTRIPLE* rgb_ptr)がHSV → RGB変換。

UINT8* reverse_image(UINT8* ptr, malloc_ex^ malloc_ptr, BOOL free_flag)がBMP画像の上下反転。

UINT8* mk_bmp_buffer(INT32 sx, INT32 sy, INT32 color, malloc_ex^ malloc_ptr)がBMPデータバッファ作成。


HSV_ChangeColorの作成

HSV_ChangeColorは実際にC#から呼び出される関数になります。

「HSV_ChangeColor.h」の記述です。

#pragma once

#include <windows.h>
#include "m_util.h"

//----- HSV_ChangeColor()引き数の構造体 -----
typedef struct {
    WORD angle;                             //HSV 変換角度
    void* src_bmp_ptr;                      //source BMP ポインター
    void* byte_buff;                        //HSV変換済みデータ ポインター
} HSV_VhangeColor_Wk;

INT16 HSV_ChangeColor(HSV_VhangeColor_Wk* in_ptr);


続いて「HSV_ChangeColor.cpp」の記述です。

#include "pch.h"
#include <windows.h>
#include <OAIdl.h>

#include "HSV_ChangeColor.h"
#include "malloc_ex.h"

//************************************************
//*
//* INT16 HSV_ChangeColor(HSV_ChangeColor_Wk *in_ptr)
//*
//* HSV色変換を行う
//*
//* in.		HSV_ChangeColor_Wk	*in_ptr							画像変換ワークポインター
//*
//* out.	INT16												0=成功 : 1=失敗
//*
//************************************************

INT16 HSV_ChangeColor(HSV_VhangeColor_Wk* in_ptr)
{
    malloc_ex^ malloc_ex_ptr;
    SAFEARRAY* src_buff_ptr, * byte_buff_ptr;
    DWORD bmp_fheader_size, bmp_iheader_size, bmp_total_size, image_offset;
    UINT8* src_bmp_ptr, * byte_bmp_ptr;
    SAFEARRAYBOUND rgsabound[1];
    HRESULT hr;
    unsigned char* buff_ptr = NULL;
    DWORD bmp_sx, bmp_sy;
    BITMAPINFOHEADER* info_header_ptr;
    DWORD x_line_size1;
    LONG i, j;
    RGBTRIPLE* data_ptr1, * data_ptr2;
    Hsv hsv_dt;

    malloc_ex_ptr = gcnew malloc_ex;
    src_buff_ptr = (SAFEARRAY*)in_ptr->src_bmp_ptr;
    byte_buff_ptr = (SAFEARRAY*)in_ptr->byte_buff;

    bmp_fheader_size = sizeof(BITMAPFILEHEADER);
    bmp_iheader_size = sizeof(BITMAPINFOHEADER);
    image_offset = bmp_fheader_size + bmp_iheader_size;

    //----- 加工用BMPをコピー -----
    src_bmp_ptr = reverse_image((UINT8*)src_buff_ptr->pvData, malloc_ex_ptr, FALSE);

    //----- BMPデータ生成 -----
    info_header_ptr = (BITMAPINFOHEADER*)(src_bmp_ptr + bmp_fheader_size);
    bmp_sx = info_header_ptr->biWidth;
    bmp_sy = info_header_ptr->biHeight;

    //----- x sizeを4の倍数にする -----
    x_line_size1 = bmp_sx * sizeof(RGBTRIPLE);
    if ((bmp_sx & 3) != 0) {
        x_line_size1 = ((x_line_size1 + 4) & -4);                   // 24Bit Color
    }

    bmp_total_size = bmp_fheader_size + bmp_iheader_size + x_line_size1 * bmp_sy;

    //----- カラー変更バッファの作成 -----
    byte_bmp_ptr = (UINT8*)malloc_ex_ptr->ex_malloc((LONG)_msize(src_bmp_ptr));
    memcpy_s(byte_bmp_ptr, _msize(src_bmp_ptr), src_bmp_ptr, _msize(src_bmp_ptr));

    //----- カラー変更 -----
    //B,G,R 24Bit Color
    data_ptr1 = (RGBTRIPLE*)(src_bmp_ptr + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));
    data_ptr2 = (RGBTRIPLE*)(byte_bmp_ptr + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));

    RGBTRIPLE* ptr1;
    RGBTRIPLE* ptr2;

    for (i = 0; i < info_header_ptr->biHeight; i++) {
        ptr1 = (RGBTRIPLE*)((UINT8*)(data_ptr1)+(x_line_size1 * i));
        ptr2 = (RGBTRIPLE*)((UINT8*)(data_ptr2)+(x_line_size1 * i));
        for (j = 0; j < info_header_ptr->biWidth; j++) {
            rgb_2_hsv(ptr1, &hsv_dt);

            hsv_dt.h = (hsv_dt.h + in_ptr->angle) % 360;

            hsv_2_rgb(&hsv_dt, ptr2);

            ptr1++;
            ptr2++;
        }
    }

    //----- 編集バッファをSAFEARRAYにコピー -----
    byte_bmp_ptr = reverse_image(byte_bmp_ptr, malloc_ex_ptr);

    //----- SAFEARRAYのサイズ変更 -----
    rgsabound[0].cElements = bmp_total_size;                            // 配列サイズ
    rgsabound[0].lLbound = 0;                                           // 先頭 index
    hr = SafeArrayRedim(byte_buff_ptr, rgsabound);

    //----- 配列の先頭ポインタを取得(ロックされる) -----
    hr = SafeArrayAccessData(byte_buff_ptr, (void**)&buff_ptr);

    memcpy_s(buff_ptr, bmp_total_size, byte_bmp_ptr, bmp_total_size);

    //----- 配列のアンロック -----
    SafeArrayUnlock(byte_buff_ptr);

    malloc_ex_ptr->ex_free(byte_bmp_ptr);
    malloc_ex_ptr->ex_free(src_bmp_ptr);

    int cnt = malloc_ex_ptr->get_count();
    delete malloc_ex_ptr;
    return 0;
}

ポイントとしてはC#から渡された配列(マネージド配列)をC言語のDLLで処理をする場合は「SAFEARRAY」ポインターで処理を行う事です。

また、加工したデータを格納する配列はサイズが0バイトの配列をC#側から渡すようにします。

C#側で作成した配列のリサイズも可能だと思いますが、メモリーリークが絶対に起きないという確証が持てないので、0バイト配列で処理をするのが安全だと考えます。

実行してみましょう。

角度を100にした状態で、左側がHSV色変換後の画像となります。


角度を200にした状態です。


プログラムの難易度的にはそれほど高くありませんので、試してみて下さい。

「SAFEARRAY」を使用する事で配列の操作なら何でもできます。

C#で大きな配列でデータ加工を行うのは速度的に遅すぎますので、C言語のDLLで処理をするのもありだと思います。

それではまた。


コメント

タイトルとURLをコピーしました