mirror of
https://github.com/chibicitiberiu/rainmeter-studio.git
synced 2024-02-24 04:33:31 +00:00
13c17b9d1a
- Merged Rainmeter.dll and Rainmeter.exe - Language resource file now located in \Language\<LanguageName>.dll - Build.bat now automatically builds and packages all languages
357 lines
8.5 KiB
C++
357 lines
8.5 KiB
C++
/*
|
|
Copyright (C) 2001 Kimmo Pekkola
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#define _CRTDBG_MAP_ALLOC
|
|
#include "StdAfx.h"
|
|
#include "resource.h"
|
|
#include "Rainmeter.h"
|
|
#include "TrayWindow.h"
|
|
|
|
#if defined _M_IX86
|
|
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
|
#elif defined _M_IA64
|
|
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
|
#elif defined _M_X64
|
|
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
|
#else
|
|
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
|
#endif
|
|
|
|
extern CRainmeter* Rainmeter;
|
|
|
|
void Bang(const WCHAR* command);
|
|
BOOL InitApplication(HINSTANCE hInstance, const WCHAR* WinClass);
|
|
HWND InitInstance(HINSTANCE hInstance, const WCHAR* WinClass, const WCHAR* WinName);
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
BOOL IsRunning(HANDLE* hMutex);
|
|
|
|
const WCHAR* WinClass = L"DummyRainWClass";
|
|
const WCHAR* WinName = L"Rainmeter control window";
|
|
|
|
enum RetValue
|
|
{
|
|
RetSuccess = 0,
|
|
RetError = 1
|
|
};
|
|
|
|
/*
|
|
** WinMain
|
|
**
|
|
** The Main-function
|
|
**
|
|
*/
|
|
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
|
|
{
|
|
HANDLE hMutex = NULL;
|
|
MSG msg;
|
|
BOOL bRet;
|
|
HWND hWnd;
|
|
|
|
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
|
// _CrtSetBreakAlloc(5055);
|
|
|
|
// Avoid loading a dll from current directory
|
|
SetDllDirectory(L"");
|
|
|
|
if (lpCmdLine && lpCmdLine[0] == L'!')
|
|
{
|
|
// It's a !bang
|
|
Bang(lpCmdLine);
|
|
return RetSuccess;
|
|
}
|
|
|
|
// Check whether Rainmeter.exe is already running
|
|
if (IsRunning(&hMutex))
|
|
{
|
|
//MessageBox(NULL, L"Rainmeter.exe is already running.", L"Rainmeter", MB_ICONWARNING | MB_TOPMOST | MB_OK);
|
|
return RetSuccess;
|
|
}
|
|
|
|
if (!hPrevInstance)
|
|
{
|
|
if (!InitApplication(hInstance, WinClass)) return RetError;
|
|
}
|
|
|
|
hWnd = InitInstance(hInstance, WinClass, WinName);
|
|
if (!hWnd) return RetError;
|
|
|
|
// Remove quotes from the commandline
|
|
WCHAR Path[MAX_PATH+1] = {0};
|
|
if (lpCmdLine)
|
|
{
|
|
size_t Pos = 0;
|
|
for (size_t i = 0, len = wcslen(lpCmdLine); i <= len && Pos < MAX_PATH; ++i)
|
|
{
|
|
if (lpCmdLine[i] != L'\"') Path[Pos++] = lpCmdLine[i];
|
|
}
|
|
}
|
|
|
|
int result = 1;
|
|
try
|
|
{
|
|
Rainmeter = new CRainmeter;
|
|
|
|
if (Rainmeter)
|
|
{
|
|
result = Rainmeter->Initialize(hWnd, hInstance, lpCmdLine);
|
|
}
|
|
}
|
|
catch (CError& error)
|
|
{
|
|
MessageBox(hWnd, error.GetString().c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
|
|
}
|
|
|
|
if (result == 1)
|
|
{
|
|
DestroyWindow(hWnd);
|
|
}
|
|
else
|
|
{
|
|
// Run the standard window message loop
|
|
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
|
|
{
|
|
if (bRet == -1) // error
|
|
{
|
|
CRainmeter::Quit();
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hMutex) ReleaseMutex(hMutex);
|
|
return (int)msg.wParam;
|
|
}
|
|
|
|
/*
|
|
** InitApplication
|
|
**
|
|
** Creates the windowclass
|
|
**
|
|
*/
|
|
BOOL InitApplication(HINSTANCE hInstance, const WCHAR* WinClass)
|
|
{
|
|
WNDCLASS wc;
|
|
|
|
wc.style = 0;
|
|
wc.lpfnWndProc = (WNDPROC)WndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = hInstance;
|
|
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOW));
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = WinClass;
|
|
|
|
return RegisterClass(&wc);
|
|
}
|
|
|
|
/*
|
|
** InitInstance
|
|
**
|
|
** Creates the window. This is just an invisible window. The real window
|
|
** is created by the DLL.
|
|
**
|
|
*/
|
|
HWND InitInstance(HINSTANCE hInstance, const WCHAR* WinClass, const WCHAR* WinName)
|
|
{
|
|
return CreateWindowEx(
|
|
WS_EX_TOOLWINDOW,
|
|
WinClass,
|
|
WinName,
|
|
WS_POPUP | WS_DISABLED,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
NULL,
|
|
NULL,
|
|
hInstance,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
/*
|
|
** Bang
|
|
**
|
|
** Sends bangs to the DLL
|
|
**
|
|
*/
|
|
void Bang(const WCHAR* command)
|
|
{
|
|
// Check if Rainmeter is running
|
|
HWND wnd = FindWindow(WinClass, WinName);
|
|
if (wnd != NULL)
|
|
{
|
|
COPYDATASTRUCT copyData;
|
|
|
|
copyData.dwData = 1;
|
|
copyData.cbData = (DWORD)((wcslen(command) + 1) * sizeof(WCHAR));
|
|
copyData.lpData = (void*)command;
|
|
|
|
// Send the bang to the Rainmeter window
|
|
SendMessage(wnd, WM_COPYDATA, (WPARAM)NULL, (LPARAM)©Data);
|
|
}
|
|
else
|
|
{
|
|
if (_wcsicmp(L"!rainmeterquit", command) != 0 &&
|
|
_wcsicmp(L"!quit", command) != 0)
|
|
{
|
|
MessageBox(NULL, L"Rainmeter is not running.\nUnable to send the !bang to it.", L"Rainmeter", MB_OK | MB_TOPMOST | MB_ICONERROR);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** RmLoadSystemLibrary
|
|
**
|
|
** Loads a system dll from system32 directory.
|
|
**
|
|
*/
|
|
HMODULE RmLoadSystemLibrary(LPCWSTR lpLibFileName)
|
|
{
|
|
WCHAR buffer[MAX_PATH];
|
|
std::wstring path;
|
|
|
|
if (GetSystemDirectory(buffer, MAX_PATH))
|
|
{
|
|
path = buffer;
|
|
path += L"\\";
|
|
path += lpLibFileName;
|
|
|
|
return LoadLibrary(path.c_str());
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
** IsRunning
|
|
**
|
|
** Checks whether Rainmeter.exe is running.
|
|
**
|
|
*/
|
|
BOOL IsRunning(HANDLE* hMutex)
|
|
{
|
|
typedef struct
|
|
{
|
|
ULONG i[2];
|
|
ULONG buf[4];
|
|
unsigned char in[64];
|
|
unsigned char digest[16];
|
|
} MD5_CTX;
|
|
|
|
typedef void (WINAPI *FPMD5INIT)(MD5_CTX *context);
|
|
typedef void (WINAPI *FPMD5UPDATE)(MD5_CTX *context, const unsigned char *input, unsigned int inlen);
|
|
typedef void (WINAPI *FPMD5FINAL)(MD5_CTX *context);
|
|
|
|
// Create MD5 digest from command line
|
|
HMODULE hCryptDll = RmLoadSystemLibrary(L"cryptdll.dll");
|
|
if (!hCryptDll) // Unable to check the mutex
|
|
{
|
|
*hMutex = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
FPMD5INIT MD5Init = (FPMD5INIT)GetProcAddress(hCryptDll, "MD5Init");
|
|
FPMD5UPDATE MD5Update = (FPMD5UPDATE)GetProcAddress(hCryptDll, "MD5Update");
|
|
FPMD5FINAL MD5Final = (FPMD5FINAL)GetProcAddress(hCryptDll, "MD5Final");
|
|
if (!MD5Init || !MD5Update || !MD5Final) // Unable to check the mutex
|
|
{
|
|
FreeLibrary(hCryptDll);
|
|
*hMutex = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
std::wstring cmdLine = GetCommandLine();
|
|
std::transform(cmdLine.begin(), cmdLine.end(), cmdLine.begin(), ::towlower);
|
|
|
|
MD5_CTX ctx = {0};
|
|
|
|
MD5Init(&ctx);
|
|
MD5Update(&ctx, (LPBYTE)cmdLine.c_str(), cmdLine.length() * sizeof(WCHAR));
|
|
MD5Final(&ctx);
|
|
|
|
FreeLibrary(hCryptDll);
|
|
|
|
// Convert MD5 digest to mutex string (e.g. "Rainmeter@0123456789abcdef0123456789abcdef")
|
|
const WCHAR szHexTable[] = L"0123456789abcdef";
|
|
WCHAR szMutex[64] = {0};
|
|
wcscpy(szMutex, L"Rainmeter@");
|
|
|
|
WCHAR* pos = szMutex + wcslen(szMutex);
|
|
|
|
for (size_t i = 0; i < 16; ++i)
|
|
{
|
|
*(pos++) = *(szHexTable + ((ctx.digest[i] >> 4) & 0xF));
|
|
*(pos++) = *(szHexTable + (ctx.digest[i] & 0xF));
|
|
}
|
|
|
|
// Create mutex
|
|
HANDLE hMutexTemp = CreateMutex(NULL, FALSE, szMutex);
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
|
{
|
|
// Rainmeter.exe is already running
|
|
*hMutex = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
// Rainmeter.exe is not running
|
|
*hMutex = hMutexTemp;
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
** WndProc
|
|
**
|
|
** The main window procedure
|
|
**
|
|
*/
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_DESTROY:
|
|
{
|
|
CRainmeter::Quit();
|
|
PostQuitMessage(0);
|
|
}
|
|
break;
|
|
|
|
case WM_COPYDATA:
|
|
{
|
|
COPYDATASTRUCT* cds = (COPYDATASTRUCT*)lParam;
|
|
if (Rainmeter && cds && (cds->dwData == 1) && (cds->cbData > 0) && cds->lpData)
|
|
{
|
|
ExecuteBang((LPCWSTR)cds->lpData);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
return 0;
|
|
}
|