Mesoscopic Programming

タコさんプログラミング専門

子ウィンドウをポップアップウィンドウに変更するには?

やっと分かったぞ!
せっかく調べたのでその方法を公開します。
ポップアップウィンドウを作るとき、
CreateWindow関数だと超簡単に親ウィンドウ(=オーナーウィンドウ)を設定できるけど、
子ウィンドウからポップアップウィンドウに変更するとなると
そう簡単には行かないのだった(分かってしまえば簡単だけど)。

// hWnd    子ウィンドウまたはポップアップウィンドウハンドル
// hParent 親ウィンドウハンドル

//-----------------------------------------------------------------------------
// 子ウィンドウをポップアップウィンドウに変更する

// 親ウィンドウをクリアする
::SetParent( hWnd, nullptr );

// ウィンドウスタイルを設定する
::SetWindowLongPtrW( hWnd, GWL_STYLE, static_cast< LONG_PTR >( WS_POPUP ) );

// オーナーウィンドウを設定する
::SetWindowLongPtrW( hWnd, GWLP_HWNDPARENT, reinterpret_cast< LONG_PTR >( hParent ) );

//-----------------------------------------------------------------------------
// ポップアップウィンドウを子ウィンドウに変更する

// ウィンドウスタイルを設定する
::SetWindowLongPtrW( hWnd, GWL_STYLE, static_cast< LONG_PTR >( WS_CHILD ) ) );

// 親ウィンドウを設定する
::SetParent( hWnd, hParent );
解説

要はSetWindowLong関数の部分ですにゃ。
※64ビットのユニコード用なのでSetWindowLongPtrW関数を使っているけども。
これがなかなか見つからなかった。
だってSetParent関数だと思うじゃん、普通。
ところがSetParent関数だと、ウィンドウが消えちゃうじゃん!
これが違うかったんだにゃ。
これで2日ほど悩んだっぺした。
分かってスッキリしたべ。
以上です。

2018/11/5
更新テスト。

VusualStudio 2015 のテキストエディタのここが嫌いだ!

誰が設計してるんだか。
このテキストエディタは。
昔のVisualStudioはこんなじゃなかったのに。
せめてオプションで機能を禁止できるようにして欲しいものだ。
この余計な機能を。
Googleで調べても禁止する方法が分からなかった。
検索ボックスに文字を入力してる途中で勝手にジャンプしてしまう余計な機能のことだ。
作業者の視線はいま検索ボックスにあるのだから、
テキストのカーソル位置は以前の場所にあると思い込んでいるのに、
検索を途中でやめて文字を入力すると、
まったくでたらめな場所に文字が入力されてしまうのだ。
こんな馬鹿な機能を考えたのはいったいどこのどいつだ。
責任者を呼んで来い!
こんなにも余計な機能なのに、
オプションで禁止できないってどういうことだ。
ほかにもたくさん余計な機能があるけど、
大体はオプションで機能を禁止できるのに。
本当に腹が立つ。
作業効率が悪くなってしょうがない。
それになんといっても重過ぎる。
インテリセンスのせいであることは分かっているが、
インテリセンスを完全に切るのは忍びない。
もっと軽いテキストエディタの統合環境が欲しい。
オプションでもっと軽いテキストエディタが選べるといいのに。
文句を言ったらスッキリした。
VisualStudio 2020くらいで改良されることを期待しよう!

プロセス関係の関数を作った

プロセス関係の関数を作ったので置いておきます。
マルチプロセスのプログラムをデバッグしていると、
自分以外のプロセスを殺したくなりますよね。
いちいち手作業で殺すのはめんどくさいので、
自動で殺すためのお助け関数を作りました。
これでプロセス識別子からハンドルをゲットして、
ターミネートしてやれば自動で殺せますよね。

親プロセス識別子取得関数
    //-------------------------------------------------------------------------
    /// 親プロセス識別子取得関数
    ///
    /// 親プロセス識別子取得関数です。
    ///
    /// @param[in] value プロセス識別子
    /// @return    プロセス識別子
    /// @attention なし
    ///
    DWORD GetParentProcess( DWORD value ) {
        // 実行結果を初期化する
        DWORD result = 0;

        // プロセススナップショットを作成する
        HANDLE snap = ::CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
        if ( nullptr != snap ) {
            // 最初のプロセス情報を取得する
            PROCESSENTRY32 pe;
            pe.dwSize = sizeof( PROCESSENTRY32 );
            BOOL result2 = ::Process32First( snap, &pe );

            // プロセス情報を巡回する
            while ( TRUE == result2 ) {
                // プロセス識別子を調べる
                if ( value == pe.th32ProcessID ) {
                    // 親プロセス識別子を取得する
                    result = pe.th32ParentProcessID;
                    break;
                }

                // 次のプロセス情報を取得する
                pe.dwSize = sizeof( PROCESSENTRY32 );
                result2 = ::Process32Next( snap, &pe );
            }
        }

        // 実行結果を返す
        return result;
    }
