ぬの部屋(仮)
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
           
  • Rust+windows-rsでDIBを使う

    CreateDIBSectionを使ってDIBを作り、CreateCompatibleDCを使って描画してみる。

    各関数・データ型・定数がwindows-rsのどこにあるかさえわかれば、あとはそこまで難しくはない。

    • win32dib.rs ... DIB関連の変数を一括で管理する構造体+CreateDIBSection,CreateCompatibleDCを呼び出す関数
    • main.rs ... エントリポイント
    • winmain.rs ... ウィンドウを表示して描画を行う

    一番厄介なのはwinmain.rs内でmydibのインスタンスであるグローバル変数で、これはstatic + Lazy + Mutexで実現しないといけない。

    win32dib.rs

    use windows::Win32::Graphics::Gdi::*;
    use windows::core::*;
    use windows::Win32::Foundation::*;
    
    // ■ BITMAPINFO         ... windows::Win32::Graphics::Gdi::BITMAPINFO
    // ■ BITMAPINFOHEADER   ... windows::Win32::Graphics::Gdi::BITMAPINFOHEADER
    // ■ BI_RGB             ... windows::Win32::Graphics::Gdi::BI_RGB
    // ■ CreatedHDC         ... windows::Win32::Graphics::Gdi::CreatedHDC
    // ■ CreateDCA          ... windows::Win32::Graphics::Gdi::CreateDCA
    // ■ CreateCompatibleDC ... windows::Win32::Graphics::Gdi::CreateCompatibleDC
    // ■ CreateDIBSection   ... windows::Win32::Graphics::Gdi::CreateDIBSection
    // ■ DIB_RGB_COLORS     ... windows::Win32::Graphics::Gdi::DIB_RGB_COLORS
    // ■ DeleteDC           ... windows::Win32::Graphics::Gdi::DeleteDC
    // ■ HBITMAP            ... windows::Win32::Graphics::Gdi::HBITMAP
    // ■ HBITMAP            ... windows::Win32::Graphics::Gdi::HBITMAP
    // ■ SelectObject       ... windows::Win32::Graphics::Gdi::SelectObject
    
    // ■ HANDLE             ... windows::Win32::Foundation::HANDLE
    
    // ■ PCSTR              ... windows::core::PCSTR
    
     pub struct Win32DIBCanvas{
        pub bitmap     :HBITMAP,
        pub bitmapInfo :BITMAPINFO,
        pub ppixel     :*mut std::ffi::c_void,
        pub hMemDC     : CreatedHDC,
    }
    
    // ppixel:*mut std::ffi::c_void, があるので、Send,Syncを実装しなければmyDIBをLazy<Mutex<myDIB>>に入れられない
    unsafe impl Send for Win32DIBCanvas {}
    unsafe impl Sync for Win32DIBCanvas {}
    
    impl Win32DIBCanvas{
        pub fn new()->Win32DIBCanvas{
            Win32DIBCanvas{
                bitmap    :HBITMAP(0),
                bitmapInfo:Default::default(),
                ppixel    :std::ptr::null_mut(),
                hMemDC    :CreatedHDC(0),
            }
        }
        pub fn create(&mut self,width:i32,height:i32){
    
            
    
            unsafe{
                let mut hdca = CreateDCA(
                    PCSTR::from_raw("DISPLAY\0".as_ptr()),
                    None,
                    None,
                    None
                );
    
                self.bitmapInfo.bmiHeader.biSize        = std::mem::size_of::<BITMAPINFOHEADER>() as u32;
                self.bitmapInfo.bmiHeader.biWidth       = width;
                self.bitmapInfo.bmiHeader.biHeight      = -height;
                self.bitmapInfo.bmiHeader.biPlanes      = 1;
                self.bitmapInfo.bmiHeader.biBitCount    = 3*8;
                self.bitmapInfo.bmiHeader.biCompression = BI_RGB;
    
                let hBitmap = CreateDIBSection(
                    hdca,
                    &self.bitmapInfo,
                    DIB_RGB_COLORS,
                    &mut self.ppixel,
                    HANDLE(0),
                    0
                );
    
                self.hMemDC =  CreateCompatibleDC(hdca);
    
                if let Ok(hbmp) = hBitmap{
                    SelectObject(self.hMemDC,hbmp);
                }
    
                DeleteDC(hdca);
            }
        }
    }
    

    main.rs

    main関数。CではWinMain開始だが、Rustではwindowsプログラムもmainから始める。

    気分的にWinMainが欲しいので、main関数からWinMainを呼ぶようにしている。

    mod winmain;
    use winmain::WinMain;
    
    
    use windows::Win32::Foundation::*;
    use windows::Win32::System::LibraryLoader::*;
    use windows::Win32::System::Threading::*;
    
    // ■ HINSTANCE        ... windows::Win32::Foundation::HINSTANCE
    // ■ GetModuleHandleA ... windows::Win32::System::LibraryLoader::GetModuleHandleA
    // ■ STARTUPINFOW     ... windows::Win32::System::Threading::STARTUPINFOW
    // ■ GetStartupInfoW  ... windows::Win32::System::Threading::GetStartupInfoW
    
    
    // Rustのwindows-rsからウィンドウズアプリケーションをビルドする時には、
    // WinWain ではなくmainをエントリポイントとする。
    
    fn main()-> windows::core::Result<()>  {
    
        let hInstance:HINSTANCE;
        unsafe{
            // https://github.com/microsoft/windows-samples-rs/blob/master/create_window/src/main.rs
            hInstance = GetModuleHandleA(None).unwrap();
        }
    
        // https://doc.rust-jp.rs/book-ja/ch12-01-accepting-command-line-arguments.html
        let args: Vec<String> = std::env::args().collect();
    
    
        // https://stackoverflow.com/questions/68322072/how-to-get-args-from-winmain-or-wwinmain-in-rust
        let mut si = STARTUPINFOW {
            cb: std::mem::size_of::<STARTUPINFOW>() as u32,
            ..Default::default()
        };
        unsafe {
            GetStartupInfoW(&mut si) 
        };
        let cmd_show = si.wShowWindow as i32;
    
        ////////////////////////////////////////////////////////////////////////////////////
        // 自作WinMainを呼び出す
    
        WinMain(
            hInstance,
            HINSTANCE(0),
            args,
            cmd_show
        );
    
    
        Ok(())
    
    }
    

    winmain.rs

    #[path="./win32dib.rs"]
    mod win32dib;
    use win32dib::Win32DIBCanvas;
    
    
    use windows::{
        core::*, 
        Win32::Foundation::*,
        Win32::Graphics::Gdi::*,
        Win32::UI::WindowsAndMessaging::*,
    };
    
    use once_cell::sync::Lazy;
    use std::sync::Mutex;
    
    // ■ Mutex ... std::sync::Mutex
    // ■ Lazy  ... once_cell::sync::Lazy
    
    
    // DIBを管理する構造体のグローバル変数
    static mydib:Lazy<Mutex<Win32DIBCanvas>> = 
            Lazy::new(|| 
                Mutex::new(
                    Win32DIBCanvas::new()
                )
            );
    
    
    // ■ COLORREF            ... windows::Win32::Foundation::COLORREF
    // ■ HINSTANCE           ... windows::Win32::Foundation::HINSTANCE
    // ■ HWND                ... windows::Win32::Foundation::HWND
    // ■ LPARAM              ... windows::Win32::Foundation::LPARAM
    // ■ LRESULT             ... windows::Win32::Foundation::LRESULT
    // ■ POINT               ... windows::Win32::Foundation::POINT
    // ■ RECT                ... windows::Win32::Foundation::RECT        
    // ■ WPARAM              ... windows::Win32::Foundation::WPARAM
    
    
    // ■ BeginPaint          ... windows::Win32::Graphics::Gdi::BeginPaint
    // ■ BitBlt              ... windows::Win32::Graphics::Gdi::BitBlt
    // ■ CreatePen           ... windows::Win32::Graphics::Gdi::CreatePen
    // ■ EndPaint            ... windows::Win32::Graphics::Gdi::EndPaint
    // ■ LineTo              ... windows::Win32::Graphics::Gdi::LineTo
    // ■ MoveToEx            ... windows::Win32::Graphics::Gdi::MoveToEx
    // ■ PS_SOLID            ... windows::Win32::Graphics::Gdi::PS_SOLID
    // ■ PAINTSTRUCT         ... windows::Win32::Graphics::Gdi::PAINTSTRUCT
    // ■ SelectObject        ... windows::Win32::Graphics::Gdi::SelectObject
    // ■ SRCCOPY             ... windows::Win32::Graphics::Gdi::SRCCOPY
    
    
    // ■ CreateWindowExA     ... windows::Win32::UI::WindowsAndMessaging::CreateWindowExA
    // ■ CS_HREDRAW          ... windows::Win32::UI::WindowsAndMessaging::CS_HREDRAW
    // ■ CS_VREDRAW          ... windows::Win32::UI::WindowsAndMessaging::CS_VREDRAW
    // ■ CW_USEDEFAULT       ... windows::Win32::UI::WindowsAndMessaging::CW_USEDEFAULT
    // ■ DefWindowProcA      ... windows::Win32::UI::WindowsAndMessaging::DefWindowProcA
    // ■ DispatchMessageA    ... windows::Win32::UI::WindowsAndMessaging::DispatchMessageA
    // ■ GetMessageA         ... windows::Win32::UI::WindowsAndMessaging::GetMessageA
    // ■ LoadCursorW         ... windows::Win32::UI::WindowsAndMessaging::LoadCursorW
    // ■ IDC_ARROW           ... windows::Win32::UI::WindowsAndMessaging::IDC_ARROW
    // ■ MSG                 ... windows::Win32::UI::WindowsAndMessaging::MSG
    // ■ PostQuitMessage     ... windows::Win32::UI::WindowsAndMessaging::PostQuitMessage
    // ■ RegisterClassA      ... windows::Win32::UI::WindowsAndMessaging::RegisterClassA
    // ■ WNDCLASSA           ... windows::Win32::UI::WindowsAndMessaging::WNDCLASSA
    // ■ WS_OVERLAPPEDWINDOW ... windows::Win32::UI::WindowsAndMessaging::WS_OVERLAPPEDWINDOW
    // ■ WS_VISIBLE          ... windows::Win32::UI::WindowsAndMessaging::WS_VISIBLE
    
    
    // ■ PCSTR               ... windows::core::PCSTR
    
    
    
    
    extern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
    
    
        unsafe {
            
            let rectnullptr: Option<*const RECT> = None;
    
    
            match message as u32 {
                WM_CREATE => {
    
                    let refmydib = &mut mydib.lock().unwrap();
                    refmydib.create(640,480);
    
                    let hPen =
                    CreatePen(
                        PS_SOLID, 
                        1,
                        COLORREF(0x000000FF)
                    );  // 赤いペンを作成
    
    
                    if hPen.is_invalid() == false{
                        // ペンが作成できていたら線を引く
    
                        let oldPen = SelectObject(
                            refmydib.hMemDC,
                            hPen
                        );
    
                        // refmydib.hMemDC の 50,50 ~ 100,100 に線を引く
                        MoveToEx(
                            refmydib.hMemDC,
                            50,
                            50,
                            None as Option<*mut POINT>
                        );
                        LineTo(
                            refmydib.hMemDC,
                            100,
                            100
                        );
    
                        SelectObject(
                            refmydib.hMemDC,
                            oldPen
                        );
    
                        // ペンを削除
                        DeleteObject(hPen);
    
                    }
    
                    LRESULT(0)
                }
                WM_PAINT => {
    
                    let mut ps = PAINTSTRUCT::default();
                    let hdc = BeginPaint(window, &mut ps);
                    let refmydib = &mut mydib.lock().unwrap();
    
                    BitBlt(
                        hdc,
                        0,
                        0,
                        640,
                        480,
                        refmydib.hMemDC,
                        0,
                        0,
                        SRCCOPY
                    );
    
                    EndPaint(window, &ps);
    
                    LRESULT(0)
                }
                WM_DESTROY => {
    
                    PostQuitMessage(0);
    
                    LRESULT(0)
                }
                _ => DefWindowProcA(window, message, wparam, lparam),
            }
        }
    }
    
    
    
    /// 自作 WinMain
    pub fn WinMain(
            hInstance : HINSTANCE, 
            hPrevInstance : HINSTANCE, 
            lpCmdLine:Vec<String>, 
            nCmdShow:i32
        )->i32{
    
        unsafe{
    
    
    
            let _hCursor = LoadCursorW(None,IDC_ARROW).unwrap();
            let _hInstance = hInstance;
            let _lpszClassName = PCSTR::from_raw("MY_NEW_WINDOW\0".as_ptr());
            let _style = CS_HREDRAW | CS_VREDRAW;
    
            // https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/UI/WindowsAndMessaging/struct.WNDCLASSA.html
            let wc=WNDCLASSA{
                hCursor :_hCursor,
                hInstance: _hInstance,
                lpszClassName: _lpszClassName,
                style: _style,
                lpfnWndProc: Some(wndproc),
                ..Default::default()
            };
    
            let atom = RegisterClassA(&wc);
            debug_assert!(atom != 0);
    
    
            let nullptr: Option<*const ::core::ffi::c_void> = None;
    
            CreateWindowExA(
                Default::default(),
                _lpszClassName,
                PCSTR::from_raw("This is a sample window\0".as_ptr()),
                WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                None,
                None,
                _hInstance,
                nullptr,
            );
    
            let mut message = MSG::default();
    
            while GetMessageA(&mut message, HWND(0), 0, 0).into() {
                DispatchMessageA(&mut message);
            }
        }
        return 0;
    
    
    }
    

    Rustでグローバル変数を作る

    Rustのグローバル変数(可変)について調べた話。正直自信がない。

    use once_cell::sync::Lazy; // 1.3.1
    use std::sync::Mutex;
    
    
    struct Foo {
      a: i32,
      b: i32,
    }
    impl Foo{
      fn new() -> Foo {
        Foo {
          a: 1,
          b: 1,
        }
      }
    }
    

    // グローバル変数
    static myGlobal: Lazy<Mutex<Foo>> = 
          Lazy::new(|| 
            Mutex::new(
              Foo::new()
            )
          );
    

    fn call_1(){
    
      let mut myg: std::sync::MutexGuard<'_, Foo> = myGlobal.lock().unwrap();
    
      myg.a += 1;
    }
    

    fn call_2(){
     
      let mut myg: std::sync::MutexGuard<'_, Foo> = myGlobal.lock().unwrap();
    
      myg.a += 1;
    }
    

    fn main() {
    
      call_1();
      call_2();
    
      // myGlobal のミューテックスガードを取得  
      let mut myg: std::sync::MutexGuard<'_, Foo> = myGlobal.lock().unwrap();
    
      myg.a += 1;
    
    
      println!("myg.a= {} , myg.b= {} ", myg.a,myg.b );
    
    }
    

     

     

    [package]
    name = "rs-static"
    version = "0.1.0"
    edition = "2021"

    # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

    [dependencies]
    once_cell = "1.3.1"

     

    解説

    1. staticをつける

    グローバル変数はstaticをつけなければならない

    しかし、staticで定義できるのは定数のみ。従ってstaticだけではかなり限定的な使い方しかできない。

    2.Mutexを使う

    Mutexをつけると、

    1.スレッドセーフになるのでunsafeをつけなくてもよくなる

    2.内部可変性パターンにより、変数をmutableにできる

    これにより、staticをつけながら可変な変数を定義できる。

    つまり、可変なグローバル変数はMutexが必要

    3.Lazyを使う

    Lazyは変数を遅延初期化するための機能。遅延初期化は、変数へ最初にアクセスしたときに初期化が発生するようにする。

    初期化のタイミングをコントロールするためには、Lazyが必要

    正直、なくても動かすことはできる。

    少なくとも、今回の小規模なプログラムに関しては。

    ただ、初期化のタイミングがコンパイル時になる。さらにMutex::new()に与える引数が定数でなければならなくなるため、わざわざconst fnをimplしないといけなくなる。

    4.Lazyの || とは

    lazyの || は無名関数を定義するためのもので、以下のように使用する。引数、戻り値型は省略可。処理を括る{}も省略できる。

    fn main() {
    
      // let func = | 引数 | -> 戻り値型{処理};
    
      let func = 
            | x:i32 , y:i32 | -> f32 
            {
              ( x + y ) as f32 
            };
    
      let a = func(1,2);
    
      println!("a = {} ", a );
    
    }
    

    5.Lazyなし版

    // use once_cell::sync::Lazy; //Lazyは必須ではない
    use std::sync::Mutex;
    
    struct Foo {
      a: i32,
      b: i32,
    }
    impl Foo{
      fn new() -> Foo {
        Foo {
          a: 1,
          b: 1,
        }
      }
      const fn new_const() -> Foo {// constをつけて定数のFooを返せる
        Foo {
          a: 1,
          b: 1,
        }
      }
    }
    
    
    // グローバル変数
    // Lazyがないときは new_constにしなければいけない
    static myGlobal: Mutex<Foo> = 
            Mutex::new(
              Foo::new_const()
          );
    
    // 以下同じ
    

    ほかの例

    Vecの例

    use once_cell::sync::Lazy;
    use std::sync::Mutex;
    
    // グローバル変数
    static myGlobal: Lazy<Mutex<Vec<i32> > >= 
          Lazy::new(|| Mutex::new(
              vec![]
          ));
    
    
    fn call_1(){
    
      let mut myg:std::sync::MutexGuard<'_, Vec<i32>> = myGlobal.lock().unwrap();
    
      myg.push(1);
    
    }
    

    Boxの例

    use once_cell::sync::Lazy;
    use std::sync::Mutex;
    
    
    #[derive(Debug)]
    struct Foo {
      a: i32,
      b: i32,
    }
    impl Foo{
      fn new() -> Foo {
        Foo {
          a: 1,
          b: 1,
        }
      }
    }
    
          
    // グローバル変数
    static myGlobal: Lazy<Mutex<Box<Foo> > >= 
          Lazy::new(|| Mutex::new(
              Box::new(Foo::new())
          ));
    
    fn call_1(){
    
      let mut myg:std::sync::MutexGuard<'_, Box<Foo>> = myGlobal.lock().unwrap();
    
      myg.a += 1;
    
    }
    

    Win32API + wxWidgetsでアイコンを取得・表示

    wxWidgetsでアイコンを表示したい。

    HICONを wxIcon::CreateFromHICON関数でwxWidgetsのwxIconへ変換。これをさらにwxBitmapに変換する。

    // https://docs.wxwidgets.org/3.0/overview_helloworld.html
    
    // プリプロセッサに以下二つを追加
    // __WXMSW__
    // WXUSINGDLL
    
    // サブシステムをWindowsに設定(WinMainで呼び出すので)
    // Windows (/SUBSYSTEM:WINDOWS)
    
    #ifndef WX_PRECOMP
    #include <wx/wx.h>
    #endif
    
    #include <wx/frame.h>  // wxFrameに必要
    
    // デバッグとリリースでライブラリを分ける
    #ifdef _DEBUG
    #pragma comment(lib,"wxbase32ud.lib")
    #pragma comment(lib,"wxbase32ud_net.lib")
    #pragma comment(lib,"wxbase32ud_xml.lib")
    #pragma comment(lib,"wxmsw32ud_adv.lib")
    #pragma comment(lib,"wxmsw32ud_aui.lib")
    #pragma comment(lib,"wxmsw32ud_core.lib")
    #pragma comment(lib,"wxmsw32ud_gl.lib")
    #pragma comment(lib,"wxmsw32ud_html.lib")
    #pragma comment(lib,"wxmsw32ud_media.lib")
    #pragma comment(lib,"wxmsw32ud_propgrid.lib")
    #pragma comment(lib,"wxmsw32ud_qa.lib")
    #pragma comment(lib,"wxmsw32ud_ribbon.lib")
    #pragma comment(lib,"wxmsw32ud_richtext.lib")
    #pragma comment(lib,"wxmsw32ud_stc.lib")
    #pragma comment(lib,"wxmsw32ud_webview.lib")
    #pragma comment(lib,"wxmsw32ud_xrc.lib")
    
    #else
    
    #pragma comment(lib,"wxbase32u.lib")
    #pragma comment(lib,"wxbase32u_net.lib")
    #pragma comment(lib,"wxbase32u_xml.lib")
    #pragma comment(lib,"wxmsw32u_adv.lib")
    #pragma comment(lib,"wxmsw32u_aui.lib")
    #pragma comment(lib,"wxmsw32u_core.lib")
    #pragma comment(lib,"wxmsw32u_gl.lib")
    #pragma comment(lib,"wxmsw32u_html.lib")
    #pragma comment(lib,"wxmsw32u_media.lib")
    #pragma comment(lib,"wxmsw32u_propgrid.lib")
    #pragma comment(lib,"wxmsw32u_qa.lib")
    #pragma comment(lib,"wxmsw32u_ribbon.lib")
    #pragma comment(lib,"wxmsw32u_richtext.lib")
    #pragma comment(lib,"wxmsw32u_stc.lib")
    #pragma comment(lib,"wxmsw32u_webview.lib")
    #pragma comment(lib,"wxmsw32u_xrc.lib")
    
    #endif
    
    
    #include <commctrl.h>
    #pragma comment(lib, "comctl32.lib")
    
    // IID_IImageList に必要
    #include <commoncontrols.h>
    
    
    // アイコンを取得
    wxBitmap my_get_icon(const wchar_t* path) {
    
      wxBitmap ret;
    
      // システムイメージリストの取得
      HIMAGELIST hImageList;
      HRESULT hr = SHGetImageList(SHIL_JUMBO, IID_IImageList, (void**)&hImageList);
      // SHIL_JUMBO     256x256 
    
      if (SUCCEEDED(hr)) {
    
        SHFILEINFO shfi;
        memset(&shfi, 0, sizeof(SHFILEINFO));
    
        // path からアイコンの「イメージリスト上のインデクス」を取得
        // ※ アイコンハンドルではない
        SHGetFileInfo(path, 0, &shfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX);
        HICON hicon = ImageList_GetIcon(hImageList, shfi.iIcon, ILD_NORMAL);
    
        // wxWidgetsのwxIconに変換
        wxIcon computerIcon;
        computerIcon.CreateFromHICON((WXHICON)hicon);
        ret = wxBitmap(computerIcon);
    
        // wxBitmapに変換してからDestryIconする
        DestroyIcon(hicon);
    
      }
    
      return ret;
    
    }
    
    /////////////////////////////////////
    /////////////////////////////////////
    /////////////////////////////////////
    
    // ウィンドウ作成
    class MyFrame : public wxFrame
    {
    
      wxBitmap mybmp_drive;
      wxBitmap mybmp_file;
      wxBitmap mybmp_doc;
    public:
    
    
      MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
        : wxFrame(NULL, wxID_ANY, title, pos, size)
      {
        SetBackgroundColour(*wxWHITE);
    
    
        mybmp_drive = my_get_icon( L"C:\\");
        mybmp_file = my_get_icon(L"C:\\Windows\\System32\\notepad.exe");
        mybmp_doc = my_get_icon(L"C:\\Users\\Public\\Documents\\desktop.ini");
    
    
        // PAINTイベントをバインド
        Bind(wxEVT_PAINT, &MyFrame::OnPaint, this);
      }
    
      // PAINTイベントのハンドラ
      void OnPaint(wxPaintEvent& event) {
        wxPaintDC dc(this);
    
        if (mybmp_drive.IsOk()) {
          dc.DrawBitmap(mybmp_drive, 5+0, 5, false);
        }
        if (mybmp_file.IsOk()) {
          dc.DrawBitmap(mybmp_file, 5 + 256*1, 5, false);
        }
        if (mybmp_doc.IsOk()) {
          dc.DrawBitmap(mybmp_doc, 5 + 256*2, 5, false);
        }
      }
    
    };
    
    
    /////////////////////////////////////
    /////////////////////////////////////
    /////////////////////////////////////
    
    // wxWidgetsのアプリケーション作成
    class MyApp : public wxApp {
    public:
    
      virtual bool OnInit() {
        MyFrame* frame = new MyFrame("Hello World", wxPoint(50, 50), wxSize(1000, 340));
        frame->Show(true);
    
        return true;
      }
    
    };
    
    /////////////////////////////////////
    /////////////////////////////////////
    /////////////////////////////////////
    
    // WinMainをマクロで定義
    wxIMPLEMENT_APP(MyApp);
    

    SHGetFileInfoでアイコンを取得(2) 大きなアイコン,コンピュータアイコンなど

    256x256のアイコンを取得

    #include<windows.h>
    #include<tchar.h>
    
    // HIMAGELIST
    // ImageList_GetIcon
    #include <commctrl.h>
    #pragma comment(lib, "comctl32.lib")
    
    
    // IID_IImageList に必要
    #include <commoncontrols.h>
    
    #include <cstdio>
    #pragma warning(disable:4996)
    
    // アイコンを取得
    HICON my_get_icon(const wchar_t* path) {
    
    
      // システムイメージリストの取得
      HIMAGELIST hImageList;
      HRESULT hr = SHGetImageList(SHIL_JUMBO , IID_IImageList, (void**)&hImageList);
      // SHIL_JUMBO       256x256 
      // SHIL_EXTRALARGE  48x48
      // SHIL_LARGE       32x32
      // SHIL_SMALL       16x16
    
      // hrからファイルのアイコンを取得
      if (SUCCEEDED(hr)) {
    
        SHFILEINFO shfi;
        memset(&shfi, 0, sizeof(SHFILEINFO));
    
        // path からアイコンの「イメージリスト上のインデクス」を取得
        // ※ アイコンハンドルではない
        SHGetFileInfo(path, 0, &shfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX);
        
        // SHGetImageListで取得したイメージリストから
        // SHGetFileInfoで取得したインデクスを指定してアイコンハンドルを取得
        HICON hicon = ImageList_GetIcon(hImageList, shfi.iIcon, ILD_NORMAL);
    
        // ※ hiconは使わなくなったら DestroyIcon で破棄すること
    
        return hicon;
    
      }
    
    }
    

    コンピュータアイコン

    #include<windows.h>
    #include<tchar.h>
    
    // HIMAGELIST
    // ImageList_GetIcon
    // 表示用に ImageList_Draw も使える
    #include <commctrl.h>
    #pragma comment(lib, "comctl32.lib")
    
    // SHGetSpecialFolderLocation
    // SHGetFolderLocation
    #include <ShlObj.h>
    
    
    #include <cstdio>
    #pragma warning(disable:4996)
    
    
    // アイコンを取得
    HICON my_get_special_icon() {
    
    #if 0
      // 注: SHGetSpecialFolderLocation は非推奨
      // https://learn.microsoft.com/ja-jp/windows/win32/api/shlobj_core/nf-shlobj_core-shgetspecialfolderlocation
      PIDLIST_ABSOLUTE pidl;
      HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_FONTS, &pidl);
    
    #else
      LPITEMIDLIST pidl;
      // マイコンピュータのPIDLを取得
      HRESULT hr = SHGetFolderLocation(NULL, CSIDL_DRIVES, NULL, 0, &pidl);
    
      // CSIDL_DRIVES マイコンピュータアイコン
      // CSIDL_FONTS フォントアイコン
      // CSIDL_DESKTOP デスクトップアイコン
      // ... etc
    
    #endif
    
    
      SHFILEINFO shfi;
    
      memset(&shfi, 0, sizeof(SHFILEINFO));
    
      DWORD_PTR ret = SHGetFileInfoW(// イメージリストとその中のpidlで指定したアイコンのidを取得
        (LPCTSTR)pidl,
        0,
        &shfi,
        sizeof(SHFILEINFO),
        SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_LARGEICON);
    
      HIMAGELIST imagelist = (HIMAGELIST)ret;
    
      // アイコンリストが取得できたかどうかを表す
      if (imagelist != nullptr) {
    
        // imagelistからアイコンを取得
        // ImageList_GetIconはアイコンのコピーを渡すので、後でDestroyIconが必要
        HICON hicon = ImageList_GetIcon(imagelist, shfi.iIcon, ILD_NORMAL);
    
    
        // SHGFI_SYSICONINDEX を指定した場合、hIconは無効
        //DestroyIcon(shfi.hIcon);
    
        return hicon;// コピーしたアイコンを返す
    
      }
      return NULL;
    }
    

    LRESULT
    CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { PAINTSTRUCT ps; HDC hdc; // アイコン static HICON myicon; switch (msg) { case WM_CREATE: // コピーしたアイコンを取得 myicon = my_get_special_icon(); return 0; case WM_DESTROY: // コピーしたアイコンを破棄 DestroyIcon(myicon); PostQuitMessage(0); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); // アイコンを描画 DrawIconEx(hdc, 0 + 10, 10, myicon, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT); EndPaint(hwnd, &ps); return 0; } return DefWindowProc(hwnd, msg, wp, lp); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow) { HWND hwnd; WNDCLASS winc; MSG msg; 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("SZL-WND"); if (!RegisterClass(&winc)) return 0; hwnd = CreateWindow( TEXT("SZL-WND"), TEXT("icon test"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, NULL, NULL, hInstance, NULL ); if (hwnd == NULL) return 0; while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg); return msg.wParam; }

    SHGetFileInfoでアイコンを取得(1)

    WindowsでSHGetFileInfoでアイコンを取得する方法。

    • 引数にSHGFI_ICON を指定した場合
      • アイコン(HICON)が取得できるので、そのアイコンを使用。
      • 使用後はDestroyIconで破棄
    • 引数にSHGFI_SYSICONINDEX を指定した場合
      • 戻り値にIMAGELIST、SHFILEINFOのiIconにそのIMAGELIST内のアイコンの識別子が取得できる
      • hIconは無効なので使ってはいけない
      • IMAGELISTはシステムが管理しているので破棄してはいけない

    SHGFI_SYSICONINDEXを指定した場合、同じアイコンはiIconが同じになるので、テーブルを作っておけばメモリを節約できる。

    DrawIconEx

    ちなみに下で、アイコンの描画はDrawIconを使っているが、これはアイコン本来のサイズで描画してくれないので、動作確認のためにはDrawIconExを使ったほうが良い。

    DrawIconExに、第五、第六、第七引数に0を指定し、且つ DI_NORMAL | DI_COMPAT をつけて描画すると、アイコンの本来のサイズで描画できる。

    DrawIconEx(hdc, 0 + 10, 10,  icondrive, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT);
    DrawIconEx(hdc, 32 + 10, 10, iconfolder, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT);
    DrawIconEx(hdc, 64 + 10, 10, iconfile, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT);
    DrawIconEx(hdc, 96 + 10, 10, iconexe, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT);
    

    1.アイコンを取得

    本来ならCopyIconしないでそのまま返して、WM_DESTROYのところでDestroyIconすればいいが、「SHGFI_ICONで取得したアイコンはDestroyIconが必要」ということを強調するためにあえて行っている。

    #include<windows.h>
    #include<tchar.h>
    
    #include <cstdio>
    #pragma warning(disable:4996)
    
    
    // アイコンを取得
    HICON my_get_icon(const wchar_t* path) {
    
      SHFILEINFO shfi;
    
      memset(&shfi, 0, sizeof(SHFILEINFO));
    
      DWORD_PTR ret = SHGetFileInfoW(// アイコンを取得
        path,
        0,
        &shfi,
        sizeof(SHFILEINFO),
        SHGFI_ICON | /* SHGFI_SYSICONINDEX | */ SHGFI_LARGEICON);
      
      // retはアイコンが取得できたかどうかを表す
      if (SUCCEEDED(ret)) {
    
        // アイコンをコピー
        HICON hicon = CopyIcon(shfi.hIcon);
    
        // SHGFI_ICON を指定しているので取得したのはアイコン
        // なのでDestroyIconで破棄する
        DestroyIcon(shfi.hIcon);
    
        return hicon;// コピーしたアイコンを返す
    
      }
      return NULL;
    }
    
          
          
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
      PAINTSTRUCT ps;
      HDC hdc;
    
      // アイコン一覧
      static HICON icondrive;
      static HICON iconfolder;
      static HICON iconfile;
      static HICON iconexe;
    
      switch (msg) {
      case WM_CREATE:
        // コピーしたアイコンを取得
        icondrive = my_get_icon(L"C:\\");
        iconfolder = my_get_icon(L"C:\\Windows");
        iconfile = my_get_icon(L"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.35.32215\\atlmfc\\include\\afx.h");
        iconexe = my_get_icon(L"C:\\Windows\\notepad.exe");
    
        return 0;
      case WM_DESTROY:
    
        // コピーしたアイコンを破棄
        DestroyIcon(icondrive);
        DestroyIcon(iconfolder);
        DestroyIcon(iconfile);
        DestroyIcon(iconexe);
    
        PostQuitMessage(0);
        return 0;
      case WM_PAINT:
    
        hdc = BeginPaint(hwnd, &ps);
    
        // アイコンを描画
        DrawIcon(hdc,  0+10, 10, icondrive);
        DrawIcon(hdc, 32+10, 10, iconfolder);
        DrawIcon(hdc, 64+10, 10, iconfile);
        DrawIcon(hdc, 96+10, 10, iconexe);
    
        EndPaint(hwnd, &ps);
    
        return 0;
    
      }
      return DefWindowProc(hwnd, msg, wp, lp);
    }
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
      PSTR lpCmdLine, int nCmdShow) {
      HWND hwnd;
      WNDCLASS winc;
      MSG msg;
    
      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("SZL-WND");
    
      if (!RegisterClass(&winc)) return 0;
    
    
    
      hwnd = CreateWindow(
        TEXT("SZL-WND"), TEXT("icon test"),
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT,
        300, 100,
        NULL, NULL,
        hInstance, NULL
      );
    
      if (hwnd == NULL) return 0;
    
      while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg);
      return msg.wParam;
    }
    

    2.アイコンリストを取得してからアイコン取得

    よく考えたらImageList_GetIconの時もDestroyIconが必要なので上と合わせるべきなのだが間違っているわけではないというかむしろこちらが正攻法だと思うのでこのままにしておく。

    #include<windows.h>
    #include<tchar.h>
    
    // HIMAGELIST
    // ImageList_GetIcon
    // 表示用に ImageList_Draw も使える
    #include <commctrl.h>
    #pragma comment(lib, "comctl32.lib")
    
    #include <cstdio>
    #pragma warning(disable:4996)
    
    // アイコンを取得
    HICON my_get_icon(const wchar_t* path) {
    
      SHFILEINFO shfi;
    
      memset(&shfi, 0, sizeof(SHFILEINFO));
    
      DWORD_PTR ret = SHGetFileInfoW(
        path,
        0,
        &shfi,
        sizeof(SHFILEINFO),
        /*SHGFI_ICON |*/ SHGFI_SYSICONINDEX | SHGFI_LARGEICON);
    
      HIMAGELIST imagelist = (HIMAGELIST)ret;
      
      // アイコンリストが取得できたかどうかを表す
      if (imagelist != nullptr) {
    
        // imagelistからアイコンを取得
        // ImageList_GetIconはアイコンのコピーを渡すので、後でDestroyIconが必要
        HICON hicon = ImageList_GetIcon(imagelist, shfi.iIcon, ILD_NORMAL);
    
    
        // SHGFI_SYSICONINDEX を指定した場合、hIconは無効
        //DestroyIcon(shfi.hIcon);
    
        return hicon;// コピーしたアイコンを返す
    
      }
      return NULL;
    }
    
    /* 上と同じ */
    

    wxGLCanvasでglewを使用する

    wxGLCanvasでglewを使用するとき、glewInit()の呼び出しに失敗する場合がある。

    例えば以下のようなコードを書くと、エラーメッセージを取得できる。

    GLenum err = glewInit();
    if (err != GLEW_OK) {
        std::string msg = (const char*)glewGetErrorString(err);
        std::cerr << "Error: " << msg << std::endl;
    }
    
    Missing GL version

    これはOpenGLのコンテキストがまだ作成されていないのにglewInit()を呼んでしまったからである。

    これを回避する確実な方法は、glewInit()の呼び出しをwxEVT_PAINTの処理時にすることらしい。

    つまり描画の最初の一回目でglewInit()する。

    Canvasのコンストラクタ

    BindでwxEVT_PAINT時にRender関数が呼ばれるように設定する。

    MyGLCanvas::MyGLCanvas(wxFrame* parent) :
        wxGLCanvas(parent, wxID_ANY), m_context(new wxGLContext(this))
    {
    
        Bind(wxEVT_PAINT, &MyGLCanvas::Render, this);
    
        /* ... */
    
    }
    

    描画関数

    描画関数。SetCurrentした後でglewInit()する。

    void MyGLCanvas::Render(wxPaintEvent& evt) {
        if (!IsShown()) return;
    
        wxGLCanvas::SetCurrent(*m_context);
    
        if (glew_inistialized == false) {// 初期化は一回だけでいいのでフラグで制御
            GLenum err = glewInit();
            if (err != GLEW_OK) {
    // エラーの場合はエラー内容を表示
    std::string msg = (const char*)glewGetErrorString(err); std::cerr << "Error: " << msg << std::endl; } else { glew_inistialized = true;// 二回呼び出されないようにフラグを立てる } } wxPaintDC(this); int w, h; GetClientSize(&w, &h); glViewport(0, 0, w, h); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* 略 */ glFlush(); SwapBuffers(); }

    libファイルを一つにまとめる

    wxWidgetsを使用するときに、.libファイルを大量にリンクしなければならない。この問題を解決するために、無数にある.libファイルを一つのファイルにまとめてしまうことができる。

    まず、以下のようにmulti-lib/ フォルダ内にwxWidgetsの.libファイルが入っているとする。

    D:.
    └─multi-lib/
            wxbase33u.lib
            wxbase33u_net.lib
            wxbase33u_xml.lib
            wxexpat.lib
            wxjpeg.lib
            wxlexilla.lib
            wxmsw33u_adv.lib
            wxmsw33u_aui.lib
            wxmsw33u_core.lib
            wxmsw33u_gl.lib
            wxmsw33u_html.lib
            wxmsw33u_media.lib
            wxmsw33u_propgrid.lib
            wxmsw33u_qa.lib
            wxmsw33u_ribbon.lib
            wxmsw33u_richtext.lib
            wxmsw33u_stc.lib
            wxmsw33u_webview.lib
            wxmsw33u_xrc.lib
            wxpng.lib
            wxregexu.lib
            wxscintilla.lib
            wxtiff.lib
            wxzlib.lib
    

    複数のライブラリを一つにまとめるには、lib.exeを使用する。

    lib.exe /OUT:纏めたファイル名.lib ライブラリ1.lib ライブラリ2.lib
    

    まず、 x64 Native Tools Command Prompt for VS 2022 を開いて、Visual Studioのツールを使えるようにする。

    そして、以下のように入力してcombined_wx.libを作成する。カレントディレクトリに出力されるので、この例だとmulti-lib/combined_wx.libが作成される。

    > cd multi-lib
    > lib.exe /OUT:combined_wx.lib *.lib

     

    使用例

    特に注意するところはない。普通に使用できる。

    // プリプロセッサに以下を追加
    // __WXMSW__
    
    // static link library の場合、以下は指定しない
    // WXUSINGDLL
    
    // サブシステムをWindowsに設定(WinMainで呼び出すので)
    // Windows (/SUBSYSTEM:WINDOWS)
    
    #ifndef WX_PRECOMP
    #include <wx/wx.h>
    #endif
    
    #include <wx/gdicmn.h> // wxPointに必要
    #include <wx/frame.h>  // wxFrameに必要
    
    // Win32 API
    #pragma comment(lib, "comctl32.lib")
    #pragma comment(lib, "rpcrt4.lib")
    
    #if 1
    
    // 一つに纏めた.libファイル群
    #pragma comment(lib,"combined_wx.lib")
    
    #else
    // 本来使用する.libファイル群
    #pragma comment(lib,"wxmsw33u_core.lib")
    #pragma comment(lib,"wxbase33u.lib")
    #pragma comment(lib,"wxbase33u_net.lib")
    #pragma comment(lib,"wxbase33u_xml.lib")
    #pragma comment(lib,"wxexpat.lib")
    #pragma comment(lib,"wxjpeg.lib")
    #pragma comment(lib,"wxlexilla.lib")
    #pragma comment(lib,"wxmsw33u_adv.lib")
    #pragma comment(lib,"wxmsw33u_aui.lib")
    #pragma comment(lib,"wxmsw33u_gl.lib")
    #pragma comment(lib,"wxmsw33u_html.lib")
    #pragma comment(lib,"wxmsw33u_media.lib")
    #pragma comment(lib,"wxmsw33u_propgrid.lib")
    #pragma comment(lib,"wxmsw33u_qa.lib")
    #pragma comment(lib,"wxmsw33u_ribbon.lib")
    #pragma comment(lib,"wxmsw33u_richtext.lib")
    #pragma comment(lib,"wxmsw33u_stc.lib")
    #pragma comment(lib,"wxmsw33u_webview.lib")
    #pragma comment(lib,"wxmsw33u_xrc.lib")
    #pragma comment(lib,"wxpng.lib")
    #pragma comment(lib,"wxregexu.lib")
    #pragma comment(lib,"wxscintilla.lib")
    #pragma comment(lib,"wxtiff.lib")
    #pragma comment(lib,"wxzlib.lib")
    
    #endif
    
    /////////////////////////////////////
    /////////////////////////////////////
    /////////////////////////////////////
    
    // ウィンドウ作成
    class MyFrame : public wxFrame
    {
    public:
        MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
            : wxFrame(NULL, wxID_ANY, title, pos, size)
        {
        }
    
    private:
    
        // イベント処理しないときはこれを入れない
        // wxDECLARE_EVENT_TABLE();
    };
    
    /////////////////////////////////////
    /////////////////////////////////////
    /////////////////////////////////////
    
    // wxWidgetsのアプリケーション作成
    class MyApp : public wxApp {
    public:
    
        virtual bool OnInit() {
            MyFrame* frame = new MyFrame("Hello World", wxPoint(50, 50), wxSize(450, 340));
            frame->Show(true);
            return true;
        }
    
    };
    
    /////////////////////////////////////
    /////////////////////////////////////
    /////////////////////////////////////
    
    // WinMainをマクロで定義
    wxIMPLEMENT_APP(MyApp);
    

    0(8) : error C7528: OpenGL reserves names starting with ‘gl_’: gl_ModelViewMatrix

    比較的最近のGLSLでは、gl_ModelViewMatrix、gl_ProjectionMatrixという名前の変数を定義するとエラーになる。正確には、「先頭に gl_ がついている変数名はコンパイルエラーになる」。

    glTranslatedなどが使用できないとか以前に、「変数名によってエラーになる」ことが問題。例えば以下のようなコードを書くと、コンパイルエラーが発生する。

    #version 330 core
    
    layout (location = 0) in vec3 aPos;
    layout (location = 1) in vec3 incolor;
    
    out vec4 vertexColor;
    
    uniform mat4 gl_ModelViewMatrix;
    uniform mat4 gl_ProjectionMatrix;
    
    void main()
    {
      gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(aPos, 1.0);
      vertexColor = vec4(incolor, 1.0);
    }
    
    Compiling shader : C:\test\verts.sh
    0(8) : error C7528: OpenGL reserves names starting with 'gl_': gl_ModelViewMatrix
    0(9) : error C7528: OpenGL reserves names starting with 'gl_': gl_ProjectionMatrix

    ただし、上の場合、gl_Positionは自分で定義しているわけではないのでエラーにならない。

    解決策

    gl_が頭についていない変数を使えばよい。ところで、gl_ModelViewMatrixやgl_ProjectionMatrixは、glMatrixMode→glTranslatef等で渡された行列の可能性がある。これが使えなくなるので、行列は自分で計算しなければいけない。面倒なのでglmを使用することになる。

    頂点シェーダ

    #version 330 core
    
    layout (location = 0) in vec3 aPos;
    layout (location = 1) in vec3 incolor;
    
    out vec4 vertexColor;
    
    uniform mat4 MyModelViewMatrix;
    uniform mat4 MyProjectionMatrix;
    
    void main()
    {
      gl_Position = MyProjectionMatrix * MyModelViewMatrix * vec4(aPos, 1.0);
      vertexColor = vec4(incolor, 1.0);
    }
    

    C++側

    glUseProgram(ProgramID);
    
    // これの代わりに glGetUniformLocation + glUniformMatrix4fv
    // 
    //glMatrixMode(GL_MODELVIEW);
    //glLoadMatrixf(glm::value_ptr(projectionMatrix));
    //glMatrixMode(GL_MODELVIEW);
    //glLoadMatrixf(glm::value_ptr(modelViewMatrix));
    
    glm::mat4 modelViewMatrix;  // モデルビュー行列の計算
    static int theta = 0.0f;
    modelViewMatrix = glm::rotate(
    	glm::mat4(1.0),
    	glm::radians((float)theta),
    	glm::vec3(0.0, 0.0, 1.0)
    );
    theta += 5;
    
    glm::mat4 projectionMatrix = glm::mat4(1.0);  // 投影行列の計算
    
    
    GLint modelViewMatrixID = glGetUniformLocation(ProgramID, "MyModelViewMatrix");
    GLint projectionMatrixID = glGetUniformLocation(ProgramID, "MyProjectionMatrix");
    
    glUniformMatrix4fv(modelViewMatrixID, 1, GL_FALSE, glm::value_ptr(modelViewMatrix));
    glUniformMatrix4fv(projectionMatrixID, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
    

    余談

    なんか前にも書いた気がするのだが、日本語の検索結果があまり出てこなかったのでここにまとめておく。

    mesonでVC++のsolutionを作る話

    meson.build作成したうえで、以下のように実行する

    meson setup 出力ディレクトリ --buildtype=モード --backend=vs

    例:

    meson setup release_build --buildtype=release --backend=vs

     

    注意:

    releaseとdebugを同時に指定できない。release用.slnとdebug用.slnを別々に作る必要がある。

     

    meson setup release_build --buildtype=release --backend=vs

    meson setup debug_build --buildtype=debug --backend=vs

     

     

    サンプルコード

    #include<windows.h>
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
      HDC hdc;
      switch (msg) {
      case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
      }
      return DefWindowProc(hwnd, msg, wp, lp);
    }
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
      PSTR lpCmdLine, int nCmdShow) {
      HWND hwnd;
      WNDCLASS winc;
      MSG msg;
    
      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("SZL-WIN");
    
      if (!RegisterClass(&winc)) return 0;
    
      hwnd = CreateWindow(
        TEXT("SZL-WIN"), TEXT("test"),
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL,
        hInstance, NULL
      );
    
      if (hwnd == NULL) return 0;
    
      while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg);
      return msg.wParam;
    }
    

    C++からwin32apiでWinMainを使うmeson.buildを書いてみる

    WinMainを使う場合、/SUBSYSTEM:WINDOWSを指定する。

    問題は、mesonが勝手に/SUBSYSTEM:CONSOLEをつけてしまうので、エントリポイントがmainなのかWinMainなのかわからなくなりエラーが出る。

    [1/1] Linking target myapp.exe
    FAILED: myapp.exe myapp.pdb
    "link" /MACHINE:x64 /OUT:myapp.exe myapp.exe.p/main.cpp.obj "/nologo" "/release" "/nologo" "/DEBUG" "/PDB:myapp.pdb" "/SUBSYSTEM:WINDOWS" "/SUBSYSTEM:CONSOLE" "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "comdlg32.lib" "advapi32.lib"
    MSVCRTD.lib(exe_main.obj) : error LNK2019: 未解決の外部シンボル main が関数 "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ) で参照されました
    myapp.exe : fatal error LNK1120: 1 件の未解決の外部参照
    ninja: build stopped: subcommand failed.

    これを回避するために、 gui_app: true を指定する。

    project('myapp', 'cpp') cpp = meson.get_compiler('cpp') executable('myapp', 'main.cpp', gui_app: true, # WinMainを使うときはこれが必要 cpp_args: [ '/D_WINDOWS' ], link_args: [ '/SUBSYSTEM:WINDOWS' # WinMainを使うときはこれが必要 ] )

    ビルド

    meson setup build

    meson compile -C build

    の順で実行する。

    	

    (mesonenv) C:\Users\myuser\source\repos\win32>meson setup build Directory already configured. Just run your build command (e.g. ninja) and Meson will regenerate as necessary. If ninja fails, run "ninja reconfigure" or "meson setup --reconfigure" to force Meson to regenerate. If build failures persist, run "meson setup --wipe" to rebuild from scratch using the same options as passed when configuring the build. To change option values, run "meson configure" instead. (mesonenv) C:\Users\myuser\source\repos\win32>meson compile -C build Activating VS 17.5.4 INFO: automatically activated MSVC compiler environment INFO: autodetecting backend as ninja INFO: calculating backend command to run: C:\Users\myuser\anaconda3\envs\mesonenv\Library\bin\ninja.EXE -C C:/Users/szl/source/repos/win32/build ninja: Entering directory `C:/Users/myuser/source/repos/win32/build' [0/1] Regenerating build files. The Meson build system Version: 1.0.1 Source dir: C:\Users\myuser\source\repos\win32 Build dir: C:\Users\myuser\source\repos\win32\build Build type: native build Project name: myapp Project version: undefined C++ compiler for the host machine: cl (msvc 19.35.32217.1 "Microsoft(R) C/C++ Optimizing Compiler Version 19.35.32217.1 for x64") C++ linker for the host machine: link link 14.35.32217.1 Host machine cpu family: x86_64 Host machine cpu: x86_64 Build targets in project: 1 Found ninja-1.10.2 at C:\Users\myuser\anaconda3\envs\mesonenv\Library\bin\ninja.EXE Cleaning... 0 files. [1/1] Linking target myapp.exe

    サンプルコード main.cpp

    #include<windows.h>
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
      HDC hdc;
      switch (msg) {
      case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
      }
      return DefWindowProc(hwnd, msg, wp, lp);
    }
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
      PSTR lpCmdLine, int nCmdShow) {
      HWND hwnd;
      WNDCLASS winc;
      MSG msg;
    
      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("SZL-WIN");
    
      if (!RegisterClass(&winc)) return 0;
    
      hwnd = CreateWindow(
        TEXT("SZL-WIN"), TEXT("test"),
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL,
        hInstance, NULL
      );
    
      if (hwnd == NULL) return 0;
    
      while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg);
      return msg.wParam;
    }