/****************************************************************************** Calligrapher -AsciiArtClip Utility- Calligrapher モジュールソースファイル Coded by Wraith in Sep 19, 2005. ******************************************************************************/ // Tab幅を4文字に設定して表示させてください。 /////////////////////////////////////////////////////////////////////////////// // // ■ calligrp.cpp // http://tricklib.com/cxx/ex/calligrapher/calligrp.cpp // // □ 関連ファイル // .defファイル(共通) // http://tricklib.com/cxx/ex/calligrapher/common_calligrp.def // .defファイル(bcc専用) // http://tricklib.com/cxx/ex/calligrapher/bcc_calligrp.def // リソースヘッダファイル // http://tricklib.com/cxx/ex/calligrapher/calligrp.rh // リソースファイル // http://tricklib.com/cxx/ex/calligrapher/calligrp.rc // AsciiArtClip デフォルトアイコン // http://tricklib.com/cxx/ex/calligrapher/asciiart.ico // AsciiArtClip ファイルサンプル集 // http://tricklib.com/cxx/ex/calligrapher/sample.zip // 全ファイルパック // http://tricklib.com/cxx/ex/calligrapher/calligrp.zip // // □ リファレンス・サポートページ // http://tricklib.com/cxx/ex/calligrapher/ // // □ ライセンス情報 // http://tricklib.com/license.htm // // □ コンパイル方法 // case Borland C++ // bcc32 -c calligrp.cpp // brcc32 calligrp.rc // ilink32 calligrp.obj, calligrp.dll, , c0d32w.obj import32.lib cw32mt.lib, bcc_calligrp.def, calligrp.res // case Visual C++ // rc calligrp.rc // cl /GX /LD calligrp.cpp /link /def:common_calligrp.def /machine:IX86 calligrp.res // case gcc(cygwin)※1 // windres calligrp.rc calligrp.res // dllwrap --driver-flag='-shared' -mno-cygwin -mwindows --def common_calligrp.def -o calligrp.dll calligrp.cpp calligrp.res // case gcc(migw)※1 // windres calligrp.rc calligrp.res // dllwrap -mwindows --def common_calligrp.def -o calligrp.dll calligrp.cpp calligrp.res // case CodeWarrior※2 // mwcc -c calligrp.cpp // mwwinrc calligrp.rc // mwld -shared -@export common_calligrp.def calligrp.obj calligrp.res advapi32.lib // // ※1 // 俺んとこのgccはいずれも、Windows SDK が古いバージョンのものみたいで // IExtractImage に対応してなかったんで実際にはコンパイルを通してないです。 // // ※2 // advapi32.lib が正しくリンクされる為にはライブラリのパスが正しく設定 // されている必要があります。 // #ifndef CALLIGRP_H #define CALLIGRP_H #ifndef _UNICODE #define _UNICODE #endif #ifndef UNICODE #define UNICODE #endif #ifndef UNICODE_ASCIIART #define UNICODE_ASCIIART #endif #ifndef STRICT #define STRICT #endif #ifndef INC_OLE2 #define INC_OLE2 #endif #include #include #include #include //#include #include #if defined(UNICODE_ASCIIART) #include #endif #if defined(_MSC_VER) #pragma comment(lib, "USER32.lib") #pragma comment(lib, "GDI32.lib") #pragma comment(lib, "KERNEL32.lib") #pragma comment(lib, "ADVAPI32.lib") #endif #include "calligrp.rh" /////////////////////////////////////////////////////////////////////////////// // // Shell Extension Information // #define MODULE_DISPLAY_NAME "AsciiArtClip Shell Extension ( calligrp.dll )" #define FILE_EXTENSION _T(".aac") #define FILE_TYPE_NAME _T("AsciiArtClipFile") ////////////////////////////////////////////////////////////////////////////// // // Declare auto closers // template class demi { public: T value; demi() {} demi(const T &X) :value(X) {} operator T& () { return value; } operator const T& () const { return value; } T * operator & () { return &value; } const T * operator & () const { return &value; } T & operator () () { return value; } const T & operator () () const { return value; } }; #define DECLARE_AUTO_CLOSE(name, type, param, init, close_command) \ class name :public demi \ { \ public: \ name(param) :demi(init) { } \ ~name() \ { \ close(); \ } \ void close() \ { \ if (value) \ { \ close_command; \ value = NULL; \ } \ } \ }; DECLARE_AUTO_CLOSE(AUTO_HANDLE, HANDLE, HANDLE X = NULL, X, INVALID_HANDLE_VALUE != value && (CloseHandle(value), false)) DECLARE_AUTO_CLOSE(AUTO_BITMAP, HBITMAP, HBITMAP X = NULL, X, DeleteObject(value)) DECLARE_AUTO_CLOSE(AUTO_FONT, HFONT, HFONT X = NULL, X, DeleteObject(value)) DECLARE_AUTO_CLOSE(AUTO_BRUSH, HBRUSH, HBRUSH X = NULL, X, DeleteObject(value)) DECLARE_AUTO_CLOSE(AUTO_COMPATIBLE_DC, HDC, HDC dc, CreateCompatibleDC(dc), DeleteDC(value)) DECLARE_AUTO_CLOSE(AUTO_REGKEY, HKEY, HKEY X = NULL, X, RegCloseKey(value)) class AUTO_WINDOW_DC :public demi { public: HWND window; AUTO_WINDOW_DC(HWND X_window = 0) :demi(GetWindowDC(X_window)), window(X_window) { } ~AUTO_WINDOW_DC() { close(); } void close() { if (value) { ReleaseDC(window, value); value = NULL; } } }; ////////////////////////////////////////////////////////////////////////////// // // Win32 Error // class win32_error :public std::runtime_error { DWORD code; public: win32_error(DWORD X_code = GetLastError()) :std::runtime_error(win32_error::make_error_message(X_code)), code(X_code) { } static const std::string make_error_message(DWORD X_code = GetLastError()); DWORD get_error_code() const { return code; } const char * get_error_message() const { return what(); } }; const std::string win32_error::make_error_message(DWORD X_code) { LPVOID lpMsgBuf; FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, X_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMsgBuf, 0, NULL); const std::string result = (const char *)lpMsgBuf; LocalFree(lpMsgBuf); return result; } class runtime_warning :public std::runtime_error { public: runtime_warning(const std::string &X) :std::runtime_error(X) { } }; void OutputExceptionString(const std::exception &e) { OutputDebugStringA("Exception in " MODULE_DISPLAY_NAME ":"); OutputDebugStringA(e.what()); } ////////////////////////////////////////////////////////////////////////////// // // ファイルオープン(読み込み専用、自動クローズ) // class OpenReadFile :public AUTO_HANDLE { public: OpenReadFile(const char *filename) :AUTO_HANDLE( CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ |FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL)) { } OpenReadFile(const wchar_t *filename) :AUTO_HANDLE( CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ |FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL)) { } }; #if defined(UNICODE_ASCIIART) typedef std::wstring astring; #else typedef std::string astring; #endif //const astring LoadText(HANDLE stream, unsigned int limit_size = 8 *1024); //HBITMAP CreateTextBitmap(const astring &text, const int target_width = 0, const int target_height = 0); //HICON CreateTextIcon(HBITMAP canvas_bitmap, int canvas_size) //bool Execute_CopyForPost(HWND window, HANDLE file); //bool Execute_CopyToBitmap(HWND window, HANDLE file); #ifndef ARRAY_SIZE #define ARRAY_SIZE(X) (sizeof(X)/sizeof(X[0])) #endif // ARRAY_SIZE #ifndef ARRAY_END #define ARRAY_END(X) (X +ARRAY_SIZE(X)) #endif // ARRAY_END #endif // CALLIGRP_H #ifndef CALLIGRP_CPP #define CALLIGRP_CPP ////////////////////////////////////////////////////////////////////////////// // // テキストファイルの読み込み // const astring LoadText(HANDLE stream, unsigned int limit_size = 8 *1024) { if (NULL == stream || INVALID_HANDLE_VALUE == stream) { throw win32_error(); } DWORD read_size = 0; DWORD total_read_size = 0; BYTE buffer[4 *1024]; std::string result; while(ReadFile(stream, buffer, sizeof(buffer), &read_size, NULL) && read_size) { result.append((std::string::value_type*)buffer, read_size); if (limit_size) { total_read_size += read_size; if (limit_size <= total_read_size) { break; } } } #if defined(UNICODE_ASCIIART) if (2 <= result.size() && '\xFF' == result[0] && '\xFE' == result[1]) { return astring(((LPCWSTR)result.data()) +1, (result.size() /sizeof(WCHAR)) -1); } else { WCHAR wbuffer[16 *1024]; MultiByteToWideChar(CP_ACP, 0, result.c_str(), -1, wbuffer, ARRAY_SIZE(wbuffer)); return astring(wbuffer); } #else return result; #endif }; ////////////////////////////////////////////////////////////////////////////// // // テキストの描画 // inline BOOL DrawTextX(HDC dc, HFONT font, const astring &text, RECT *draw_rect, UINT flags) { if (0 == text.size()) { throw runtime_warning("描画要求のあったテキストが空文字列です。"); } HGDIOBJ backup_font = SelectObject(dc, font); #if defined(UNICODE_ASCIIART) BOOL result = DrawTextW(dc, text.c_str(), text.length(), draw_rect, flags); #else BOOL result = DrawTextA(dc, text.c_str(), text.length(), draw_rect, flags); #endif SelectObject(dc, backup_font); return result; } ////////////////////////////////////////////////////////////////////////////// // // 背景色の描画 // inline BOOL FillBackgroud(HDC dc, int width, int height, HBRUSH brush) { RECT dc_rect; dc_rect.left = 0; dc_rect.top = 0; dc_rect.right = width; dc_rect.bottom = height; return FillRect(dc, &dc_rect, brush); } ////////////////////////////////////////////////////////////////////////////// // // ビットマップの作成 // HBITMAP CreateTextBitmap(const astring &text, const int target_width = 0, const int target_height = 0) { // target_width, target_height が指定されていればそのサイズでビットマップ // を作成し、そうでなければオリジナルのサイズでビットマップを作成。 const TCHAR *font_face = _T("MS Pゴシック"); const int font_size = 9; AUTO_WINDOW_DC dc; AUTO_BRUSH white_brush(CreateSolidBrush(0xFFFFFF)); // フォントの作成 LOGFONT lfont; memset(&lfont, 0, sizeof(LOGFONT)); _tcscpy(lfont.lfFaceName, font_face); lfont.lfHeight = -MulDiv(font_size, GetDeviceCaps(dc, LOGPIXELSY), 72); lfont.lfWeight = FW_REGULAR; lfont.lfCharSet = DEFAULT_CHARSET; AUTO_FONT font = CreateFontIndirect(&lfont); // 描画矩形の取得(...実際にはクリップします。) RECT canvas_rect = { 0, }; DrawTextX(dc, font, text, &canvas_rect, DT_CALCRECT |DT_NOPREFIX); const int canvas_width = canvas_rect.right -canvas_rect.left; const int canvas_height = canvas_rect.bottom -canvas_rect.top; // 前景色の計算 COLORREF color = 0x000000; if (target_width && target_height && canvas_width && canvas_height) { const double target_size = sqrt(target_width *target_height); const double canvas_size = sqrt(canvas_width *canvas_height); if (target_size < canvas_size) { color = 0x010101 *(0xAA -(int)(0xAA *target_size /canvas_size)); // StretchBlt よりイメージの圧縮を行うと、黒が目立ちすぎるので // 圧縮率が高いほど、明るい灰色にしておく。 } } HBITMAP canvas_bitmap = CreateCompatibleBitmap(dc, canvas_width, canvas_height); AUTO_COMPATIBLE_DC canvas_dc(dc); SelectObject(canvas_dc, canvas_bitmap); FillBackgroud(canvas_dc, canvas_width, canvas_height, white_brush); // AAの描画 SetTextColor(canvas_dc, color); DrawTextX(canvas_dc, font, text, &canvas_rect, DT_NOPREFIX); // for DEBUG // この行を有効にすると画面上に描画されます。 //BitBlt(dc, 0, 0, canvas_size, canvas_size, canvas_dc, 0, 0, SRCCOPY); if (target_width && target_height) { HBITMAP target_bitmap = CreateCompatibleBitmap(dc, target_width, target_height); AUTO_COMPATIBLE_DC target_dc(dc); SelectObject(target_dc, target_bitmap); FillBackgroud(target_dc, target_width, target_height, white_brush); int copy_width = target_width; int copy_height = target_height; const double target_rate = (double)target_width /(double)target_height; const double canvas_rate = (double)canvas_width /(double)canvas_height; if (target_rate < canvas_rate) { // 中途半端な拡大が行われると汚くなるので、2.0倍未満の倍率では拡大が行われないようにする。 if (canvas_width < target_width && target_width < canvas_width *2) { copy_width = canvas_width; } // 縦横比が崩れないように調整 copy_height = (int)((double)copy_width /canvas_rate); } else { // 中途半端な拡大が行われると汚くなるので、2.0倍未満の倍率では拡大が行われないようにする。 if (canvas_height < target_height && target_height < canvas_height *2) { copy_height = canvas_height; } // 縦横比が崩れないように調整 copy_width = (int)((double)copy_height *canvas_rate); } StretchBlt(target_dc, (target_width -copy_width)/2, (target_height -copy_height)/2, copy_width, copy_height, canvas_dc, 0, 0, canvas_width, canvas_height, SRCCOPY); canvas_dc.close(); DeleteObject(canvas_bitmap); return target_bitmap; } else { return canvas_bitmap; } } ////////////////////////////////////////////////////////////////////////////// // // アイコンの作成 // HICON CreateTextIcon(HBITMAP canvas_bitmap, int canvas_size) { if (!canvas_bitmap) { return NULL; } // MASK の生成 AUTO_WINDOW_DC dc; AUTO_BITMAP mask_bitmap = CreateCompatibleBitmap(dc, canvas_size, canvas_size); { AUTO_COMPATIBLE_DC canvas_dc(dc); SelectObject(canvas_dc, mask_bitmap); FillBackgroud(canvas_dc, canvas_size, canvas_size, AUTO_BRUSH(CreateSolidBrush(0x000000))); } // アイコンの生成 ICONINFO ii = { TRUE, 0, 0, mask_bitmap, canvas_bitmap, }; return CreateIconIndirect(&ii); } /////////////////////////////////////////////////////////////////////////////// // // HTML(もどき)エンコード // astring & string_replace(astring &X, const astring &X_search, const astring &X_replace) { const astring::size_type search_length = X_search.length(); const astring::size_type replace_length = X_replace.length(); astring::size_type p = 0; while(astring::npos != (p = X.find(X_search, p))) { X.replace(p, search_length, X_replace); p += replace_length; } return X; } #if defined(UNICODE_ASCIIART) const int g_cp932_data[] = { // バベル( http://tricklib.com/cxx/ex/babel/ )で使ってるヤツと同じデータです。 #include "cp932.csv" }; std::map g_cp932; void init_cp932() { static bool first = true; if (!first) { return; } first = false; const int *i = g_cp932_data; while(i < ARRAY_END(g_cp932_data)) { const int sjis = *(i++); const int unicode = *(i++); if (g_cp932.end() == g_cp932.find(unicode)) { g_cp932.insert(std::pair(unicode, sjis)); } } } #endif const std::string html_encode(const astring &X) { astring X_text = X; if (0 < X_text.size()) { // 一般的なHTMLエンコード string_replace(X_text, _T("&"), _T("&")); string_replace(X_text, _T("<"), _T("<")); string_replace(X_text, _T(">"), _T(">")); // 行頭の半角スペースのエンコード if (_T(' ') == X[0]) { X_text = _T(" ") +X_text.substr(1); } string_replace(X_text, _T("\r "), _T("\r ")); string_replace(X_text, _T("\n "), _T("\n ")); // 連続する半角スペースのエンコード string_replace(X_text, _T(" "), _T("  ")); } #if defined(UNICODE_ASCIIART) // シフトJISで表示できない文字をエスケープ char buffer[16 *1024]; memset(buffer, 0, sizeof(buffer)); int j = 0; init_cp932(); for(astring::iterator i = X_text.begin(); i != X_text.end(); ++i) { char current_str[16]; if (0x80 <= *i) { int current_char = g_cp932[*i]; if (current_char) { if (current_char < 0x100) { current_str[0] = current_char &0xFF; current_str[1] = 0; } else { current_str[0] = (current_char >> 8) &0xFF; current_str[1] = current_char &0xFF; current_str[2] = 0; } } else { wsprintfA(current_str, "&#%d;", *i); } } else { current_str[0] = *i; current_str[1] = 0; } const int current_strlen = strlen(current_str); if (sizeof(buffer) <= j +current_strlen +1) { break; } strcpy(buffer +j, current_str); j += current_strlen; } return std::string(buffer); #else return X_text; #endif } /////////////////////////////////////////////////////////////////////////////// // // クリップボード // void Simple_SetClipboardData(HWND window, UINT format, HANDLE data) { OpenClipboard(window); EmptyClipboard(); SetClipboardData(format, data); CloseClipboard(); } HANDLE string_to_handle(const std::string &value) { HANDLE hMemory = ::GlobalAlloc(GHND, value.length() +1); strcpy((char *)::GlobalLock(hMemory), value.c_str()); GlobalUnlock(hMemory); return hMemory; } HRESULT Execute_CopyForPost(HWND window, HANDLE file) { try { Simple_SetClipboardData(window, CF_TEXT, string_to_handle( html_encode( LoadText(file)))); return S_OK; } catch(const win32_error &e) { OutputExceptionString(e); return e.get_error_code(); } catch(const std::exception &e) { OutputExceptionString(e); return E_FAIL; } catch(...) { return E_FAIL; } } HRESULT Execute_CopyToBitmap(HWND window, HANDLE file) { try { Simple_SetClipboardData(window, CF_BITMAP, CreateTextBitmap( LoadText(file))); return S_OK; } catch(const win32_error &e) { OutputExceptionString(e); return e.get_error_code(); } catch(const std::exception &e) { OutputExceptionString(e); return E_FAIL; } catch(...) { return E_FAIL; } } #endif // CALLIGRP_CPP /////////////////////////////////////////////////////////////////////////////// // // Interface for rundll32.exe // #ifndef RUNDLL32_IF_CPP #define RUNDLL32_IF_CPP #define DECLARE_RUNDLL32_FUNCTION(name, command) \ DECLARE_RUNDLL32_FUNCTION_core(name, LPCSTR, command) \ DECLARE_RUNDLL32_FUNCTION_core(name##A, LPCSTR, command) \ DECLARE_RUNDLL32_FUNCTION_core(name##W, LPCWSTR, command) #define DECLARE_RUNDLL32_FUNCTION_core(name, string_type, command) \ extern "C" int __declspec(dllexport) \ name(HWND hwnd, HINSTANCE hinst, string_type lpszCmdLine, int nCmdShow) \ { \ hwnd, hinst, lpszCmdLine, nCmdShow; \ return command; \ } DECLARE_RUNDLL32_FUNCTION(CopyForPost, Execute_CopyForPost(hwnd, OpenReadFile(lpszCmdLine))) DECLARE_RUNDLL32_FUNCTION(CopyToBitmap, Execute_CopyToBitmap(hwnd, OpenReadFile(lpszCmdLine))) #undef DECLARE_RUNDLL32_FUNCTION #undef DECLARE_RUNDLL32_FUNCTION_core #endif // RUNDLL32_IF_CPP /////////////////////////////////////////////////////////////////////////////// // // Interface for Shell(explorer.exe) // #ifndef EXPLORER_IF_CPP #define EXPLORER_IF_CPP #include #pragma data_seg(".text") #define INITGUID #include #include // {FFDFE672-69F8-4595-B9DF-288FBEDD17AB} DEFINE_GUID(CLSID_CalligrapherShellExtension, 0xffdfe672L, 0x69f8, 0x4595, 0xb9, 0xdf, 0x28, 0x8f, 0xbe, 0xdd, 0x17, 0xab ); // this module GUID LPCTSTR szCLSID_CalligrapherShellExtension = _T("{FFDFE672-69F8-4595-B9DF-288FBEDD17AB}"); class ReferenceCounter { private: ULONG m_cRef; public: ReferenceCounter(); virtual ~ReferenceCounter(); public: STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); void RefCheck(); }; class CalligraphClassFactory :public IClassFactory, ReferenceCounter { public: //IUnknown members STDMETHODIMP QueryInterface(REFIID, LPVOID *); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); //IClassFactory members STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID *); STDMETHODIMP LockServer(BOOL); }; class AsciiArtClipFile :public IExtractIcon, IExtractImage, IPersistFile, ReferenceCounter { protected: TCHAR m_szFileUserClickedOn[MAX_PATH]; SIZE m_RequestImageSize; const astring GetText(); void OutputDebugFileName(); public: //IUnknown members STDMETHODIMP QueryInterface(REFIID, LPVOID *); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); //IExtractIcon methods STDMETHODIMP GetIconLocation(UINT uFlags, LPTSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags); STDMETHODIMP Extract(LPCTSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize); //IExtractImage methods STDMETHODIMP GetLocation(LPWSTR pszPathBuffer, DWORD cchMax, DWORD *pdwPriority, const SIZE *prgSize, DWORD dwRecClrDepth, DWORD *pdwFlags); STDMETHODIMP Extract(HBITMAP *phBmpImage); //IPersistFile methods STDMETHODIMP GetClassID(LPCLSID lpClassID); STDMETHODIMP IsDirty(); STDMETHODIMP Load(LPCOLESTR lpszFileName, DWORD grfMode); STDMETHODIMP Save(LPCOLESTR lpszFileName, BOOL fRemember); STDMETHODIMP SaveCompleted(LPCOLESTR lpszFileName); STDMETHODIMP GetCurFile(LPOLESTR *lplpszFileName); }; #pragma data_seg() // // Global variables // UINT g_cRefThisDll = 0; // Reference count of this DLL. HINSTANCE g_hmodThisDll = NULL; // Handle to this DLL itself. extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { hInstance, dwReason, lpReserved; if (dwReason == DLL_PROCESS_ATTACH) { g_hmodThisDll = hInstance; } return 1; } STDAPI DllCanUnloadNow() { if (g_cRefThisDll) { return S_FALSE; } else { return S_OK; } } STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut) { *ppvOut = NULL; try { if (IsEqualIID(rclsid, CLSID_CalligrapherShellExtension)) { return (new CalligraphClassFactory)->QueryInterface(riid, ppvOut); } } catch(...) { } OutputDebugStringA("DllGetClassObject@" MODULE_DISPLAY_NAME " is faild."); return CLASS_E_CLASSNOTAVAILABLE; } // *********************** ReferenceCounter ************************* ReferenceCounter::ReferenceCounter() :m_cRef(0) { ++g_cRefThisDll; } ReferenceCounter::~ReferenceCounter() { --g_cRefThisDll; } STDMETHODIMP_(ULONG) ReferenceCounter::AddRef() { return ++m_cRef; } STDMETHODIMP_(ULONG) ReferenceCounter::Release() { if (--m_cRef) { return m_cRef; } delete this; return 0L; } void ReferenceCounter::RefCheck() { if (!m_cRef) { delete this; } } // *********************** CalligraphClassFactory ************************* STDMETHODIMP CalligraphClassFactory::QueryInterface(REFIID riid, LPVOID *ppv) { *ppv = NULL; if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)) { *ppv = (LPCLASSFACTORY)this; } else { RefCheck(); return E_NOINTERFACE; } AddRef(); return S_OK; } STDMETHODIMP_(ULONG) CalligraphClassFactory::AddRef() { return ReferenceCounter::AddRef(); } STDMETHODIMP_(ULONG) CalligraphClassFactory::Release() { return ReferenceCounter::Release(); } STDMETHODIMP CalligraphClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppv) { *ppv = NULL; if (pUnkOuter) { return CLASS_E_NOAGGREGATION; } try { return (new AsciiArtClipFile())->QueryInterface(riid, ppv); } catch(...) { } OutputDebugStringA("CreateInstance@" MODULE_DISPLAY_NAME " is faild."); return E_OUTOFMEMORY; } STDMETHODIMP CalligraphClassFactory::LockServer(BOOL fLock) { fLock; return S_OK; } // *********************** Calligraph ************************* const astring AsciiArtClipFile::GetText() { astring value = LoadText(OpenReadFile(m_szFileUserClickedOn)); #if defined(UNICODE_ASCIIART) if (astring::npos == value.find_first_not_of(L"  \t\r\n")) #else if (astring::npos == value.find_first_not_of(" \t\r\n")) #endif { value.erase(); } return value; } void AsciiArtClipFile::OutputDebugFileName() { if (m_szFileUserClickedOn[0]) { m_szFileUserClickedOn[MAX_PATH -1] = 0; OutputDebugString(m_szFileUserClickedOn); } } STDMETHODIMP AsciiArtClipFile::QueryInterface(REFIID riid, LPVOID *ppv) { *ppv = NULL; if (IsEqualIID(riid, IID_IExtractIcon) || IsEqualIID(riid, IID_IUnknown)) { *ppv = (LPEXTRACTICON)this; } else if (IsEqualIID(riid, IID_IExtractImage)) { *ppv = (LPEXTRACTIMAGE)this; } else if (IsEqualIID(riid, IID_IPersistFile)) { *ppv = (LPPERSISTFILE)this; } else { RefCheck(); return E_NOINTERFACE; } AddRef(); return S_OK; } STDMETHODIMP_(ULONG) AsciiArtClipFile::AddRef() { return ReferenceCounter::AddRef(); } STDMETHODIMP_(ULONG) AsciiArtClipFile::Release() { return ReferenceCounter::Release(); } // *********************** IExtractIcon Implementation ************************* const TCHAR default_icon_tag[] = _T("|default") FILE_EXTENSION; STDMETHODIMP AsciiArtClipFile::GetIconLocation( UINT uFlags, LPTSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags) { uFlags, szIconFile, cchMax, piIndex, pwFlags; *pwFlags = GIL_NOTFILENAME; if (GIL_DEFAULTICON != (uFlags &GIL_DEFAULTICON)) { if (GIL_ASYNC == (uFlags &GIL_ASYNC)) { return E_PENDING; } WIN32_FIND_DATA wfd = { 0, }; HANDLE FindHandle = FindFirstFile(m_szFileUserClickedOn, &wfd); FindClose(FindHandle); if (FindHandle != INVALID_HANDLE_VALUE) { if (0 < wfd.nFileSizeLow || 0 < wfd.nFileSizeHigh) { TCHAR buffer[MAX_PATH +32]; wsprintf(buffer, _T("%s|%ld|%ld"), m_szFileUserClickedOn, wfd.ftLastWriteTime.dwLowDateTime, wfd.ftLastWriteTime.dwHighDateTime); if (_tcslen(buffer) < cchMax) { _tcscpy(szIconFile, buffer); *piIndex = 0; *pwFlags |= GIL_DONTCACHE; return S_OK; } } } } if (ARRAY_SIZE(default_icon_tag) <= cchMax) { _tcscpy(szIconFile, default_icon_tag); *piIndex = 0; return S_OK; } return E_FAIL; } STDMETHODIMP AsciiArtClipFile::Extract( LPCTSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize) { pszFile, nIconIndex, phiconLarge, phiconSmall, nIconSize; if (0 != _tcscmp(default_icon_tag, pszFile)) { // デフォルトアイコンの要求ではない... try { const astring &value = GetText(); if (phiconLarge) { const int icon_size = LOWORD(nIconSize); *phiconLarge = CreateTextIcon(AUTO_BITMAP(CreateTextBitmap(value, icon_size, icon_size)), icon_size); } if (phiconSmall) { const int icon_size = HIWORD(nIconSize); *phiconSmall = CreateTextIcon(AUTO_BITMAP(CreateTextBitmap(value, icon_size, icon_size)), icon_size); } return S_OK; } catch(const runtime_warning &) { // ここで runtime_warning まで出力するのはくどいので出力しない。 } catch(const std::exception &e) { OutputExceptionString(e); OutputDebugFileName(); } catch(...) { } // アイコンの作成に失敗した場合はデフォルトアイコンを返す... } if (phiconLarge) { const int icon_size = LOWORD(nIconSize); *phiconLarge = (HICON)LoadImage(g_hmodThisDll, MAKEINTRESOURCE(ICON_ASCIIARTCLIP), IMAGE_ICON, icon_size, icon_size, 0); } if (phiconSmall) { const int icon_size = HIWORD(nIconSize); *phiconSmall = (HICON)LoadImage(g_hmodThisDll, MAKEINTRESOURCE(ICON_ASCIIARTCLIP), IMAGE_ICON, icon_size, icon_size, 0); } return S_OK; } // *********************** IExtractImage Implementation ************************* STDMETHODIMP AsciiArtClipFile::GetLocation( LPWSTR pszPathBuffer, DWORD cchMax, DWORD *pdwPriority, const SIZE *prgSize, DWORD dwRecClrDepth, DWORD *pdwFlags) { pszPathBuffer, cchMax, pdwPriority, prgSize, dwRecClrDepth, pdwFlags; if (_tcslen(m_szFileUserClickedOn) < cchMax) { #if defined(UNICODE) wcscpy(pszPathBuffer, m_szFileUserClickedOn); #else MultiByteToWideChar(CP_ACP, 0, m_szFileUserClickedOn, -1, pszPathBuffer, cchMax); #endif if (pdwPriority) { *pdwPriority = 0x10000000; // == IEIT_PRIORITY_NORMAL } if (prgSize) { m_RequestImageSize = *prgSize; } if (IEIFLAG_ASYNC == (*pdwFlags &IEIFLAG_ASYNC)) { return E_PENDING; } return S_OK; } return E_FAIL; } STDMETHODIMP AsciiArtClipFile::Extract(HBITMAP *phBmpImage) { if (phBmpImage) { try { *phBmpImage = CreateTextBitmap(GetText(), m_RequestImageSize.cx, m_RequestImageSize.cy); return S_OK; } catch(const runtime_warning &) { // ここで runtime_warning まで出力するのはくどいので出力しない。 } catch(const win32_error &e) { OutputExceptionString(e); OutputDebugFileName(); return e.get_error_code(); } catch(const std::exception &e) { OutputExceptionString(e); OutputDebugFileName(); } catch(...) { } } return E_FAIL; } // *********************** IPersistFile Implementation ****************** STDMETHODIMP AsciiArtClipFile::GetClassID(LPCLSID lpClassID) { lpClassID; return E_FAIL; } STDMETHODIMP AsciiArtClipFile::IsDirty() { return S_FALSE; } STDMETHODIMP AsciiArtClipFile::Load(LPCOLESTR lpszFileName, DWORD grfMode) { lpszFileName, grfMode; if (MAX_PATH <= wcslen(lpszFileName)) { return E_FAIL; } #if defined(UNICODE) wcscpy(m_szFileUserClickedOn, (const WCHAR*)lpszFileName); #else WideCharToMultiByte(CP_ACP, 0, lpszFileName, -1, m_szFileUserClickedOn, sizeof(m_szFileUserClickedOn), NULL, NULL); #endif return S_OK; } STDMETHODIMP AsciiArtClipFile::Save(LPCOLESTR lpszFileName, BOOL fRemember) { lpszFileName, fRemember; return E_FAIL; } STDMETHODIMP AsciiArtClipFile::SaveCompleted(LPCOLESTR lpszFileName) { lpszFileName; return E_FAIL; } STDMETHODIMP AsciiArtClipFile::GetCurFile(LPOLESTR *lplpszFileName) { lplpszFileName; return E_FAIL; } #endif // EXPLORER_IF_CPP /////////////////////////////////////////////////////////////////////////////// // // Interface for regsvr32.exe // #ifndef REGSVR32_IF_CPP #define REGSVR32_IF_CPP extern "C" HRESULT __declspec(dllexport) DllRegisterServer() { #if !defined(__MWERKS__) // names from resource TCHAR szAsciiArtClip[256]; // = _T("アスキーアート クリップ"); LoadString(g_hmodThisDll, STR_ASCIIARTCLIP, szAsciiArtClip, sizeof(szAsciiArtClip)); TCHAR szCopyForPost[256]; // = _T("カキコ用に中身をコピー"); LoadString(g_hmodThisDll, STR_COPYFORPOST, szCopyForPost, sizeof(szCopyForPost)); TCHAR szCopyToBitmap[256]; // = _T("画像で中身をコピー"); LoadString(g_hmodThisDll, STR_COPYTOBITMAP, szCopyToBitmap, sizeof(szCopyToBitmap)); #else // CodeWarrior のリソースコンパイラは日本語に対応できていないっぽい // ので、直埋め。(俺がちゃんとした使い方を知らんだけかもしれんけど。) LPCTSTR szAsciiArtClip = _T("アスキーアート クリップ"); LPCTSTR szCopyForPost = _T("カキコ用に中身をコピー(&P)"); LPCTSTR szCopyToBitmap = _T("画像で中身をコピー(&B)"); // ...gcc のリソースコンパイラも完全には日本語に対応できていないっぽいが // このモジュールの範囲内では影響は無い模様。 #endif // this module GUID LPCTSTR szCLSID = szCLSID_CalligrapherShellExtension; // this module name LPCTSTR szModuleName = _T("AsciiArtClip Shell Extension"); // DLL パスの取得 TCHAR szModulePath[MAX_PATH]; GetModuleFileName(g_hmodThisDll, szModulePath, ARRAY_SIZE(szModulePath)); struct REGSTRUCT { HKEY hRootKey; LPCTSTR lpszSubKey; LPCTSTR lpszValueName; LPCTSTR lpszData; }; REGSTRUCT RegEntries[] = { HKEY_CLASSES_ROOT, FILE_EXTENSION, NULL, FILE_TYPE_NAME, HKEY_CLASSES_ROOT, FILE_EXTENSION, _T("Content Type"), _T("text/plain"), HKEY_CLASSES_ROOT, FILE_EXTENSION, _T("PerceivedType"), _T("text"), HKEY_CLASSES_ROOT, FILE_EXTENSION _T("\\ShellNew"), _T("NullFile"), _T(""), HKEY_CLASSES_ROOT, FILE_TYPE_NAME, NULL, szAsciiArtClip, HKEY_CLASSES_ROOT, FILE_TYPE_NAME _T("\\DefaultIcon"), NULL, _T("\"%s\",0"), HKEY_CLASSES_ROOT, FILE_TYPE_NAME _T("\\Shell\\CopyForPost"), NULL, szCopyForPost, HKEY_CLASSES_ROOT, FILE_TYPE_NAME _T("\\Shell\\CopyForPost\\Command"), NULL, _T("rundll32.exe \"%s\",CopyForPost %%1"), HKEY_CLASSES_ROOT, FILE_TYPE_NAME _T("\\Shell\\CopyToBitmap"), NULL, szCopyToBitmap, HKEY_CLASSES_ROOT, FILE_TYPE_NAME _T("\\Shell\\CopyToBitmap\\Command"), NULL, _T("rundll32.exe \"%s\",CopyToBitmap %%1"), HKEY_CLASSES_ROOT, FILE_TYPE_NAME _T("\\Shell\\Open\\Command"), NULL, _T("notepad.exe %%1"), HKEY_CLASSES_ROOT, FILE_TYPE_NAME _T("\\shellex\\IconHandler"), NULL, szCLSID, HKEY_CLASSES_ROOT, FILE_TYPE_NAME _T("\\shellex\\{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}"), NULL, szCLSID, HKEY_CLASSES_ROOT, _T("CLSID\\%s"), NULL, szModuleName, HKEY_CLASSES_ROOT, _T("CLSID\\%s\\InProcServer32"), NULL, _T("\"%s\""), HKEY_CLASSES_ROOT, _T("CLSID\\%s\\InProcServer32"), _T("ThreadingModel"), _T("Apartment"), HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"), szCLSID, szModuleName, }; for(int i = 0; i < ARRAY_SIZE(RegEntries); ++i) { AUTO_REGKEY RegKey; DWORD dwDisp; HRESULT lResult; TCHAR szSubKey[1024]; wsprintf(szSubKey, RegEntries[i].lpszSubKey, szCLSID); if (ERROR_SUCCESS == RegOpenKeyEx(RegEntries[i].hRootKey, szSubKey, 0, KEY_SET_VALUE, &RegKey) || ERROR_SUCCESS == RegCreateKeyEx(RegEntries[i].hRootKey, szSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &RegKey, &dwDisp)) { TCHAR szData[1024]; wsprintf(szData, RegEntries[i].lpszData, szModulePath); RegSetValueEx(RegKey, RegEntries[i].lpszValueName, 0, REG_SZ, (LPBYTE)szData, (lstrlen(szData) + 1) * sizeof(TCHAR)); } else { return E_FAIL; } } return S_OK; } void delete_reg_key(HKEY hKey, LPCTSTR pszSubKey) { { AUTO_REGKEY hEnumKey; if (ERROR_SUCCESS == RegOpenKeyEx(hKey, pszSubKey, 0, KEY_ALL_ACCESS, &hEnumKey)) { TCHAR szKey[MAX_PATH]; DWORD dwSize = MAX_PATH; while(ERROR_SUCCESS == RegEnumKeyEx(hEnumKey, 0, szKey, &dwSize, NULL, NULL, NULL, NULL)) { delete_reg_key(hEnumKey, szKey); dwSize = MAX_PATH; } } } RegDeleteKey(hKey, pszSubKey); } extern "C" HRESULT __declspec(dllexport) DllUnregisterServer() { LPCTSTR calligrapher_application_subkey_path = _T("SOFTWARE\\TrickLibrary\\calligrapher"); { AUTO_REGKEY hCalligrapherKey; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, calligrapher_application_subkey_path, 0, KEY_ALL_ACCESS, &hCalligrapherKey)) { TCHAR buffer[256]; DWORD reg_type = REG_SZ; DWORD buffer_size = sizeof(buffer); if (ERROR_SUCCESS == RegQueryValueEx(hCalligrapherKey, _T("selfdelete"), NULL, ®_type, (LPBYTE)buffer, &buffer_size) && 0 == lstrcmp(_T("true"), buffer)) { // DLL パスの取得 TCHAR szModulePath[MAX_PATH]; GetModuleFileName(g_hmodThisDll, szModulePath, MAX_PATH); // DLL の削除 MoveFileEx(szModulePath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); } } } delete_reg_key(HKEY_LOCAL_MACHINE, calligrapher_application_subkey_path); // this module GUID LPCTSTR szCLSID = szCLSID_CalligrapherShellExtension; LPCTSTR reg_subkey_list[] = { FILE_EXTENSION, FILE_TYPE_NAME, _T("CLSID\\%s"), }; for(int i = 0; i < ARRAY_SIZE(reg_subkey_list); ++i) { TCHAR szSubKey[1024]; wsprintf(szSubKey, reg_subkey_list[i], szCLSID); delete_reg_key(HKEY_CLASSES_ROOT, szSubKey); } AUTO_REGKEY RegKey; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"), 0, KEY_ALL_ACCESS, &RegKey)) { RegDeleteValue(RegKey, szCLSID); } return S_OK; } #endif // REGSVR32_IF_CPP /****************************************************************************** □■□■ Wraith the Trickster □■□■ ■□■□ 〜I'll go with heaven's advantage and fool's wisdom.〜 ■□■□ ******************************************************************************/