ぬの部屋(仮)
nu-no-he-ya
  •      12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
         12
    3456789
    10111213141516
    17181920212223
    2425262728  
           
      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
           
       1234
    567891011
    12131415161718
    19202122232425
    26272829   
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       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     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28      
           
         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     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
    1234567
    891011121314
    15161718192021
    22232425262728
           
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       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     
         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
           
  • C++CLIでテキストファイルの入出力

    テキストファイルの書き込みにはStreamWriterを用いる。System::Text::Encodingでエンコーディングの指定が可能

    void FileWrite(System::String^ filepathname)
    {
      System::IO::StreamWriter^ sw = gcnew System::IO::StreamWriter(
        filepathname, //ファイル名
        false, //追記モード
        System::Text::Encoding::UTF8
        //System::Text::Encoding::GetEncoding("shift_jis") //文字コード
        );
    
    
      sw->Write("吾輩は猫である。名前はまだ無い。\n");
      sw->Write("どこで生れたかとんと見当がつかぬ。\n");
      sw->Write("何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。\n");
      sw->Write("吾輩はここで始めて人間というものを見た。\n");
      sw->Write("しかもあとで聞くとそれは書生という人間中で一番獰悪な種族であったそうだ。\n");
      sw->Write("この書生というのは時々我々を捕えて煮て食うという話である。\n");
    
      sw->Close();
    }
    

     

    テキストファイルの読み込みにはStreamReaderを使用する。

    一行ずつの読み込みにはReadLineを用いる。ファイル終端判定はPeekを使うのが一般的のようだが、参考文献によると模範解答ではないらしい。ここではEndOfStreamを使っている

    void FileRead(System::String^ filepathname)
    {
    
      //"C:\test\1.txt"をShift-JISコードとして開く
      System::IO::StreamReader^ sr = gcnew System::IO::StreamReader(
        "C:\\test\\sample.txt",
        System::Text::Encoding::Encoding::UTF8);
    
      while(sr->EndOfStream != true ){
        System::String^ r = sr->ReadLine(); 
        System::Console::WriteLine( r );//ReadLineは改行を含まない
      }
    
      sr->Close();
    }
    

     

     

    int main(array<System::String ^> ^args){
    
      FileWrite("C:\\test\\sample.txt");
      FileRead("C:\\test\\sample.txt");
    
      System::Console::Read();
    }
    

     

    参考文献

    https://dobon.net/vb/dotnet/file/readfile.html

    https://www.aozora.gr.jp/cards/000148/files/789_14547.html

    http://d.hatena.ne.jp/saiya_moebius/20090116/1232072712

    グローバルフック マウスフック

    グローバルフックをするには、DLLにする必要がある。

    また、イベントがあったことを知るために、FindWindowで送信先のウィンドウクラス名を指定してSendMessageしている。

    マウスフックの時は、SetWindowsHookExに渡す引数はWH_MOUSEとなる。また、フックプロシージャのwParamにはイベントが入っている。

     

    DLL側

    dllmain.h

    #pragma once
    #include <Windows.h>
    BOOL APIENTRY DllMain(HMODULE hModule,
      DWORD  ul_reason_for_call,
      LPVOID lpReserved
    );
    HINSTANCE GetDllInstance();
    

    dllmain.cpp

    HINSTANCE hDLLInstance = nullptr;
    BOOL APIENTRY DllMain(HMODULE hModule,
      DWORD  ul_reason_for_call,
      LPVOID lpReserved
    )
    {
      hDLLInstance = hModule;
    
      return TRUE;
    }
    HINSTANCE GetDllInstance() {
      return hDLLInstance;
    }
    

    フックをかけるときにインスタンスハンドルが必要になるので、DllMainの中で保存しておく。

     

    DLLDefs.h

    DLL側にはプリプロセッサにDLL_EXPORT_DOをセットする。

    #ifdef  DLL_EXPORT_DO
    /*  DLLを作る場合   */
    #define  __DLL_PORT  extern "C" __declspec(dllexport)
    #define  __DLL_PORT_CLS __declspec(dllexport)
    #else
    /*  DLLを使う場合   */
    #define  __DLL_PORT  extern "C" __declspec(dllimport)   
    #define  __DLL_PORT_CLS __declspec(dllimport)
    #endif
    

    このファイルは次のMouseHook.hでincludeされるが、結果的にexe側でもincludeされることになるので、両方のプロジェクトから読める必要がある。

     

     

    MouseHook.h

    #pragma once
    #include <Windows.h>
    #include "../DLLDefs.h"
    
    //マウスがクリックされたら、本体のプログラムへこのメッセージを送信する
    constexpr UINT WM_HOOKED_MOUSEDOWN = WM_USER + 2;
    
    class __DLL_PORT_CLS CMouseHook {
      static HHOOK hHook;
      static LRESULT CALLBACK MouseProcedure(int p_nCode, WPARAM p_wParam, LPARAM p_lParam);
    public:
      BOOL Set();
      BOOL Unset();
      ~CMouseHook();
    };
    

    フック関数とフックハンドルはstaticにする。

     

    MouseHook.cpp

    #include "MouseHook.h"
    #include "dllmain.h"
    #include <tchar.h>
    
    #pragma warning(disable:4996)
    #pragma data_seg( ".CMouseHookHandle" )
    HHOOK CMouseHook::hHook = nullptr;
    #pragma data_seg()
    
    BOOL CMouseHook::Set() {//フックをセットする関数
      hHook = ::SetWindowsHookEx(WH_MOUSE //種類はマウスフック
        , (HOOKPROC)CMouseHook::MouseProcedure
        , GetDllInstance(), 0);//このDLLのインスタンスハンドルを指定
    
      if (!hHook)
        return FALSE;
    
      return TRUE;
    }
    
    BOOL CMouseHook::Unset() {//フックを外す
      BOOL ret = FALSE;
    
      if (hHook)
        ret = ::UnhookWindowsHookEx(hHook);
    
      hHook = nullptr;
      return ret;
    }
    
    //フックの処理
    LRESULT CALLBACK CMouseHook::MouseProcedure(int p_nCode, WPARAM p_wParam, LPARAM p_lParam) {
      if (p_nCode < 0)
        return ::CallNextHookEx(hHook, p_nCode, p_wParam, p_lParam);
    
      if (p_nCode == HC_ACTION) {
    
        MOUSEHOOKSTRUCT *pmh = (MOUSEHOOKSTRUCT *)p_lParam;
    
        if (pmh) {
          if (p_wParam == WM_LBUTTONDOWN || p_wParam == WM_NCLBUTTONDOWN) {
                                      //このNU_WND_CLASS_NAMEは、exe側で作成するウィンドウのウィンドウクラス名
            PostMessage(FindWindow(_T("NU_WND_CLASS_NAME"), nullptr), WM_HOOKED_MOUSEDOWN, p_wParam, p_lParam);
                                                                       //exe側にWM_HOOKED_MOUSEDOWNを送る
          }
        }
      }
      return ::CallNextHookEx(hHook, p_nCode, p_wParam, p_lParam);;
    }
    CMouseHook::~CMouseHook() {
      Unset();
    }
    

     

    MouseHook.def

    SECTIONS
     .CMouseHookHandle	READ WRITE SHARED
    

     

    exe側

    #pragma comment(lib, "MouseHook.lib")
    #include "../MouseHook/MouseHook.h"
    #include<windows.h>
    #include <tchar.h>
    //ウィンドウプロシージャ
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
      switch (msg) {
      case WM_DESTROY:
        DestroyWindow(hwnd);
        PostQuitMessage(0);
        return 0;
      case WM_HOOKED_MOUSEDOWN:
        OutputDebugString(_T("どこかの窓でマウスがクリックされました\n"));
        return 0;
      }
      return DefWindowProc(hwnd, msg, wp, lp);
    }
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
      PSTR lpCmdLine, int nCmdShow) {
      HWND hwnd;
      MSG msg;
      WNDCLASS winc;
    
      //ウィンドウクラスの登録
      winc.style = CS_HREDRAW | CS_VREDRAW;
      winc.lpfnWndProc = WndProc;
      winc.cbClsExtra = winc.cbWndExtra = 0;
      winc.hInstance = hInstance;
      winc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
      winc.hCursor = LoadCursor(NULL, IDC_ARROW);
      winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
      winc.lpszMenuName = NULL;
      winc.lpszClassName = TEXT("NU_WND_CLASS_NAME");
    
      if (!RegisterClass(&winc)) return 0;
    
    
      //フックをかける
      CMouseHook hm;
      hm.Set();
    
      //ウィンドウ作成
      hwnd = CreateWindow(
        TEXT("NU_WND_CLASS_NAME"), TEXT("test"),
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        100, 100, 200, 200, NULL, NULL,
        hInstance, NULL
      );
    
      if (hwnd == NULL) return 0;
    
      while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg);
    
      //フックを外す
      hm.Unset();
    
      return msg.wParam;
    }
    

     

     

    vray for Blenderでオブジェクトにfog

    VRAY for Blenderでfogを使う方法。

    オブジェクトのマテリアルではなく、Worldの方のEffectsにフォグを設定し、「FogをObjectの中限定で発生させる」という考え方をするらしい。

    複数のオブジェクトをフォグにする場合、Effects ContainerにAddを使い、二つ以上の設定を束ねてWorld Outputへ接続する。

     

    vray_fog_nodes

     

    vray_fog

    はじめてのCUDAプログラム

    CUDAをやってみたくなった。

    インストールがもの凄く簡単になっていて、Visual C++ 2017 Communityが入っているなら

    https://developer.nvidia.com/cuda-downloads

    からCUDA Toolkitをダウンロードしてインストールするだけで、VC++のプロジェクトにCUDAのプロジェクトが追加される。

     

     

    以下、初めてのCUDAプログラム

    #include "cuda_runtime.h"
    #include "device_launch_parameters.h"
    #include <stdio.h>
    #include <cstring>
    __global__ void hello(char *c) {
      c[0] = 'h';
      c[1] = 'e';
      c[2] = 'l';
      c[3] = 'l';
      c[4] = 'o';
      c[5] = '\0';
    }
    int main(void) {
      const size_t LEN = strlen("hello") + 1;//(CPU側)
      char c_cpu[LEN];//(CPU側)
      char *c_gpu;//(CPU側)
    
      cudaMalloc( (void**)&c_gpu, LEN);//GPU側にメモリを確保
    
      hello <<<1, 1 >>>( c_gpu );//GPU側の関数を呼出
    
      cudaMemcpy(&c_cpu, c_gpu, LEN, cudaMemcpyDeviceToHost);//GPU側から実行結果を取得
    
      cudaFree(c_gpu);//GPU側のメモリを解放
    
      puts(c_cpu);//(CPU側)
    
      getchar();//(CPU側)
    
      return 0;
    }
    

     

    cudaMalloc

    GPU側のメモリを確保するための関数。

     

    関数名 cudaMalloc
    戻り値 cudaError_t
    引数
    void** devPtr GPU側で確保したメモリのアドレスを格納するためのvoid**型の変数
    size_t  size 確保するサイズをバイト単位で指定

    参考URI:

    https://www.cs.cmu.edu/afs/cs/academic/class/15668-s11/www/cuda-doc/html/group__CUDART__MEMORY_gc63ffd93e344b939d6399199d8b12fef.html

     

    cudaFree

    cudaMallocで確保したメモリを開放する

    関数名 cudaFree
    戻り値 cudaError_t
     
    void *  devPtr cudaMallocで確保した領域のアドレス

    参考URI

    https://www.cs.cmu.edu/afs/cs/academic/class/15668-s11/www/cuda-doc/html/group__CUDART__MEMORY_gb17fef862d4d1fefb9dba35bd62a187e.html#gb17fef862d4d1fefb9dba35bd62a187e

    C++CLIでメンバ関数をデリゲート経由で呼び出す

    特に解説することはない。

     

    ref class CTest{
    public:
      int func(double v){
        return (int)v * (int)v;
      }
      delegate int DelegateToFuncT(double v);//デリゲート型を定義
    };
    
    ///////////////////////////////////////////////////
    
    int main(array<System::String ^> ^args)
    {
    
      CTest^ ct = gcnew CTest();
    
      //デリゲート作成
      CTest::DelegateToFuncT^ dfunc = gcnew CTest::DelegateToFuncT(ct,&CTest::func);
    
      int ret = dfunc( 5.5 );//呼出
    
      Console::WriteLine( System::String::Format("** {0}\n",ret) );
    
      Console::ReadLine();
    
      return 0;
    }
    

     

     

     

     

     

    C++CLIでdll内のクラスを使う時の error C2011: ‘***’ : ‘class’ 型の再定義

    #pragma onceを忘れたとかそんな話ではない。

    すべてCLIで、testclidll.dll内にクラスClass1を作成し、それをexe側に参照を追加してClass1を使おうとしたとき、

     

    error C2011: 'testclidll::Class1' : 'class' 型の再定義

     

    が発生する

     

    再現手順 (Visual Studio 2017 community)

    問題1

    1.[ファイル] - [新規作成] - [プロジェクト] から、「CLRコンソールアプリケーション」を作成(名前をexe_and_dll_testとする)

    2.[ファイル] - [新規作成] - [プロジェクト] から、「クラスライブラリ」を作成(名前をtestclidllとする)

    3.testclidll.hを以下のようにする

    // testclidll.h
    #pragma once
    using namespace System;
    namespace testclidll {
    
    
      public ref class Class1
      {
        int c;
      public:
        void Set(int d);
        int Get();
    
      };
    }
    

     

    4.testclidll.cppを以下のようにする

    namespace testclidll {
    
      void Class1::Set(int d){
        c = d;
      }
      int Class1::Get(){
        return c;
      }
    }
    

     

    5.exe側を以下のようにする

    #include "stdafx.h"
    using namespace System;
    #include "../testclidll/testclidll.h"
    int main(array<System::String ^> ^args)
    {
    
      testclidll::Class1^ c = gcnew testclidll::Class1;
    
      c->Set(10);
    
      Console::WriteLine(System::String::Format("{0}\n",c->Get()));
        return 0;
    }
    

     

    6.DLLをコンパイルする

    7.ソリューションエクスプローラから、exe側のプロジェクトを右クリックし、[参照...]を選択

     プロパティページから、[共通プロパティ]-[Frameworkと参照]で「新しい参照の追加...」ボタンを押し、コンパイルしたdllを追加する

    8.exe側をコンパイルする

     

    2>e:\mycodes\exe_and_dll_test\exe_and_dll_test\../testclidll/testclidll.h(12): error C2011: 'testclidll::Class1' : 'class' 型の再定義
    2> e:\mycodes\exe_and_dll_test\debug\testclidll.dll : 'testclidll::Class1' の宣言を確認してください。
    2>exe_and_dll_test.cpp(14): error C2027: 認識できない型 'testclidll::Class1' が使われています。
    2> e:\mycodes\exe_and_dll_test\debug\testclidll.dll : 'testclidll::Class1' の宣言を確認してください。
    2>exe_and_dll_test.cpp(14): error C2227: '->Set' : 左側がクラス、構造体、共用体、ジェネリック型へのポインターではありません。
    2>exe_and_dll_test.cpp(18): error C2027: 認識できない型 'testclidll::Class1' が使われています。
    2> e:\mycodes\exe_and_dll_test\debug\testclidll.dll : 'testclidll::Class1' の宣言を確認してください。
    2>exe_and_dll_test.cpp(18): error C2227: '->Get' : 左側がクラス、構造体、共用体、ジェネリック型へのポインターではありません。

     

    解決策1

    まず、C/C++ではdllをリンクするときにも必ずヘッダファイルをincludeしなければならないが、.NETではdllが情報を持っている(?)ので、そこへさらにインクルードをかけると定義が二重に行われる(のだと思う)。従って、

    #include "stdafx.h"
    using namespace System;
    //#include "../testclidll/testclidll.h" //このincludeはしてはいけない
    int main(array<System::String ^> ^args)
    {
    
      testclidll::Class1^ c = gcnew testclidll::Class1;
    
      c->Set(10);
    
      Console::WriteLine(System::String::Format("{0}\n",c->Get()));
        return 0;
    }
    

     

    問題2

    再現手順

    1. testclidll.hを、以下のように修正する

    // testclidll.h
    #pragma once
    using namespace System;
    namespace testclidll {
    
      enum ReturnT{ //型を追加
        True,False,
      };
    
      public ref class Class1
      {
        int c;
      public:
        void Set(int d);
        int Get();
    
      ReturnT isOdd(); //メンバが奇数かどうかを返す関数を追加。戻り値はユーザー定義型のReturnT
    
      };
    }
    

     

    2.testclidll.cppを以下のように修正する

    // これは メイン DLL ファイルです。
    #include "stdafx.h"
    #include "testclidll.h"
    namespace testclidll {
    
      void Class1::Set(int d){
        c = d;
      }
      int Class1::Get(){
        return c;
      }
    
      //メンバが奇数かどうかを返す関数の定義
      ReturnT Class1::isOdd(){
    
        if( c % 2 != 0 )
          return True;
    
        return False;
    
      }
    }
    

     

    3.exe側を以下のように修正する

    #include "stdafx.h"
    using namespace System;
    //#include "../testclidll/testclidll.h"
    int main(array<System::String ^> ^args)
    {
    
      testclidll::Class1^ c = gcnew testclidll::Class1;
    
      c->Set(10);
      
      testclidll::ReturnT t = c->isOdd();//奇数かどうかの判定を追加
    
      Console::WriteLine(System::String::Format("{0}\n",c->Get()));
        return 0;
    }
    

     

    4.testclidllをコンパイルする

     

    5.exe側をコンパイルする

     

    コンバイルエラー

    2>exe_and_dll_test.cpp(16): error C2039: 'ReturnT' : 'testclidll' のメンバーではありません。
    2>exe_and_dll_test.cpp(16): error C2065: 'ReturnT' : 定義されていない識別子です。
    2>exe_and_dll_test.cpp(16): error C2146: 構文エラー : ';' が、識別子 't' の前に必要です。
    2>exe_and_dll_test.cpp(16): error C2065: 't' : 定義されていない識別子です。

     

    これは、クラスの情報は参照したdllの中にあるが、enumのような定数の情報は入っていない(?)ので、定義がないと怒られる。そこで、testclidll.hのincludeを復活させてみる。

    #include "stdafx.h"
    using namespace System;
    #include "../testclidll/testclidll.h" //やっぱりいるのか?
    int main(array<System::String ^> ^args)
    {
    

     

    1>e:\mycodes\exe_and_dll_test\exe_and_dll_test\../testclidll/testclidll.h(14): error C2011: 'testclidll::Class1' : 'class' 型の再定義
    1> e:\mycodes\exe_and_dll_test\debug\testclidll.dll : 'testclidll::Class1' の宣言を確認してください。
    1>exe_and_dll_test.cpp(14): error C2027: 認識できない型 'testclidll::Class1' が使われています。
    1> e:\mycodes\exe_and_dll_test\debug\testclidll.dll : 'testclidll::Class1' の宣言を確認してください。
    1>exe_and_dll_test.cpp(14): error C2227: '->Set' : 左側がクラス、構造体、共用体、ジェネリック型へのポインターではありません。
    1>exe_and_dll_test.cpp(16): error C2027: 認識できない型 'testclidll::Class1' が使われています。
    1> e:\mycodes\exe_and_dll_test\debug\testclidll.dll : 'testclidll::Class1' の宣言を確認してください。
    1>exe_and_dll_test.cpp(16): error C2227: '->isOdd' : 左側がクラス、構造体、共用体、ジェネリック型へのポインターではありません。
    1>exe_and_dll_test.cpp(18): error C2027: 認識できない型 'testclidll::Class1' が使われています。
    1> e:\mycodes\exe_and_dll_test\debug\testclidll.dll : 'testclidll::Class1' の宣言を確認してください。
    1>exe_and_dll_test.cpp(18): error C2227: '->Get' : 左側がクラス、構造体、共用体、ジェネリック型へのポインターではありません。

     

    当然のように最初のエラーが再発する。

     

    解決策2

    enumの定義を別のヘッダファイルへ移動する

    testclidllプロジェクト内、defvalheader.hを追加

    namespace testclidll {
    
      enum ReturnT{
        True,False,
      };
    }
    

    それに伴い、dll本体側であるtestclidll.hからenumの定義を消し、includeにする

    // testclidll.h
    #pragma once
    #include "defvalheader.h" //ReturnTの定義を読み込む
    using namespace System;
    namespace testclidll {
    
      public ref class Class1
      {
        int c;
      public:
        void Set(int d);
        int Get();
    
        ReturnT isOdd();
    
      };
    }
    

     

    exe側では、testclidll.hではなく、defvalheader.hを読み込む

    #include "stdafx.h"
    using namespace System;
    #include "../testclidll/defvalheader.h"
    int main(array<System::String ^> ^args)
    {
    
      testclidll::Class1^ c = gcnew testclidll::Class1;
    
      c->Set(10);
      
      testclidll::ReturnT t = c->isOdd();
    
      Console::WriteLine(System::String::Format("{0}\n",c->Get()));
        return 0;
    }
    

     

     

    タスクトレイにアイコンを表示する

    タスクトレイにアイコンを表示する方法

    ① アイコンの表示を開始したいタイミングで、Shell_NotifyIcon関数をNIM_ADDで呼び出す

    ② メッセージループに「タスクトレイのアイコンにアクションがあった」という単位でメッセージが届くので、処理する

    ③ アイコンを消したいタイミングで、Shell_NotifyIcon関数をNIM_DELETEで呼び出す

     

    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
    
      static const decltype(WM_USER) WM_NOTIFYICON = WM_USER + 100;
      static const int IconID = 100;
    
      switch (msg) {
      case WM_LBUTTONDOWN://ウィンドウをクリックしたらアイコン表示開始
      {
        NOTIFYICONDATA nid;
        nid.cbSize = sizeof(nid);
        nid.hWnd = hwnd;
        nid.uID = IconID;//複数のアイコンを表示したときの識別ID。なんでもいい。
        nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
        nid.uCallbackMessage = WM_NOTIFYICON; //WM_USER以降の定数。
        nid.hIcon = (HICON)LoadIcon(NULL, IDI_APPLICATION);
        _tcscpy(nid.szTip, _T("タスクトレイで表示する文字列"));
        int ret = (int)Shell_NotifyIcon(NIM_ADD, &nid);
        ShowWindow(hwnd, SW_HIDE);
      }
        break;
      case WM_NOTIFYICON:
        if (wp == IconID && lp == WM_LBUTTONDOWN) {
          //アイコンに対する操作がWM_LBUTTONDOWNでアイコンのIDがIconIDなら以下の処理:
          ShowWindow(hwnd, SW_SHOW);
    
          //タスクトレイアイコンを削除
          ////////////////////////////////////////
          NOTIFYICONDATA nid;
          nid.cbSize = sizeof(nid);
          nid.hWnd = hwnd;
          nid.uID = IconID;
          nid.uFlags = 0;
          Shell_NotifyIcon(NIM_DELETE, &nid);
          ////////////////////////////////////////
    
        }
    
        break;
      case WM_DESTROY:
        DestroyWindow(hwnd);
        PostQuitMessage(0);
        return 0;
      }
      return DefWindowProc(hwnd, msg, wp, lp);
    }
    

     

     

     

    デバッガ用の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の方へ行ってしまうので、変数をグローバルにしなくていい程度のメリットしかなくなってしまう。このようにクラスを作れば、同じコードで違う挙動をするウィンドウを最小限の労力で作ることができる。