解説

自分を起動したプロセスが誰なのかを知りたいです。
他のプロセスのためのプロセスならば、
親が特定のプロセスでなければ意味がありませんから。

プロセス実行ファイルパス取得関数
    //-------------------------------------------------------------------------
    /// プロセス実行ファイルパス取得関数
    ///
    /// プロセス実行ファイルパス取得関数です。
    ///
    /// @param[in]  id     プロセス識別子
    /// @param[out] buffer 文字列バッファ
    /// @param[out] size   バッファサイズ
    /// @return     文字列ポインタ
    /// @attention  なし
    ///
    char const* GetProcessExeFilePath( DWORD id, char* buffer, size_t size ) {
        // 実行結果を初期化する
        char const* result = nullptr;

        // モジュールスナップショットを作成する
        HANDLE snap = ::CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, id );
        if ( nullptr != snap ) {
            // 最初のモジュール情報を取得する
            MODULEENTRY32 me;
            me.dwSize = sizeof( MODULEENTRY32 );
            BOOL result2 = ::Module32First( snap, &me );

            // モジュール情報を巡回する
            while ( TRUE == result2 ) {
                // プロセス識別子を調べる
                if ( id == me.th32ProcessID ) {
                    // プロセス実行ファイルパスを取得する
                    ::strcpy_s( buffer, size, me.szExePath );

                    // 文字列ポインタを設定する
                    result = buffer;
                    break;
                }

                // 次のプロセス情報を取得する
                me.dwSize = sizeof( MODULEENTRY32 );
                BOOL result2 = ::Module32Next( snap, &me );
            }
        }

        // 実行結果を返す
        return result;
    }
解説

親プロセスの識別子が分かったなら、
その実行ファイルパスから
目的とするプロセスかどうか
判断できますよね。

プロセス検索関数
    //-------------------------------------------------------------------------
    /// プロセス検索関数
    ///
    /// プロセス検索関数です。
    ///
    /// @param[in] value プロセス実行ファイルパス
    /// @return    プロセス識別子
    /// @attention なし
    ///
    //-------------------------------------------------------------------------
    // プロセス検索関数
    DWORD SearchProcess( char const* value ) {
        // 実行結果を初期化する
        DWORD result = 0;

        // プロセススナップショットを作成する
        HANDLE snap_process = ::CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
        if ( nullptr != snap_process ) {
            // 最初のプロセス情報を取得する
            PROCESSENTRY32 pe;
            pe.dwSize = sizeof( PROCESSENTRY32 );
            BOOL result2 = ::Process32First( snap_process, &pe );

            // プロセス情報を巡回する
            while ( TRUE == result2 ) {
                // モジュールスナップショットを作成する
                HANDLE snap_module = ::CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pe.th32ProcessID );
                if ( nullptr != snap_module ) {
                    // 最初のモジュール情報を取得する
                    MODULEENTRY32 me;
                    me.dwSize = sizeof( MODULEENTRY32 );
                    BOOL result2 = ::Module32First( snap_module, &me );

                    // モジュール情報を巡回する
                    while ( TRUE == result2 ) {
                        // プロセス実行ファイルパスを調べる
                        if ( 0 == ::_strcmpi( value, me.szExePath ) ) {
                            // プロセス識別子を取得する
                            result = pe.th32ProcessID;
                            break;
                        }

                        // 次のプロセス情報を取得する
                        me.dwSize = sizeof( MODULEENTRY32 );
                        BOOL result2 = ::Module32Next( snap_module, &me );
                    }

                    // 実行結果を調べる
                    if ( 0 != result ) {
                        // ブレークする
                        break;
                    }
                }

                // 次のプロセス情報を取得する
                pe.dwSize = sizeof( PROCESSENTRY32 );
                result2 = ::Process32Next( snap_process, &pe );
            }
        }

        // 実行結果を返す
        return result;
    }
解説

