ぬの部屋(仮)
nu-no-he-ya
  •      12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • デバッガ用のprintf

    printfデバッグは便利だが、コンソールを開かなければいけないという欠点がある。

    デバッガに出力するならOutputDebugStringという関数があるが、書式指定が使えないので数字の出力には一手間かかる。

    _RPT0 , _RPT1 , _RPT2 , _RPT3 , _RPT4

    というデバッグ用のマクロがあり、これをつかえばprintfのように書けるのだが、引数の数が決まっていてやや不便。

    https://msdn.microsoft.com/ja-jp/library/ms350217(v=vs.71).aspx

    _RPTn使用例:

    #include <crtdbg.h>
    void func(int input1,double input2) {
      _RPT2(
        _CRT_WARN, 
        "func inputs = %d , %lf \n", 
        input1,
        input2
      );
    }
    

     

    printf(そして可変長引数)は危険なので、デバッグしようとしてバグを増やしてしまっては本末転倒と考えれば、この仕様は合理的だ。しかしそれでもprintf形式が恋しくなることがあるので、自作する。

    自作DebugPrintf

    void DebugPrintf(LPCTSTR pszFormat, ...)
    {
      va_list  argp;
      TCHAR pszBuf[256];
      va_start(argp, pszFormat);
      _vstprintf(pszBuf, pszFormat, argp);
      va_end(argp);
      OutputDebugString(pszBuf);
    }
    

    可変長引数をとる関数を作りそれをそのまま_vstprintfへ流し、OutputDebugStringでデバッガへ出力。ここでは文字数の上限が256となっているが、リスクを承知でやっているのだからこの点は自己責任となる。

     

     

     

     

     

    C++CLIでParallel::For

    C#のサンプルは沢山あるがCLIで実行できずに困ったのでここに書いておく。

    下記は、要素数10のdoubleの配列aの内容を、0~9の1.5倍の値で初期化する。

     

    using namespace System;
    typedef double datatype_t;
    ref struct mystruct{
       array<datatype_t>^ m_a;
    public:
       mystruct(array<datatype_t>^ dst){
          m_a = dst;
       }
       void function(int number){
          m_a[ number] =  number*1.5;
       }
    };
    int main(array<System::String ^> ^args)
    {
       array<datatype_t>^ a = gcnew array<datatype_t>(10);
    
       mystruct^ plfor = gcnew mystruct(a);
    
       System::Threading::Tasks::Parallel::For(
          0,
          a->Length,
          gcnew Action<int>(plfor, &mystruct::function)
       );
    
       for(int i= 0 ;i < a->Length;i++){
          System::Console::WriteLine( 
             System::String::Format("a[{0}] = {1}",i,a[i]));
       }
    
       Console::ReadLine();
    
        return 0;
    }
    

     

     

    Win32APIでウィンドウをカプセル化

    ウィンドウプロシージャをメンバ関数にしたい。しかしWNDCLASSEXのlpfnWndProcに指定できるのは普通の関数かstaticメンバ関数のみ。

    しかし一工夫することで、ウィンドウをカプセル化することができる。コードは以下。

    (ソースコードをまとめたファイル:CnuWindow.zip )

     

    CnuWindow.h

    #pragma once
    #include <windows.h>
    class CnuWindow
    {
       TCHAR WINDOW_CLASS_NAME[1024];
    
       static LRESULT CALLBACK StaticWndProc(
          HWND hWnd, 
          UINT msg, 
          WPARAM wp, 
          LPARAM lp);
    private:
       HWND m_hwnd;
       HINSTANCE m_hInstance;
    public:
       CnuWindow();
       virtual ~CnuWindow();
    
       //! @brief ウィンドウ定義用メンバ関数
       bool RegistWindow(
          const TCHAR* window_class_name, 
          const HINSTANCE hInst
       );
    
       //! @brief ウィンドウプロシージャ
       virtual LRESULT WndProc(
          HWND hWnd, 
          UINT msg, 
          WPARAM wp, 
          LPARAM lp
       );
    
       HWND GetHWnd()const { return m_hwnd; }
       HINSTANCE GetHInstance()const { return m_hInstance; }
    
       //! @brief ウィンドウ作成用メンバ関数
       bool nuCreateWindow(
          LPCTSTR lpWindowName,   // ウィンドウ名
          DWORD dwStyle,         // ウィンドウスタイル
          int x,               // ウィンドウの横方向の位置
          int y,               // ウィンドウの縦方向の位置
          int nWidth,            // ウィンドウの幅
          int nHeight,         // ウィンドウの高さ
          HWND hWndParent,      // 親ウィンドウまたはオーナーウィンドウのハンドル
          HMENU hMenu            // メニューハンドルまたは子ウィンドウ ID
       );
    };
    

     

    CnuWindow.cpp

    #include "CnuWindow.h"
    #include <windows.h>
    #include <tchar.h>
    CnuWindow::CnuWindow()
    {
    }
    CnuWindow::~CnuWindow()
    {
    }
    // ウィンドウを作成する
    bool CnuWindow::RegistWindow(const TCHAR* window_class_name, const HINSTANCE hInst)
    {
       _tcscpy_s(WINDOW_CLASS_NAME, window_class_name);
       m_hInstance = hInst;
       WNDCLASSEX wc;
    
       // ウィンドウクラスの情報を設定
       wc.cbSize = sizeof(wc);
       wc.style = CS_HREDRAW | CS_VREDRAW;
       wc.lpfnWndProc = CnuWindow::StaticWndProc; // ウィンドウプロシージャ
       wc.cbClsExtra = 0;
       wc.cbWndExtra = 0;
       wc.hInstance = hInst;                     // インスタンスハンドル
       wc.hIcon = (HICON)LoadIcon(NULL, IDI_APPLICATION);
       wc.hIconSm = wc.hIcon;
       wc.hCursor = (HCURSOR)LoadCursor(NULL, IDC_ARROW);
       wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
       wc.lpszMenuName = NULL;
       wc.lpszClassName = WINDOW_CLASS_NAME;     // ウィンドウクラス名
    
       // ウィンドウクラスを登録する
       if (RegisterClassEx(&wc) == 0) { return false; }
    
       return true;
    }
    bool CnuWindow::nuCreateWindow(
       LPCTSTR lpWindowTitle, // ウィンドウ名
       DWORD dwStyle,        // ウィンドウスタイル
       int x,                // ウィンドウの横方向の位置
       int y,                // ウィンドウの縦方向の位置
       int nWidth,           // ウィンドウの幅
       int nHeight,          // ウィンドウの高さ
       HWND hWndParent,      // 親ウィンドウまたはオーナーウィンドウのハンドル
       HMENU hMenu           // メニューハンドルまたは子ウィンドウ ID
    ) {
       m_hwnd = CreateWindow(
          WINDOW_CLASS_NAME,      // ウィンドウクラス名
          lpWindowTitle,         // タイトルバーに表示する文字列
          dwStyle,            //  ウィンドウの種類
          x,                  // ウィンドウを表示する位置(X座標)
          y,                  // ウィンドウを表示する位置(Y座標)
          nWidth,               // ウィンドウの幅
          nHeight,            // ウィンドウの高さ
          hWndParent,            // 親ウィンドウのウィンドウハンドル
          hMenu,               // メニューハンドル
          m_hInstance,         // インスタンスハンドル
          this               // その他の作成データ
       );
       if (m_hwnd == nullptr)
          return false;
    
       return true;
    }
    LRESULT  CnuWindow::WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
    {
       switch (msg)
       {
       case WM_DESTROY:
          PostQuitMessage(0);
          return 0;
       }
       return DefWindowProc(hWnd, msg, wp, lp);
    }
    LRESULT CALLBACK CnuWindow::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    
       CnuWindow* This = (CnuWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
       if (!This) {//取得できなかった(ウィンドウ生成中)場合
          if (message == WM_CREATE) {
             This = (CnuWindow*)((LPCREATESTRUCT)lParam)->lpCreateParams;
             if (This) {
                SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)This);
                return This->WndProc(hWnd, message, wParam, lParam);
             }
          }
       }
       else {//取得できた場合(ウィンドウ生成後)
          return This->WndProc(hWnd, message, wParam, lParam);
       }
       return DefWindowProc(hWnd, message, wParam, lParam);
    }
    

     

    main.cpp

    #include<windows.h>
    #include <tchar.h>
    #include "CnuWindow.h"
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
       PSTR lpCmdLine, int nCmdShow) {
    
       CnuWindow wino;
       wino.RegistWindow(_T("WINO"), hInstance);
       wino.nuCreateWindow(
          _T("ウィンドウO"), 
          WS_OVERLAPPEDWINDOW | WS_VISIBLE, 
          100, 100, 
          300, 300, 
          nullptr, 
          nullptr
       );
    
    
       MSG msg;
       while (GetMessage(&msg, NULL, 0, 0)) {
          TranslateMessage(&msg);
          DispatchMessage(&msg);
       }
       return (int)msg.wParam;
    }
    

     

    クラス名はCnuWindowにしているので、それを置換すれば独自のクラス名にできる。

    内容的にはCreateWindow時にlpParamに自身のthisを入れる典型的な方法なので詳細は他所へ譲るとして、多少解説をする

    解説1 SetWindowLongPtrを使う

    LRESULT CALLBACK CnuWindow::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    
       CnuWindow* This = (CnuWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
       if (!This) {//取得できなかった(ウィンドウ生成中)場合
          if (message == WM_CREATE) {
             This = (CnuWindow*)((LPCREATESTRUCT)lParam)->lpCreateParams;
             if (This) {
                SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)This);
                return This->WndProc(hWnd, message, wParam, lParam);
             }
          }
       }
       else {//取得できた場合(ウィンドウ生成後)
          return This->WndProc(hWnd, message, wParam, lParam);
       }
       return DefWindowProc(hWnd, message, wParam, lParam);
    }
    

    64ビット環境ではSetWindowLongではなくSetWindowLongPtrを使わなくてはならない。それに伴い、GetWindowLongPtr,GWLP_USERDATAに変更する。

     

    解説2 (staticでない)メンバ関数のWndProcをvirtualにする

    virtual LRESULT  WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);
    

     

    これをvirtualにする理由は、main.cppでいずれ以下のように書きたいからである。

    #include<windows.h>
    #include <tchar.h>
    #include <cstdint>
    #include "CnuWindow.h"
    class CWin1 : public CnuWindow {
    
       LRESULT WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
       {
          switch (msg)
          {
          case WM_CREATE:
             break;
          case WM_LBUTTONDOWN:
             MessageBox(hWnd, _T("CWin1"), 0, 0);
             break;
          case WM_DESTROY:
             PostQuitMessage(0);
             return 0;
          }
          return DefWindowProc(hWnd, msg, wp, lp);
       }
    
    };
    
    class CWin2 : public CnuWindow {
    
       LRESULT WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
       {
          switch (msg)
          {
          case WM_CREATE:
             break;
          case WM_LBUTTONDOWN:
             MessageBox(hWnd, _T("CWin2"), 0, 0);
             break;
          case WM_DESTROY:
             PostQuitMessage(0);
             return 0;
          }
          return DefWindowProc(hWnd, msg, wp, lp);
       }
    
    };
    
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
       PSTR lpCmdLine, int nCmdShow) {
    
       CWin1 win1;
       win1.RegistWindow(_T("WIN1"), hInstance);
       win1.nuCreateWindow(_T("ウィンドウ1"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 300, 300, nullptr, nullptr);
    
       CWin2 win2;
       win2.RegistWindow(_T("WIN2"), hInstance);
       win2.nuCreateWindow(_T("ウィンドウ2"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 400, 300, 300, nullptr, nullptr);
    
       CnuWindow wino;
       wino.RegistWindow(_T("WINO"), hInstance);
       wino.nuCreateWindow(_T("ウィンドウO"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 800, 300, 300, nullptr, nullptr);
    
    
       MSG msg;
       while (GetMessage(&msg, NULL, 0, 0)) {
          TranslateMessage(&msg);
          DispatchMessage(&msg);
       }
       return (int)msg.wParam;
    
    }
    

     

    上記コードは、CnuWindowを継承したCWin1,CWin2クラスを作成し、それぞれのインスタンスがまったく異なるウィンドウとして動作する。

    WndProcを仮想関数にしないと、CWin1,CWin2を作成してもメッセージが全てCnuWindowの方へ行ってしまうので、変数をグローバルにしなくていい程度のメリットしかなくなってしまう。このようにクラスを作れば、同じコードで違う挙動をするウィンドウを最小限の労力で作ることができる。