diff --git a/PowerEditor/src/tools/NppShell/codeblocks/NppShell.cbp b/PowerEditor/src/tools/NppShell/codeblocks/NppShell.cbp index 46708283a..daf66435b 100644 --- a/PowerEditor/src/tools/NppShell/codeblocks/NppShell.cbp +++ b/PowerEditor/src/tools/NppShell/codeblocks/NppShell.cbp @@ -14,6 +14,7 @@ + @@ -36,6 +37,7 @@ + @@ -53,13 +55,17 @@ + + + + diff --git a/PowerEditor/src/tools/NppShell/src/Bitmap.cpp b/PowerEditor/src/tools/NppShell/src/Bitmap.cpp new file mode 100644 index 000000000..79e1c5076 --- /dev/null +++ b/PowerEditor/src/tools/NppShell/src/Bitmap.cpp @@ -0,0 +1,125 @@ +//From: Visual Style Menus in MSDN + +#include "Bitmap.h" +#include + +void InitBitmapInfo(BITMAPINFO *pbmi, ULONG cbInfo, LONG cx, LONG cy, WORD bpp) +{ + ZeroMemory(pbmi, cbInfo); + pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pbmi->bmiHeader.biPlanes = 1; + pbmi->bmiHeader.biCompression = BI_RGB; + + pbmi->bmiHeader.biWidth = cx; + pbmi->bmiHeader.biHeight = cy; + pbmi->bmiHeader.biBitCount = bpp; +} + +HRESULT Create32BitHBITMAP(HDC hdc, const SIZE *psize, void **ppvBits, HBITMAP* phBmp) +{ + *phBmp = NULL; + + BITMAPINFO bmi; + InitBitmapInfo(&bmi, sizeof(bmi), psize->cx, psize->cy, 32); + + HDC hdcUsed = hdc ? hdc : GetDC(NULL); + if (hdcUsed) + { + *phBmp = CreateDIBSection(hdcUsed, &bmi, DIB_RGB_COLORS, ppvBits, NULL, 0); + if (hdc != hdcUsed) + { + ReleaseDC(NULL, hdcUsed); + } + } + return (NULL == *phBmp) ? E_OUTOFMEMORY : S_OK; +} + +HRESULT ConvertToPARGB32(HDC hdc, ARGB *pargb, HBITMAP hbmp, SIZE& sizImage, int cxRow) +{ + BITMAPINFO bmi; + InitBitmapInfo(&bmi, sizeof(bmi), sizImage.cx, sizImage.cy, 32); + + HRESULT hr = E_OUTOFMEMORY; + HANDLE hHeap = GetProcessHeap(); + void *pvBits = HeapAlloc(hHeap, 0, bmi.bmiHeader.biWidth * 4 * bmi.bmiHeader.biHeight); + if (pvBits) + { + hr = E_UNEXPECTED; + if (GetDIBits(hdc, hbmp, 0, bmi.bmiHeader.biHeight, pvBits, &bmi, DIB_RGB_COLORS) == bmi.bmiHeader.biHeight) + { + ULONG cxDelta = cxRow - bmi.bmiHeader.biWidth; + ARGB *pargbMask = static_cast(pvBits); + + for (ULONG y = bmi.bmiHeader.biHeight; y; --y) + { + for (ULONG x = bmi.bmiHeader.biWidth; x; --x) + { + if (*pargbMask++) + { + // transparent pixel + *pargb++ = 0; + } + else + { + // opaque pixel + *pargb++ |= 0xFF000000; + } + } + + pargb += cxDelta; + } + + hr = S_OK; + } + + HeapFree(hHeap, 0, pvBits); + } + + return hr; +} + +bool HasAlpha(ARGB *pargb, SIZE& sizImage, int cxRow) +{ + ULONG cxDelta = cxRow - sizImage.cx; + for (ULONG y = sizImage.cy; y; --y) + { + for (ULONG x = sizImage.cx; x; --x) + { + if (*pargb++ & 0xFF000000) + { + return true; + } + } + + pargb += cxDelta; + } + + return false; +} + +HRESULT ConvertBufferToPARGB32(HPAINTBUFFER hPaintBuffer, HDC hdc, HICON hicon, SIZE& sizIcon) +{ + RGBQUAD *prgbQuad; + int cxRow; + HRESULT hr = GetBufferedPaintBits(hPaintBuffer, &prgbQuad, &cxRow); + if (SUCCEEDED(hr)) + { + ARGB *pargb = reinterpret_cast(prgbQuad); + if (!HasAlpha(pargb, sizIcon, cxRow)) + { + ICONINFO info; + if (GetIconInfo(hicon, &info)) + { + if (info.hbmMask) + { + hr = ConvertToPARGB32(hdc, pargb, info.hbmMask, sizIcon, cxRow); + } + + DeleteObject(info.hbmColor); + DeleteObject(info.hbmMask); + } + } + } + + return hr; +} diff --git a/PowerEditor/src/tools/NppShell/src/Bitmap.h b/PowerEditor/src/tools/NppShell/src/Bitmap.h new file mode 100644 index 000000000..03de5fb9c --- /dev/null +++ b/PowerEditor/src/tools/NppShell/src/Bitmap.h @@ -0,0 +1,10 @@ +#include +#include + +typedef DWORD ARGB; + +void InitBitmapInfo(BITMAPINFO *pbmi, ULONG cbInfo, LONG cx, LONG cy, WORD bpp); +HRESULT Create32BitHBITMAP(HDC hdc, const SIZE *psize, void **ppvBits, HBITMAP* phBmp); +HRESULT ConvertToPARGB32(HDC hdc, ARGB *pargb, HBITMAP hbmp, SIZE& sizImage, int cxRow); +bool HasAlpha(ARGB *pargb, SIZE& sizImage, int cxRow); +HRESULT ConvertBufferToPARGB32(HPAINTBUFFER hPaintBuffer, HDC hdc, HICON hicon, SIZE& sizIcon); diff --git a/PowerEditor/src/tools/NppShell/src/NppShell.cpp b/PowerEditor/src/tools/NppShell/src/NppShell.cpp index 56538a5c7..d5d617006 100644 --- a/PowerEditor/src/tools/NppShell/src/NppShell.cpp +++ b/PowerEditor/src/tools/NppShell/src/NppShell.cpp @@ -1,9 +1,13 @@ #include "NppShell.h" +//#include "Bitmap.h" #include "resource.h" #include #include +//#include + + //--------------------------------------------------------------------------- // Global variables //--------------------------------------------------------------------------- @@ -43,6 +47,7 @@ void MsgBox(LPCTSTR lpszMsg); void MsgBoxError(LPCTSTR lpszMsg); BOOL CheckNpp(LPCTSTR path); INT_PTR CALLBACK DlgProcSettings(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +void InvalidateIcon(HICON * iconSmall, HICON * iconLarge); #ifdef UNICODE #define _ttoi _wtoi @@ -619,12 +624,38 @@ STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmd InsertMenu(hMenu, nIndex, MF_STRING|MF_BYPOSITION, idCmd++, m_szMenuTitle); + HBITMAP icon = NULL; + if (m_showIcon) {/* + if (m_supportARGB32) { + icon = NULL; + HICON hicon; + DWORD menuIconWidth = GetSystemMetrics(SM_CXMENUCHECK); + DWORD menuIconHeight = GetSystemMetrics(SM_CYMENUCHECK); + HRESULT hr = LoadShellIcon(menuIconWidth, menuIconHeight, &hicon); + if (SUCCEEDED(hr)) { + HBITMAP hbitmap; + LoadARGBBitmap(hicon, menuIconWidth, menuIconHeight, &hbitmap); + if (SUCCEEDED(hr)) { + icon = hbitmap; + } + } + } else { + icon = HBMMENU_CALLBACK; + }*/ + DWORD menuIconWidth = GetSystemMetrics(SM_CXMENUCHECK); + DWORD menuIconHeight = GetSystemMetrics(SM_CYMENUCHECK); + HRESULT hr = LoadShellBitmap(menuIconWidth, menuIconHeight, &icon); + if (FAILED(hr)) + MsgBoxError(TEXT("Help")); + } + MENUITEMINFO mii; ZeroMemory(&mii, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_BITMAP; - mii.hbmpItem = HBMMENU_CALLBACK; - SetMenuItemInfo(hMenu, nIndex, MF_BYPOSITION, &mii); + mii.hbmpItem = icon; + //SetMenuItemInfo(hMenu, nIndex, MF_BYPOSITION, &mii); + SetMenuItemBitmaps(hMenu, nIndex, MF_BYPOSITION, icon, icon); m_hMenu = hMenu; m_menuID = idCmd; @@ -632,6 +663,11 @@ STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmd return ResultFromShort(idCmd-idCmdFirst); } + + + + + STDMETHODIMP CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) { HRESULT hr = E_INVALIDARG; @@ -667,35 +703,33 @@ STDMETHODIMP CShellExt::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, switch(uMsg) { case WM_MEASUREITEM: { //for owner drawn menu - MEASUREITEMSTRUCT * pmis = (MEASUREITEMSTRUCT*) lParam; + MEASUREITEMSTRUCT * lpdis = (MEASUREITEMSTRUCT*) lParam; + if (lpdis == NULL) + break; - //Keep 0, as we use the space used for checkmarks and whatnot - pmis->itemWidth = 0;//menuIconWidth + menuIconPadding; - pmis->itemHeight = 0;//menuItemHeight + menuIconPadding; + lpdis->itemWidth += menuIconPadding; + if (lpdis->itemHeight < menuIconHeight) + lpdis->itemHeight = menuIconHeight; if (plResult) *plResult = TRUE; - break; } case WM_DRAWITEM: { //for owner drawn menu //Assumes proper font already been set DRAWITEMSTRUCT * lpdis = (DRAWITEMSTRUCT*) lParam; - UINT icon = IDI_ICON_NPP_BASE + m_iconID; - if (icon > IDI_ICON_NPP_MAX) - icon = IDI_ICON_NPP_MAX; + if ((lpdis == NULL) || (lpdis->CtlType != ODT_MENU)) + break; if (m_showIcon) { - HICON nppIcon = (HICON)LoadImage(_hModule, MAKEINTRESOURCE(icon), IMAGE_ICON, menuIconWidth, menuIconHeight, 0); - if (m_useCustom) { - HICON customIcon = (HICON)LoadImage(NULL, m_szCustomPath, IMAGE_ICON, menuIconWidth, menuIconHeight, LR_DEFAULTCOLOR|LR_LOADFROMFILE); - if (customIcon != NULL) { - DestroyIcon(nppIcon); - nppIcon = customIcon; - } + HICON nppIcon = NULL; + + HRESULT hr = LoadShellIcon(menuIconWidth, menuIconHeight, &nppIcon); + + if (SUCCEEDED(hr)) { + DrawIconEx(lpdis->hDC, menuIconPadding, menuIconPadding, nppIcon, menuIconWidth, menuIconHeight, 0, NULL, DI_NORMAL); + DestroyIcon(nppIcon); } - DrawIconEx(lpdis->hDC, menuIconPadding, menuIconPadding, nppIcon, menuIconWidth, menuIconHeight, 0, NULL, DI_NORMAL); - DestroyIcon(nppIcon); } if (plResult) @@ -756,43 +790,36 @@ STDMETHODIMP CShellExt::Extract(LPCTSTR pszFile, UINT nIconIndex, HICON * phicon WORD sizeSmall = HIWORD(nIconSize); WORD sizeLarge = LOWORD(nIconSize); ICONINFO iconinfo; + BOOL res; + HRESULT hrSmall = S_OK, hrLarge = S_OK; - int iconID = IDI_ICON_NPP_BASE + m_iconID; - if (iconID > IDI_ICON_NPP_MAX) - iconID = IDI_ICON_NPP_BASE; + if (phiconSmall) + hrSmall = LoadShellIcon(sizeSmall, sizeSmall, phiconSmall); + if (phiconLarge) + hrLarge = LoadShellIcon(sizeLarge, sizeLarge, phiconLarge); - HICON iconSmall = (HICON)LoadImage(_hModule, MAKEINTRESOURCE(iconID), IMAGE_ICON, sizeSmall, sizeSmall, LR_DEFAULTCOLOR); - HICON iconLarge = (HICON)LoadImage(_hModule, MAKEINTRESOURCE(iconID), IMAGE_ICON, sizeLarge, sizeLarge, LR_DEFAULTCOLOR); - - *phiconSmall = iconSmall; - *phiconLarge = iconLarge; - - if (m_useCustom) { - HICON customSmall = (HICON)LoadImage(NULL, m_szCustomPath, IMAGE_ICON, sizeSmall, sizeSmall, LR_DEFAULTCOLOR|LR_LOADFROMFILE); - HICON customLarge = (HICON)LoadImage(NULL, m_szCustomPath, IMAGE_ICON, sizeLarge, sizeLarge, LR_DEFAULTCOLOR|LR_LOADFROMFILE); - - if (customSmall != NULL) { - DestroyIcon(*phiconSmall); - *phiconSmall = customSmall; - } - - if (customLarge != NULL) { - DestroyIcon(*phiconLarge); - *phiconLarge = customLarge; - } + if (FAILED(hrSmall) || FAILED(hrLarge)) { + InvalidateIcon(phiconSmall, phiconLarge); + return S_FALSE; } - if (!m_isDynamic) + if (!m_isDynamic || !phiconLarge) //No modifications required return S_OK; - HICON newIconLarge; HDC dcEditColor, dcEditMask; HGDIOBJ oldBitmapColor, oldBitmapMask, oldFontColor; HFONT font; HBRUSH brush; - GetIconInfo(*phiconLarge, &iconinfo); - DestroyIcon(*phiconLarge); + res = GetIconInfo(*phiconLarge, &iconinfo); + if (!res) + return S_OK; //abort, the icon is still valid + + res = DestroyIcon(*phiconLarge); + if (!res) + return S_OK; + else + *phiconLarge = NULL; dcEditColor = CreateCompatibleDC(GetDC(0)); dcEditMask = CreateCompatibleDC(GetDC(0)); @@ -858,12 +885,29 @@ STDMETHODIMP CShellExt::Extract(LPCTSTR pszFile, UINT nIconIndex, HICON * phicon DeleteBrush(brush); - newIconLarge = CreateIconIndirect(&iconinfo); - *phiconLarge = newIconLarge; + *phiconLarge = CreateIconIndirect(&iconinfo); + res = DeleteBitmap(iconinfo.hbmColor); + res = DeleteBitmap(iconinfo.hbmMask); + + if (*phiconLarge == NULL) { + InvalidateIcon(phiconSmall, phiconLarge); + return S_FALSE; + } return S_OK; } +void InvalidateIcon(HICON * iconSmall, HICON * iconLarge) { + if (iconSmall && *iconSmall) { + DestroyIcon(*iconSmall); + *iconSmall = NULL; + } + if (iconLarge && *iconLarge) { + DestroyIcon(*iconLarge); + *iconLarge = NULL; + } +} + // *** Private methods *** STDMETHODIMP CShellExt::InvokeNPP(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, int iShowCmd) { TCHAR szFilename[MAX_PATH]; @@ -940,12 +984,145 @@ STDMETHODIMP CShellExt::InvokeNPP(HWND hParent, LPCSTR pszWorkingDir, LPCSTR psz si.wShowWindow = iShowCmd; //SW_RESTORE; if (!CreateProcess (NULL, pszCommand, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { DWORD errorCode = GetLastError(); - TCHAR * message = new TCHAR[512+bytesRequired]; - wsprintf(message, TEXT("Error in CreateProcess (%d): Is this command correct?\r\n%s"), errorCode, pszCommand); - MsgBoxError(message); - delete [] message; + if (errorCode == ERROR_ELEVATION_REQUIRED) { //Fallback to shellexecute + CoInitializeEx(NULL, 0); + HINSTANCE execVal = ShellExecute(NULL, TEXT("runas"), pszCommand, NULL, NULL, iShowCmd); + CoUninitialize(); + if (execVal <= (HINSTANCE)32) { + TCHAR * message = new TCHAR[512+bytesRequired]; + wsprintf(message, TEXT("ShellExecute failed (%d): Is this command correct?\r\n%s"), execVal, pszCommand); + MsgBoxError(message); + delete [] message; + } + } else { + TCHAR * message = new TCHAR[512+bytesRequired]; + wsprintf(message, TEXT("Error in CreateProcess (%d): Is this command correct?\r\n%s"), errorCode, pszCommand); + MsgBoxError(message); + delete [] message; + } } + + CoTaskMemFree(pszCommand); return NOERROR; } + +STDMETHODIMP CShellExt::LoadShellIcon(int cx, int cy, HICON * phicon) { + HRESULT hr = E_OUTOFMEMORY; + HICON hicon = NULL; + + if (m_useCustom) { + hicon = (HICON)LoadImage(NULL, m_szCustomPath, IMAGE_ICON, cx, cy, LR_DEFAULTCOLOR|LR_LOADFROMFILE); + } + + //Either no custom defined, or failed and use fallback + if (hicon == NULL) { + int iconID = IDI_ICON_NPP_BASE + m_iconID; + if (iconID > IDI_ICON_NPP_MAX) + iconID = IDI_ICON_NPP_BASE; + + hicon = (HICON)LoadImage(_hModule, MAKEINTRESOURCE(iconID), IMAGE_ICON, cx, cy, 0); + } + + if (hicon == NULL) { + hr = E_OUTOFMEMORY; + *phicon = NULL; + } else { + hr = S_OK; + *phicon = hicon; + } + + return hr; +} + +STDMETHODIMP CShellExt::LoadShellBitmap(int cx, int cy, HBITMAP * phbitmap) { + HRESULT hr = E_OUTOFMEMORY; + HBITMAP hbitmap = NULL; + + if (m_useCustom) { + hbitmap = (HBITMAP)LoadImage(NULL, m_szCustomPath, IMAGE_BITMAP, cx, cy, LR_DEFAULTCOLOR|LR_LOADFROMFILE); + } + + //Either no custom defined, or failed and use fallback + if (hbitmap == NULL) { + int iconID = IDB_BITMAP_NPP;//IDI_ICON_NPP_BASE + m_iconID; + if (iconID > IDI_ICON_NPP_MAX) + iconID = IDI_ICON_NPP_BASE; + + hbitmap = (HBITMAP)LoadImage(_hModule, MAKEINTRESOURCE(iconID), IMAGE_BITMAP, cx, cy, 0); + } + + if (hbitmap == NULL) { + hr = E_OUTOFMEMORY; + *phbitmap = NULL; + } else { + hr = S_OK; + *phbitmap = hbitmap; + } + + return hr; +} + +/* +STDMETHODIMP CShellExt::LoadARGBBitmap(HICON icon, int cx, int cy, HBITMAP * phbitmap) { + HRESULT hr = E_OUTOFMEMORY; + HBITMAP hbmp = NULL; + + SIZE sizIcon; + sizIcon.cx = cx; + sizIcon.cy = cy; + + RECT rcIcon; + SetRect(&rcIcon, 0, 0, sizIcon.cx, sizIcon.cy); + + HDC hdcDest = CreateCompatibleDC(NULL); + if (hdcDest) + { + hr = Create32BitHBITMAP(hdcDest, &sizIcon, NULL, &hbmp); + if (SUCCEEDED(hr)) + { + hr = E_FAIL; + + HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcDest, hbmp); + if (hbmpOld) + { + BLENDFUNCTION bfAlpha = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; + BP_PAINTPARAMS paintParams = {0}; + paintParams.cbSize = sizeof(paintParams); + paintParams.dwFlags = BPPF_ERASE; + paintParams.pBlendFunction = &bfAlpha; + + HDC hdcBuffer; + HPAINTBUFFER hPaintBuffer = pBeginBufferedPaint(hdcDest, &rcIcon, BPBF_DIB, &paintParams, &hdcBuffer); + if (hPaintBuffer) + { + if (DrawIconEx(hdcBuffer, 0, 0, hicon, sizIcon.cx, sizIcon.cy, 0, NULL, DI_NORMAL)) + { + // If icon did not have an alpha channel, we need to convert buffer to PARGB. + hr = ConvertBufferToPARGB32(hPaintBuffer, hdcDest, hicon, sizIcon); + } + + // This will write the buffer contents to the destination bitmap. + pEndBufferedPaint(hPaintBuffer, TRUE); + } + + SelectObject(hdcDest, hbmpOld); + } + } + + DeleteDC(hdcDest); + } + + if (FAILED(hr)) { + DeleteBitmap(hbmp); + hbmp = NULL; + } + + if (phbitmap) + *phbitmap = hbmp; + + return hr; + +} +*/ diff --git a/PowerEditor/src/tools/NppShell/src/NppShell.h b/PowerEditor/src/tools/NppShell/src/NppShell.h index 43c8d48d7..d42a44a80 100644 --- a/PowerEditor/src/tools/NppShell/src/NppShell.h +++ b/PowerEditor/src/tools/NppShell/src/NppShell.h @@ -16,6 +16,9 @@ #include #include +//This is not ideal, but missing from current mingw +#define ERROR_ELEVATION_REQUIRED 740 + #define GUID_SIZE 128 #define GUID_STRING_SIZE 40 #define TITLE_SIZE 64 @@ -85,6 +88,9 @@ private: // *** Private methods *** STDMETHODIMP InvokeNPP(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, int iShowCmd); + STDMETHODIMP LoadShellIcon(int cx, int cy, HICON * phicon); + STDMETHODIMP LoadShellBitmap(int cx, int cy, HBITMAP * phbitmap); + //STDMETHODIMP LoadARGBBitmap(HICON icon, int cx, int cy, HBITMAP * phbitmap); public: CShellExt(); diff --git a/PowerEditor/src/tools/NppShell/src/NppShell.rc b/PowerEditor/src/tools/NppShell/src/NppShell.rc index a6888f231..1b2baa422 100644 --- a/PowerEditor/src/tools/NppShell/src/NppShell.rc +++ b/PowerEditor/src/tools/NppShell/src/NppShell.rc @@ -28,7 +28,7 @@ BEGIN VALUE "FileDescription", "ShellHandler for Notepad++" #endif VALUE "FileVersion", "0.1" - VALUE "LegalCopyright", "Copyright © 2008" + VALUE "LegalCopyright", "Copyright © 2010" #ifdef WIN64 VALUE "OriginalFilename", "NppShell64.dll" #else @@ -49,7 +49,7 @@ END // Icon // -IDI_ICON_NPP_0 ICON "icon\\npp_0.ico" +IDI_ICON_NPP_0 ICON "icon\\npp_1.ico" IDI_ICON_NPP_1 ICON "icon\\npp_1.ico" ///////////////////////////////////////////////////////////////////////////// @@ -81,5 +81,5 @@ BEGIN CONTROL "Show extension",IDC_CHECK_ISDYNAMIC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,42,67,10 CONTROL "Use classic icon",IDC_RADIO_CLASSIC,"Button",BS_AUTORADIOBUTTON | WS_GROUP,156,60,65,10 CONTROL "Use modern icon",IDC_RADIO_MODERN,"Button",BS_AUTORADIOBUTTON,156,72,69,10 - DEFPUSHBUTTON "Apply",IDOK,222,126,50,14 + DEFPUSHBUTTON "OK",IDOK,222,126,50,14 END