いろんなプロセスを殺したいときってありますよね。
ファイル名だけだと同じ名前の他人だったりするから、
ちゃんとフルパスで探してあげてね。
あと
必要なヘッダはこんな感じです。

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

もし足りなかったらぼめんなさい。

以上です。

C++/CLIにはまる

いままでWin32だけで済まそうとがんばって来ましたが、.NETの便利な関数というか.NETにしかない関数を使いたくて、ついにCLIに手を出しました。
でもやっぱりC#には手を出したくない。仕事以外では。
なぜならば神であるビャーネ・ストラウストラップ先生に申し訳ないからだ。
ま、両方やればいいじゃんと言う話もあるが。

しかし結局CLIを勉強しようとすると、C#の勉強にもなってしまうのだ。
なぜならば.NET APIを検索すると、ほとんどC#関係の記事しか引っかからないからだ。

VS2015を使えば、C++11とCLIを同時に使えるので非常に便利で楽しい。
しかも#pragma managedを使えば、CLRプロジェクトでも、ほぼすべてネイティブコードで書くことだってできるんだ。意味ないけど。

最近やっと、マネージコードとネイティブコードの混在方法が分かってきた。
マネージコードでDLL作ると、ヘッダファイルを書く必要がないってのも分かった。
いまオリジナルの構成ファイル処理モジュールを作っている。
.NETに備え付けの構成ファイルAPIだと細かいことが自由にできないからだ。
そんなわけでXMLも勉強してしまった。
実におもしろい。

レジストリのクラス

ずっと昔ながらのプロファイルばかり使っていましたが、
意を決してレジストリを使うことにしました。
そこで、レジストリのクラスを作りました。

TRegistry.h
//----------------------------------------------------------------------------
/// @file    TRegistry.h
/// @brief   レジストリクラスヘッダ
/// @details レジストリクラスです。
/// @version 0.1.0
/// @date    2015/05/10
/// @author  Copyright (C) 2015 hidakas1961 All rights reserved.
//----------------------------------------------------------------------------

#pragma once

#include <Common.h>
#include <TLogOut.h>

// 共通ライブラリ名前空間
namespace Common
{
    //------------------------------------------------------------------------
    /// @brief   レジストリクラス
    /// @details レジストリクラスです。
    //------------------------------------------------------------------------
    class TRegistry
    {
        //--------------------------------------------------------------------
        // 動的変数
        //--------------------------------------------------------------------

    private :

        HKEY         m_hopenkey; ///< オープンキーハンドル
        const char * m_headkey;  ///< 先頭キー文字列
        const char * m_subkey;   ///< サブキー文字列

        //--------------------------------------------------------------------
        // 構築子と解体子
        //--------------------------------------------------------------------

    public :

        /// @brief   デフォルト構築子
        /// @param   [in] subkey   サブキー文字列
        /// @param   [in] headkey  先頭キー文字列
        /// @param   [in] hopenkey オープンキーハンドル
        /// @details レジストリクラスを構築します。
        explicit TRegistry( const char * subkey, const char * headkey = "Software", HKEY hopenkey = HKEY_CURRENT_USER );

        /// @brief 解体子
        inline virtual ~TRegistry() {}

        //--------------------------------------------------------------------
        // 動的関数
        //--------------------------------------------------------------------

    private :

        /// @brief   レジストリキーオープン関数
        /// @param   [in] tailkey 最後尾キー文字列
        /// @return  レジストリキーハンドル
        /// @details レジストリキーをオープンします。
        HKEY OpenKey( const char * tailkey = 0 ) const;

    public :

        /// @brief   任意型データ保存関数
        /// @param   [in] entry   エントリー文字列
        /// @param   [in] data    任意データ
        /// @param   [in] tailkey 最後尾キー文字列
        /// @retval  true  成功
        /// @retval  false 失敗
        /// @details 任意の型のデータを保存します。
        template< class T > bool WriteData( const char * entry, const T & data, const char * tailkey = 0 ) const
        {
            bool  result = false;
            DWORD size   = sizeof( data );
            DWORD type   = REG_BINARY;

            Log().Begin( __func__ );
            Log().LineDataText( "entry  ", entry );
            Log().LineDataText( "class T", typeid( data ).name() );
            Log().LineData    ( "data   ", data );
            Log().LineDataText( "tailkey", tailkey );
            Log().LineDataText( "type   ", "REG_BINARY" );
            Log().LineData    ( "size   ", size );

            // レジストリキーをオープンします。
            HKEY hkey = OpenKey( tailkey );

            if ( hkey )
            {
                // エントリデータを保存します。
                result = RegSetValueEx( hkey, entry, 0, type, reinterpret_cast< const BYTE * >( & data ), size ) == ERROR_SUCCESS;

                // レジストリキーをクローズします。
                RegCloseKey( hkey );
            }

            Log().LineData( "result ", result );
            Log().End( __func__ );

            return result;
        }

