728x90
출처: https://mawile.tistory.com/160
우선은 기본적인 환경설정이 되어있어야합니다!
우선 아래 명령어를 통해서, 기본적인 rust개발에 필요한 환경을 맞추어줍시다!
cargo new [프로젝트명]
그 후, 그 프로젝트폴더경로로 명령프롬프트의 cd명령을 통해 이동을 합니다.
그러면은 Cargo.toml이라는 파일이 만들어졌을겁니다.
다음과같이 "[dependencies]" 항목에 다음과 같이 적어줍니다.
이 부분은 외부로부터 라이브러리를 불러오는 부분입니다.
아래의 라이브러리내용을 알고싶거나, 최신버전을 알고싶다면 밑에 링크로 들어가주세요!!
[dependencies]
winapi = { version = "0.3.8", features = ["winuser", "libloaderapi"] }
user32-sys = "0.2.0"
kernel32-sys = "0.2.2"
이제 본격적으로 작업할 main.rs 파일로 들어가서 맨 위부분부터 다음과 같은 소스코드를 적어줍니다!
use std::io::Error;
use std::mem::{size_of, zeroed};
#[cfg(windows)]
use winapi::shared::minwindef::{UINT, WPARAM, LPARAM, LRESULT, LPVOID, HINSTANCE, LOWORD};
use winapi::shared::windef::{HWND, HMENU, HBRUSH};
use winapi::um::winnt::{LPCSTR, LPCWSTR};
use winapi::um::winuser::{WNDCLASSEXW, LoadCursorW, LoadIconW, GetMessageW, DispatchMessageW, RegisterClassExW, CreateWindowExW, ShowWindow, MessageBoxA, TranslateMessage, DefWindowProcW, PostQuitMessage}; // functions
use winapi::um::winuser::{IDI_APPLICATION, IDC_ARROW, CS_HREDRAW, CS_VREDRAW, WS_EX_TOPMOST, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, WM_DESTROY, SW_SHOWDEFAULT, WM_CREATE, WS_VISIBLE, WS_CHILD, WM_COMMAND}; // const variable
use winapi::um::libloaderapi::GetModuleHandleA;
이 부분을 설명하자면, use는 해당 라이브러리의 클래스, 함수, 열거형을 사용하겠다는 의미입니다.
참고로 위의 winapi::um이라든지, winapi::shared 라든지, 이 라이브러리에 뭐가들었는지 모르겠으신분들은, 위에 링크에서 검색해서 찾아보시면 아주 자세하게 나와있습니다.
그다음 함수들을 적어줍니다.
fn hide_console_window() //콘솔창을 숨기는 함수
{
let window = unsafe { //메모리보호를 강요하지않음 (unsafe)
kernel32::GetConsoleWindow() //콘솔창 핸들값 얻어오기
};
if window != std::ptr::null_mut() { //만약 nullptr이 아닐경우
unsafe {
user32::ShowWindow (window, 0 as winapi::ctypes::c_int) //창 숨기기
};
}
}
#[cfg(windows)] //windows사용명시
fn to_wstring(str: &str) -> Vec<u16> { //str를 winapi의 wide-string으로 변환하는 함수
use std::ffi::OsStr; //문자열 인코딩관련 라이브러리
use std::os::windows::ffi::OsStrExt; //같음
use std::iter::once; //반복자관련 라이브러리
let v: Vec<u16> = OsStr::new(str).encode_wide().chain(once(0).into_iter()).collect(); //인코딩
return v; //반환
}
그다음은 windows 메세지 콜백함수 입니다.
#[cfg(windows)]
unsafe extern "system"
fn wnd_proc(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) -> LRESULT { //__stdcall
match msg { //msg로 패턴매칭
WM_CREATE => { //창생성 메세지
//윈도우옵션에서 WS_EX_TOPMOST지우기 (메세지박스가 잘안보여서요. 이 옵션은 지웠습니다.)
winapi::um::winuser::SetWindowLongW(hwnd, winapi::um::winuser::GWL_EXSTYLE, winapi::um::winuser::GetWindowLongW(hwnd, winapi::um::winuser::GWL_EXSTYLE) & !WS_EX_TOPMOST as i32);
//버튼생성
CreateWindowExW(0, to_wstring("button").as_ptr(), to_wstring("btn1").as_ptr(), WS_VISIBLE | WS_CHILD,
0 as winapi::ctypes::c_int, 0 as winapi::ctypes::c_int,
100 as winapi::ctypes::c_int, 50 as winapi::ctypes::c_int,
hwnd, 0x01 as HMENU, 0 as HINSTANCE, 0 as LPVOID); 0
},
WM_COMMAND => { //메세지전송 메세지
let cmdMsg = LOWORD(wparam as u32); //wparam에 저장된 하위비트의 내용을 cmdMsg에 저장
if cmdMsg == 0x01 { //1일시
//메세지박스출력
winapi::um::winuser::MessageBoxW(hwnd, to_wstring("btn1").as_ptr(), to_wstring("btn1").as_ptr(), winapi::um::winuser::MB_OK);
}
//switch문으로 따지면 break;
0
},
WM_DESTROY => {
//윈도우파괴 메세지받을시 메세지종료
PostQuitMessage(0); 0
},
_ => {
//다 아니라면, 해당함수의 반환값을 반환
return DefWindowProcW(hwnd, msg, wparam, lparam);
}
}
}
fn main() {
let msg: &str = "test"; //윈도우 제목
let wide: Vec<u16> = to_wstring(msg); //2바이트 와이드문자열 생성
unsafe {
let h_instance = GetModuleHandleA(0 as LPCSTR); //현재 모듈값구하고
let wndclass = WNDCLASSEXW { //WNDCLASSEXW구조체 내용입력.
cbSize: size_of::<WNDCLASSEXW>() as u32,
cbClsExtra: 0, //사용x
cbWndExtra: 0, //사용x
hbrBackground: 16 as HBRUSH, //하얀색창
hCursor: LoadCursorW(0 as HINSTANCE, IDC_ARROW), // 커서불러오기
hIcon: LoadIconW(0 as HINSTANCE, IDI_APPLICATION), //아이콘불러오기
hIconSm: LoadIconW(0 as HINSTANCE, IDI_APPLICATION), //작은아이콘
hInstance: h_instance, //모듈값
lpfnWndProc: Some(wnd_proc), //메세지 콜백함수
lpszClassName: wide.as_ptr(), //윈도우의 클래스이름
lpszMenuName: 0 as LPCWSTR, //사용x
style: CS_HREDRAW | CS_VREDRAW, //창 스타일
};
//부모 윈도우생성
CreateWindowExW(
0,
wide.as_ptr(),
wide.as_ptr(),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
0 as HWND, 0 as HMENU,
h_instance,
0 as *mut winapi::ctypes::c_void
);
//구조체내용입력
match RegisterClassExW(&wndclass) {
0 => { //만약 FALSE일시
MessageBoxA(
0 as HWND,
b"Failed to call an RegisterClassEx\0".as_ptr() as *const i8,
b"\0".as_ptr() as *const i8,
0 as UINT
);
},
_atom => { //아니라면 그 내용을 _atom에 입력
let window = CreateWindowExW(
0,
wide.as_ptr(),
wide.as_ptr(),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
0 as HWND, 0 as HMENU,
h_instance,
0 as LPVOID
);
if window.is_null() { //만약 nullptr일경우
MessageBoxA(
0 as HWND,
b"failed to load an windows\0".as_ptr() as *const i8,
b"\0".as_ptr() as *const i8,
0 as UINT
);
} else {
//그것도아니라면 창생성
ShowWindow(window, SW_SHOWDEFAULT);
hide_console_window();
let mut msg = zeroed();
while GetMessageW(&mut msg, 0 as HWND, 0, 0) != 0 {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
}
}
};
}
후.... 코드가 100줄이 넘어가니까 주석쓰기가 점점 귀찮아지네요..ㅠㅠ
모르는 부분있으면, 댓글로 질문주세요!
어쨌든, 위 코드를 모두 작성후, 실행하기위해서는 해당명령어를 입력하세요.
cargo run
그러면................????????
WOW~~~ 끝...!!!!
출처: https://mawile.tistory.com/160 [전생했더니 C딱인생이였던건에 대하여∑:티스토리]
728x90
반응형
'컴퓨터 활용(한글, 오피스 등) > 기타' 카테고리의 다른 글
rust 기초 (0) | 2024.06.08 |
---|---|
Excel에서 x 행마다 번호를 늘리는 방법 (0) | 2024.05.29 |
웹 아이콘 폰트를 모아놓은 라이브러리 Font Awesome (0) | 2024.04.29 |
Visual Studio 2019 로 rust 디버깅하기(msvc Debug 로 디버깅) (0) | 2024.04.10 |
DB 연계 방식 (0) | 2024.04.09 |