/*************************************************************************************************** pClip クリップボードの画像をホットキーでBMP保存 Copyright (C) 2008 by Pyo PapparaSoft ***************************************************************************************************/ #include // ウィンドウ操作関連 #include // コモンコントロール #include "resource.h" // リソース // 定数 #define CLASSNAME_MAIN "pClipMainFrame" // クラス名(メインウィンドウ) #define APP_TITLE "pClip" // アプリケーションタイトル #define IDH_SAVEIMAGE (WM_APP + 0x0001) // 画像保存ホットキーID #define ID_MAINTRAY 100 // タスクトレイアイコンID #define TRAY_MESSAGE (WM_APP + 0x0002) // タスクトレイのメッセージ // 関数 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // ウィンドウプロシージャ void MainContextMenu(HWND, POINT *); // メインメニュー表示 BOOL GetClipBoard(HWND); // クリップボード取得 BOOL SaveBmpFile(HWND, const char *, HBITMAP); // ビットマップ保存 BOOL SetHotkey(HWND, DWORD, int); // ホットキー設定 BOOL ResetHotkey(HWND, int); // ホットキー解除 int HexToInt(char *); // 16進数→int // ************************************************************************************************* // メイン関数 // ************************************************************************************************* int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { MSG msg; // メッセージ WNDCLASSEX wc; // ウィンドウクラス HWND hWnd; // ウィンドウハンドル DWORD mainhotkey; // ホットキー char path[MAX_PATH + 1]; // ファイルパス char drive[_MAX_DRIVE + 1]; // ドライブ名 char dir[_MAX_DIR + 1]; // ディレクトリ char dumy[MAX_PATH + 1]; // 一時変数 char inifilepath[MAX_PATH + 1]; // 設定ファイルパス char buf[MAX_PATH + 1]; // 一時変数 // ウィンドウクラスの設定 wc.cbSize = sizeof(wc); // 構造体の大きさ wc.style = NULL; // スタイル wc.lpfnWndProc = WndProc; // メッセージ処理関数 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; // プログラムのハンドル wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAINICON)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); // カーソル wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // ブラシ wc.lpszMenuName = NULL; // メニュー wc.lpszClassName = CLASSNAME_MAIN; // クラス名 wc.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAINICON)); // ウインドウクラス登録 if (!RegisterClassEx(&wc)) { return 0; } // ウィンドウ作成 hWnd = CreateWindowEx( WS_EX_TOOLWINDOW | // タスクバーに表示させない 0, CLASSNAME_MAIN, // ウインドウクラス APP_TITLE, // タイトル WS_POPUP | // ポップアップ 0, 0, // x位置 0, // y位置 300, // xサイズ 200, // yサイズ NULL, // 親ウインドウのハンドル NULL, // メニューのハンドル hInstance, // インスタンスのハンドル NULL // 作成時の引数保存用ポインタ ); if (hWnd == NULL) { return 0; } // 実行ファイルのフルパスを取得 GetModuleFileName(hInstance, path, MAX_PATH); // 取得したパスを分解する(ドライブ、ディレクトリ、ファイル名、拡張子) _splitpath(path, drive, dir, dumy, dumy); // iniファイルのフルパスを作成 wsprintf(inifilepath, "%s%s\\pclip.ini", drive, dir); // iniファイルからホットキー情報を取り出す GetPrivateProfileString("System", "Hotkey", "0", buf, 6, inifilepath); mainhotkey = HexToInt(buf); if (mainhotkey < 0) mainhotkey = 0; // ホットキー設定 SetHotkey(hWnd, mainhotkey, IDH_SAVEIMAGE); // メッセージループ while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } // ************************************************************************************************* // ウィンドウプロシージャ // ************************************************************************************************* LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { static NOTIFYICONDATA ni; // タスクトレイの構造体 POINT pmouse; // マウス位置 // メッセージ判断 switch (msg) { // ウィンドウが作成されたとき case WM_CREATE: // タスクトレイアイコン構造体の初期化 memset(&ni, 0, sizeof(NOTIFYICONDATA)); ni.cbSize = sizeof(NOTIFYICONDATA); // 構造体サイズ ni.uID = ID_MAINTRAY; // タスクトレイアイコンID ni.uFlags = NIF_ICON | // hIconメンバ設定 NIF_MESSAGE | // uCallbackMessageメンバ設定 NIF_TIP | // szTipメンバ設定 0; ni.hIcon = LoadIcon(((LPCREATESTRUCT)lp)->hInstance, MAKEINTRESOURCE(IDI_MAINICON)); ni.uCallbackMessage = TRAY_MESSAGE; // 送信するメッセージID ni.hWnd = hWnd; // メッセージを受け取るウィンドウ lstrcpy(ni.szTip, APP_TITLE); // タスクトレイアイコン登録 Shell_NotifyIcon(NIM_ADD, &ni); return 0; // ホットキー case WM_HOTKEY: if ((int)wp == IDH_SAVEIMAGE) { // ウィンドウをフォアグラウンドにする SetForegroundWindow(hWnd); // 画像保存 GetClipBoard(hWnd); } return 0; // タスクトレイ case TRAY_MESSAGE: switch(lp) { // マウスの左ボタンが押されたとき case WM_LBUTTONDOWN: // ウィンドウをフォアグラウンドにする SetForegroundWindow(hWnd); // 画像保存 GetClipBoard(hWnd); break; // マウスの右ボタンが押されて上がったとき case WM_RBUTTONUP: // ウィンドウをフォアグラウンドにする SetForegroundWindow(hWnd); // マウス位置取得 GetCursorPos(&pmouse); // メインメニュー表示 MainContextMenu(hWnd, &pmouse); break; } return 0; // ウィンドウが終了するとき case WM_CLOSE: // ホットキー解除 ResetHotkey(hWnd, IDH_SAVEIMAGE); // タスクトレイアイコン削除 Shell_NotifyIcon(NIM_DELETE, &ni); DestroyWindow(hWnd); return 0; // ウィンドウが破棄されたとき case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc (hWnd, msg, wp, lp); } // ************************************************************************************************* // メインメニュー表示 // ************************************************************************************************* void MainContextMenu(HWND hWnd, POINT *pt) { HMENU hMenu; // メインメニュー int result; // メニュー戻り値 // メインメニューの作成 hMenu = CreatePopupMenu(); // メニュー追加 AppendMenu(hMenu, MF_STRING, 1, "終了(&C)"); // ポップアップメニュー表示 result = TrackPopupMenu( hMenu, // メニューハンドル TPM_LEFTALIGN | // 左端をx座標に合わせる TPM_TOPALIGN | // 上端をy座標に合わせる TPM_LEFTBUTTON | // マウスの左ボタンでメニュー決定可能 TPM_RIGHTBUTTON | // マウスの右ボタンでメニュー決定可能 TPM_RETURNCMD, // Enterキー pt->x, pt->y, // 表示位置 0, // 予約済み(常に0) hWnd, // 送信するウィンドウ NULL // 無視される(NULL固定) ); // メニュー破棄 DestroyMenu(hMenu); switch (result) { // キャンセル時 default: break; // 終了 case 1: PostMessage(hWnd, WM_CLOSE, 0, 0); break; } return; } // ************************************************************************************************* // クリップボード取得 // ************************************************************************************************* BOOL GetClipBoard(HWND hWnd) { HBITMAP hBmp; // ビットマップハンドル SYSTEMTIME stime; // 現在時刻 char bmpfilename[MAX_PATH + 1]; // BMPファイル名 // クリップボードにビットマップデータが入っている場合 if (!IsClipboardFormatAvailable(CF_BITMAP)) { MessageBox(hWnd, "クリップボードに画像データがありません。", APP_TITLE, MB_OK | MB_ICONASTERISK); return FALSE; } // クリップボードを開く if (!OpenClipboard(hWnd)) { return FALSE; } // クリップボードからビットマップハンドルを取得 hBmp = (HBITMAP)GetClipboardData(CF_BITMAP); if (hBmp == NULL) { CloseClipboard(); return FALSE; } // 現在時刻取得 GetLocalTime(&stime); wsprintf(bmpfilename, "%d%02d%02d_%02d%02d%02d.bmp", stime.wYear, stime.wMonth, stime.wDay, stime.wHour, stime.wMinute, stime.wSecond); // ビットマップ保存 if (!SaveBmpFile(hWnd, bmpfilename, hBmp)) { MessageBox(hWnd, "画像データ保存に失敗しました。", APP_TITLE, MB_OK | MB_ICONASTERISK); CloseClipboard(); return FALSE; } // クリップボードを閉じる CloseClipboard(); return TRUE; } // ************************************************************************************************* // ビットマップ保存 // ************************************************************************************************* BOOL SaveBmpFile(HWND hWnd, const char *filename, HBITMAP hBmp) { // 渡されたビットマップ情報 BITMAP bitmap; // ビットマップ構造体 HDC hDc; // デバイスコンテキスト // 保存するビットマップ情報 LPBYTE lpDIB; // DIB LPBITMAPINFO lpbi; // ビットマップ構造体のアドレス LPBYTE lpPixel; // ピクセル配列のアドレス BITMAPFILEHEADER FileHead; // ファイルヘッダ構造体 BITMAPINFOHEADER InfoHead; // 情報ヘッダ構造体 int headersize; // ファイルヘッダと情報ヘッダのサイズ int width, height; // 画像サイズ int pixelsize; // ピクセルデータのサイズ // ファイル関係 HANDLE fp; // ファイルポインタ DWORD writesize; // 書き込んだサイズ // --------------------------------------------------------------------------------------------- // ファイル書き込み // --------------------------------------------------------------------------------------------- fp = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!fp) { return FALSE; } // ビットマップj情報を取得 GetObject(hBmp, sizeof(BITMAP), &bitmap); // --------------------------------------------------------------------------------------------- // 24ビットDIBを作成して画像をコピー // --------------------------------------------------------------------------------------------- // 画像サイズを取得 width = bitmap.bmWidth; height = bitmap.bmHeight; // 画像サイズが0の場合 if (width <= 0 || height <= 0) { CloseHandle(fp); return FALSE; } // ピクセルデータのサイズを求める if (width % 4 == 0) { pixelsize = width * height * 3; } else { // 横幅が4の倍数でない場合は4の倍数にそろえて計算 pixelsize = (width + (4 - width % 4)) * height * 3; } // DIB用バッファ確保 lpDIB = (LPBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFO) + pixelsize); // BITMAPINFOのアドレス lpbi = (LPBITMAPINFO)lpDIB; // ピクセル配列のアドレス lpPixel = (LPBYTE)(lpDIB + sizeof(BITMAPINFO)); // BITMAPINFO構造体の値の設定 ZeroMemory(lpbi, sizeof(BITMAPINFO)); lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); lpbi->bmiHeader.biWidth = width; lpbi->bmiHeader.biHeight = height; lpbi->bmiHeader.biPlanes = 1; lpbi->bmiHeader.biBitCount = 24; lpbi->bmiHeader.biCompression = BI_RGB; // プライマリモニタのデバイスコンテキストを取得 hDc = GetWindowDC(NULL); // ピクセル情報取得(ビットマップからDIBに変換) GetDIBits( hDc, // デバイスコンテキスト hBmp, // ビットマップ 0, // 取得する最初の走査行 bitmap.bmHeight, // 取得する走査行の数 lpPixel, // 保存するバッファのポインタ lpbi, // BITMAPINFO構造体のポインタ DIB_RGB_COLORS // カラーテーブルを取得しない ); // デバイスコンテキスト開放 ReleaseDC(NULL, hDc); // --------------------------------------------------------------------------------------------- // ヘッダ設定 // --------------------------------------------------------------------------------------------- // BMPヘッダー部分のサイズ、ファイル全体サイズ headersize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // ファイルヘッダ設定(14バイト) FileHead.bfType = 0x4d42; // (2bytes)ファイルタイプ("BM") FileHead.bfSize = headersize + pixelsize; // (4bytes)ファイル全体のサイズ FileHead.bfReserved1 = 0; // (2bytes)常に0 FileHead.bfReserved2 = 0; // (2bytes)常に0 FileHead.bfOffBits = headersize; // (4bytes)画像データまでのオフセット // 情報ヘッダ設定(40バイト) InfoHead.biSize = sizeof(BITMAPINFOHEADER); // (4bytes)情報ヘッダサイズ InfoHead.biWidth = width; // (4bytes)画像の幅 InfoHead.biHeight = height; // (4bytes)画像の高さ InfoHead.biPlanes = 1; // (2bytes)プレーン数(常に1) InfoHead.biBitCount = 24; // (2bytes)1画素あたりのデータサイズ InfoHead.biCompression = 0; // (4bytes)圧縮形式 InfoHead.biSizeImage = pixelsize; // (4bytes)画像データ部のサイズ InfoHead.biXPelsPerMeter = 0; // (4bytes)横方向解像度 InfoHead.biYPelsPerMeter = 0; // (4bytes)縦方向解像度 InfoHead.biClrUsed = 0; // (4bytes)パレット数 InfoHead.biClrImportant = 0; // (4bytes)重要パレットインデックス // --------------------------------------------------------------------------------------------- // 出力 // --------------------------------------------------------------------------------------------- // ファイルヘッダ書き込み if (0 == WriteFile(fp, &FileHead, sizeof(BITMAPFILEHEADER), &writesize, NULL)) { CloseHandle(fp); HeapFree(GetProcessHeap(), 0, lpDIB); return FALSE; } // 情報ヘッダ if (0 == WriteFile(fp, &InfoHead, sizeof(BITMAPINFOHEADER), &writesize, NULL)) { CloseHandle(fp); HeapFree(GetProcessHeap(), 0, lpDIB); return FALSE; } // ピクセル情報書き込み if (0 == WriteFile(fp, lpPixel, pixelsize, &writesize, NULL)) { CloseHandle(fp); HeapFree(GetProcessHeap(), 0, lpDIB); return FALSE; } // ファイルを閉じる CloseHandle(fp); // DIB用バッファ開放 HeapFree(GetProcessHeap(), 0, lpDIB); return TRUE; } // ************************************************************************************************* // ホットキー設定 // ************************************************************************************************* BOOL SetHotkey(HWND hWnd, DWORD hotkey, int hotkeyid) { UINT mkey; // 修飾キー UINT vkey; // 仮想キーコード UINT modifiers; // RegisterHotKey用の修飾キー // ホットキーが設定されていない場合 if (hotkey <= 0) { // ホットキー解除 ResetHotkey(hWnd, hotkeyid); return FALSE; } // 修飾キーと仮想キーコードを取得する mkey = (UINT)HIBYTE(hotkey); // 上位1バイト vkey = (UINT)LOBYTE(hotkey); // 下位1バイト // どの修飾キーが含まれているか調べてRegisterHotKey用のパラメータを作成 modifiers = 0; if (mkey & 1) modifiers |= MOD_ALT; // Altキー if (mkey & 2) modifiers |= MOD_CONTROL; // Ctrlキー if (mkey & 4) modifiers |= MOD_SHIFT; // Shiftキー if (mkey & 8) modifiers |= MOD_WIN; // Windowsキー // ホットキー登録 if (!RegisterHotKey( hWnd, // メッセージを受け取るウィンドウハンドル hotkeyid, // ホットキーID modifiers, // 修飾キーのフラグ vkey // 仮想キーコード )) { return FALSE; } return TRUE; } // ************************************************************************************************* // ホットキー解除 // ************************************************************************************************* BOOL ResetHotkey(HWND hWnd, int hotkeyid) { // ホットキー解除 return UnregisterHotKey(hWnd, hotkeyid); } // ************************************************************************************************* // 16進数→int // ************************************************************************************************* int HexToInt(char *str) { int place = 1; // 桁数 long var = 0; // 10進数の値 int length; // 文字列の長さ int i; // 一時変数 int cnt = 0; // 文字列カウント // 文字列の長さを取得 length = (int)lstrlen(str); // 16進数→10進数 for (i = length - 1; i >= 0; i--) { // 有効文字の長さが6文字より多い場合は何もしない if (cnt > 6) { break; } switch (str[i]) { case '0': cnt++; break; case '1': var += place; cnt++; break; case '2': var += place * 2; cnt++; break; case '3': var += place * 3; cnt++; break; case '4': var += place * 4; cnt++; break; case '5': var += place * 5; cnt++; break; case '6': var += place * 6; cnt++; break; case '7': var += place * 7; cnt++; break; case '8': var += place * 8; cnt++; break; case '9': var += place * 9; cnt++; break; case 'A': case 'a': var += place * 10; cnt++; break; case 'B': case 'b': var += place * 11; cnt++; break; case 'C': case 'c': var += place * 12; cnt++; break; case 'D': case 'd': var += place * 13; cnt++; break; case 'E': case 'e': var += place * 14; cnt++; break; case 'F': case 'f': var += place * 15; cnt++; break; default: continue; } // 加算対象の桁を一つ上げる place *= 16; } return var; }