        /// @brief   任意型データ取得関数
        /// @param   [in] entry   エントリー文字列
        /// @param   [in] data    デフォルトデータ
        /// @param   [in] tailkey 最後尾キー文字列
        /// @return  任意型データ
        /// @details 任意の型のデータを取得します。
        template< class T > T ReadData( const char * entry, const T & data, const char * tailkey = 0 ) const
        {
            bool  result = false;
            T     buffer = data;
            DWORD size   = sizeof( T );
            DWORD recv   = 0;
            DWORD type   = REG_BINARY;

            Log().Begin( __func__ );
            Log().LineDataText( "entry  ", entry );
            Log().LineDataText( "class T", typeid( data ).name() );
            Log().LineData    ( "data   ", data );
            Log().LineDataText( "tailkey", tailkey );
            Log().LineDataText( "type   ", "REG_BINARY" );
            Log().LineData    ( "size   ", size );

            // レジストリキーをオープンします。
            HKEY hkey = OpenKey( tailkey );

            if ( hkey )
            {
                // エントリデータを取得します。
                if ( RegQueryValueEx( hkey, entry, 0, & type, reinterpret_cast< BYTE * >( & buffer ), & size ) == ERROR_SUCCESS )
                {
                    result = true;
                    recv   = size;
                }

                // レジストリキーをクローズします。
                RegCloseKey( hkey );
            }

            Log().LineData( "result ", result );
            Log().LineData( "recv   ", recv );
            Log().LineData( "buffer ", buffer );
            Log().End( __func__ );

            return buffer;
        }

        /// @brief   バイナリデータ保存関数
        /// @param   [in] entry   エントリー文字列
        /// @param   [in] buffer  バッファポインタ
        /// @param   [in] size    バッファサイズ
        /// @param   [in] tailkey 最後尾キー文字列
        /// @retval  true  成功
        /// @retval  false 失敗
        /// @details バイナリデータを保存します。
        bool WriteBinary( const char * entry, const void * buffer, DWORD size, const char * tailkey = 0 ) const;

        /// @brief   文字列保存関数
        /// @param   [in] entry   エントリー文字列
        /// @param   [in] text    文字列
        /// @param   [in] tailkey 最後尾キー文字列
        /// @retval  true  成功
        /// @retval  false 失敗
        /// @details 文字列を保存します。
        bool WriteText( const char * entry, const char * text, const char * tailkey = 0 ) const;

        /// @brief   整数型データ保存関数
        /// @param   [in] entry   エントリー文字列
        /// @param   [in] data    整数型データ
        /// @param   [in] tailkey 最後尾キー文字列
        /// @retval  true  成功
        /// @retval  false 失敗
        /// @details 整数型のデータを保存します。
        bool WriteInt( const char * entry, DWORD data, const char * tailkey = 0 ) const;

        /// @brief   バイナリデータ取得関数
        /// @param   [in] entry   エントリー文字列
        /// @param   [in] buffer  バッファポインタ
        /// @param   [in] size    バッファサイズ
        /// @param   [in] tailkey 最後尾キー文字列
        /// @return  取得データバイトサイズ
        /// @details バイナリデータを取得します。
        DWORD ReadBinary( const char * entry, void * buffer, DWORD size, const char * tailkey = 0 ) const;

        /// @brief   文字列取得関数
        /// @param   [in] entry   エントリー文字列
        /// @param   [in] buffer  文字列バッファポインタ
        /// @param   [in] size    バッファサイズ
        /// @param   [in] tailkey 最後尾キー文字列
        /// @return  取得文字列バイトサイズ
        /// @details 文字列を取得します。
        DWORD ReadText( const char * entry, char * buffer, DWORD size, const char * tailkey = 0 ) const;

        /// @brief   整数型データ取得関数
        /// @param   [in] entry   エントリー文字列
        /// @param   [in] data    デフォルトデータ
        /// @param   [in] tailkey 最後尾キー文字列
        /// @return  整数型データ
        /// @details 整数型のデータを取得します。
        DWORD ReadInt( const char * entry, DWORD data, const char * tailkey = 0 ) const;
    };
}   // Window
TRegistry.cpp
//----------------------------------------------------------------------------
/// @file    TRegistry.cpp
/// @brief   レジストリクラス
/// @details レジストリクラスです。
//----------------------------------------------------------------------------

#include <TRegistry.h>

//----------------------------------------------------------------------------
// 名前空間使用宣言
//----------------------------------------------------------------------------

using namespace Common;

//----------------------------------------------------------------------------
// 構築子と解体子
//----------------------------------------------------------------------------
// デフォルト構築子
TRegistry::TRegistry( const char * subkey, const char * headkey, HKEY hopenkey )
    : m_subkey  ( subkey )
    , m_headkey ( headkey )
    , m_hopenkey( hopenkey )
{
    Log().Begin( __func__ );
    Log().LineDataText( "subkey  ", subkey );
    Log().LineDataText( "headkey ", headkey );
    Log().LineData    ( "hopenkey", hopenkey );
    Log().End( __func__ );
}

//----------------------------------------------------------------------------
// 動的関数
//----------------------------------------------------------------------------

// レジストリキーオープン関数
HKEY TRegistry::OpenKey( const char * tailkey ) const
{
    // サブキー文字列を作成します。
    string subkey;

    if ( m_headkey )
    {
        subkey.append( m_headkey );
        subkey.append( "\\" );
    }

    subkey.append( m_subkey );

    if ( tailkey )
    {
        subkey.append( "\\" );
        subkey.append( tailkey );
    }

    // レジストリキーをオープンします。
    HKEY hkey;

    if ( RegCreateKeyEx( m_hopenkey, subkey.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, & hkey, NULL ) == ERROR_SUCCESS )
    {
        return hkey;
    }

    return 0;
}

// バイナリデータ保存関数
bool TRegistry::WriteBinary( const char * entry, const void * buffer, DWORD size, const char * tailkey ) const
{
    bool  result = false;
    DWORD type   = REG_BINARY;

    Log().Begin( __func__ );
    Log().LineDataText( "entry  ", entry );
    Log().LineData    ( "buffer ", buffer );
    Log().LineData    ( "size   ", size );
    Log().LineDataText( "tailkey", tailkey );
    Log().LineDataText( "type   ", "REG_BINARY" );

    // レジストリキーをオープンします。
    HKEY hkey = OpenKey( tailkey );

    if ( hkey )
    {
        // エントリデータを保存します。
        result = RegSetValueEx( hkey, entry, 0, type, reinterpret_cast< const BYTE * >( buffer ), size ) == ERROR_SUCCESS;

        // レジストリキーをクローズします。
        RegCloseKey( hkey );
    }

    Log().LineData( "result ", result );
    Log().End( __func__ );

    return result;
}

// 文字列保存関数
bool TRegistry::WriteText( const char * entry, const char * text, const char * tailkey ) const
{
    bool  result = false;
    DWORD size   = strlen( text ) + 1;
    DWORD type   = REG_SZ;

    Log().Begin( __func__ );
    Log().LineDataText( "entry  ", entry );
    Log().LineDataText( "text   ", text );
    Log().LineDataText( "tailkey", tailkey );
    Log().LineDataText( "type   ", "REG_SZ" );
    Log().LineData    ( "size   ", size );

    // レジストリキーをオープンします。
    HKEY hkey = OpenKey( tailkey );

    if ( hkey )
    {
        // エントリデータを保存します。
        result = RegSetValueEx( hkey, entry, 0, type, reinterpret_cast< const BYTE * >( text ), size ) == ERROR_SUCCESS;

        // レジストリキーをクローズします。
        RegCloseKey( hkey );
    }

    Log().LineData( "result ", result );
    Log().End( __func__ );

    return result;
}

// 整数型データ保存関数
bool TRegistry::WriteInt( const char * entry, DWORD data, const char * tailkey ) const
{
    bool  result = false;
    DWORD size   = sizeof( DWORD );
    DWORD type   = REG_DWORD;

    Log().Begin( __func__ );
    Log().LineDataText( "entry  ", entry );
    Log().LineData    ( "data   ", data );
    Log().LineDataText( "tailkey", tailkey );
    Log().LineDataText( "type   ", "REG_DWORD" );
    Log().LineData    ( "size   ", size );

    // レジストリキーをオープンします。
    HKEY hkey = OpenKey( tailkey );

    if ( hkey )
    {
        // エントリデータを保存します。
        result = RegSetValueEx( hkey, entry, 0, type, reinterpret_cast< const BYTE * >( & data ), size ) == ERROR_SUCCESS;

        // レジストリキーをクローズします。
        RegCloseKey( hkey );
    }

    Log().LineData( "result ", result );
    Log().End( __func__ );

    return result;
}

// バイナリデータ取得関数
DWORD TRegistry::ReadBinary( const char * entry, void * buffer, DWORD size, const char * tailkey ) const
{
    bool  result = false;
    DWORD recv   = 0;
    DWORD type   = REG_BINARY;

    Log().Begin( __func__ );
    Log().LineDataText( "entry  ", entry );
    Log().LineData    ( "buffer ", buffer );
    Log().LineData    ( "size   ", size );
    Log().LineDataText( "tailkey", tailkey );
    Log().LineDataText( "type   ", "REG_BINARY" );

    // レジストリキーをオープンします。
    HKEY hkey = OpenKey( tailkey );

    if ( hkey )
    {
        // エントリデータを取得します。
        if ( RegQueryValueEx( hkey, entry, 0, & type, reinterpret_cast< BYTE * >( buffer ), & size ) == ERROR_SUCCESS )
        {
            result = true;
            recv   = size;
        }

        // レジストリキーをクローズします。
        RegCloseKey( hkey );
    }

    Log().LineData( "result ", result );
    Log().LineData( "recv   ", recv );
    Log().End( __func__ );

    return recv;
}

// 文字列取得関数
DWORD TRegistry::ReadText( const char * entry, char * buffer, DWORD size, const char * tailkey ) const
{
    bool  result = false;
    DWORD recv   = 0;
    DWORD type   = REG_SZ;

    Log().Begin( __func__ );
    Log().LineDataText( "entry  ", entry );
    Log().LineData    ( "buffer ", buffer );
    Log().LineData    ( "size   ", size );
    Log().LineDataText( "tailkey", tailkey );
    Log().LineDataText( "type   ", "REG_SZ" );

    // レジストリキーをオープンします。
    HKEY hkey = OpenKey( tailkey );

    if ( hkey )
    {
        // エントリデータを取得します。
        if ( RegQueryValueEx( hkey, entry, 0, & type, reinterpret_cast< BYTE * >( buffer ), & size ) == ERROR_SUCCESS )
        {
            result = true;
            recv   = size;
        }

        // レジストリキーをクローズします。
        RegCloseKey( hkey );
    }

    Log().LineData( "result ", result );
    Log().LineData( "recv   ", recv );

    if ( recv )
    {
        Log().LineDataText( "buffer ", buffer );
    }

    Log().End( __func__ );

    return recv;
}

// 整数型データ取得関数
DWORD TRegistry::ReadInt( const char * entry, DWORD data, const char * tailkey ) const
{
    bool  result = false;
    DWORD buffer = data;
    DWORD size   = sizeof( DWORD );
    DWORD recv   = 0;
    DWORD type   = REG_DWORD;

    Log().Begin( __func__ );
    Log().LineDataText( "entry  ", entry );
    Log().LineData    ( "data   ", data );
    Log().LineDataText( "tailkey", tailkey );
    Log().LineDataText( "type   ", "REG_DWORD" );
    Log().LineData    ( "size   ", size );

    // レジストリキーをオープンします。
    HKEY hkey = OpenKey( tailkey );

    if ( hkey )
    {
        // エントリデータを取得します。
        if ( RegQueryValueEx( hkey, entry, 0, & type, reinterpret_cast< BYTE * >( & buffer ), & size ) == ERROR_SUCCESS )
        {
            result = true;
            recv   = size;
        }

        // レジストリキーをクローズします。
        RegCloseKey( hkey );
    }

    Log().LineData( "result ", result );
    Log().LineData( "recv   ", recv );
    Log().LineData( "buffer ", buffer );
    Log().End( __func__ );

    return buffer;
}
解説

整数と文字列以外の任意の型にはテンプレートでバイナリーデータとして対応しているので、
どんなクラスや構造体もそのまま保存と取得ができるようになっています。
またログ出力クラスもだいぶ改良しましたので、
サンプルプログラムは、サイドバーのリンクから倉庫置き場に行って適当に見つけてください。
以上です。