diff options
author | Vadim Dashevskiy <watcherhd@gmail.com> | 2012-07-04 08:25:18 +0000 |
---|---|---|
committer | Vadim Dashevskiy <watcherhd@gmail.com> | 2012-07-04 08:25:18 +0000 |
commit | 5500b21532dfe16253820b109df71f8f5d3006f7 (patch) | |
tree | 79ce32a372e080691d7e4d8b85e3230e46a7ddf1 /plugins/AssocMgr/src/dde.cpp | |
parent | 0624d6b4e9b82ccfaabf7a20d00c474a09354e8d (diff) |
AssocMgr: changed folder structure
git-svn-id: http://svn.miranda-ng.org/main/trunk@751 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/AssocMgr/src/dde.cpp')
-rw-r--r-- | plugins/AssocMgr/src/dde.cpp | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/plugins/AssocMgr/src/dde.cpp b/plugins/AssocMgr/src/dde.cpp new file mode 100644 index 0000000000..a8328b4d34 --- /dev/null +++ b/plugins/AssocMgr/src/dde.cpp @@ -0,0 +1,295 @@ +/*
+
+'File Association Manager'-Plugin for Miranda IM
+
+Copyright (C) 2005-2007 H. Herkenrath
+
+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 (AssocMgr-License.txt); if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "common.h"
+
+/* Conversation */
+extern HINSTANCE hInst;
+static HWND hwndDdeMsg;
+/* Misc */
+static HANDLE hHookModulesLoaded,hHookPreShutdown;
+
+/************************* Open Handler ***************************/
+
+// pszFilePath needs to be allocated using mir_alloc()
+static void __stdcall FileActionAsync(void *param)
+{
+ TCHAR *pszFilePath = (TCHAR*)param;
+ /* invoke main handler */
+ switch(InvokeFileHandler(pszFilePath)) { /* pszFilePath is always a long path name */
+ case 0: /* success */ break;
+ case CALLSERVICE_NOTFOUND:
+ ShowInfoMessage(NIIF_ERROR,Translate("Miranda IM could not open file"),Translate("Miranda IM was not able to open \""TCHAR_STR_PARAM"\".\n\nThere is no registered handler for this file type."),pszFilePath);
+ break;
+ default:
+ ShowInfoMessage(NIIF_ERROR,Translate("Miranda IM could not open file"),Translate("Miranda IM was not able to open \""TCHAR_STR_PARAM"\".\n\nThe file could not be processed."),pszFilePath);
+ }
+ mir_free(pszFilePath); /* async param */
+}
+
+// pszUrl needs to be allocated using mir_alloc()
+static void __stdcall UrlActionAsync(void *param)
+{
+ TCHAR *pszUrl = (TCHAR*)param;
+ /* invoke main handler */
+ switch(InvokeUrlHandler(pszUrl)) {
+ case 0: /* success */ break;
+ case CALLSERVICE_NOTFOUND:
+ ShowInfoMessage(NIIF_ERROR,Translate("Miranda IM could not open URL"),Translate("Miranda IM was not able to open \""TCHAR_STR_PARAM"\".\n\nThere is no registered handler for this URL type."),pszUrl);
+ break;
+ default:
+ ShowInfoMessage(NIIF_ERROR,Translate("Miranda IM could not open URL"),Translate("Miranda IM was not able to open \""TCHAR_STR_PARAM"\".\n\nThe given URL is invalid and can not be parsed."),pszUrl);
+ }
+ mir_free(pszUrl); /* async param */
+}
+
+/************************* Conversation ***************************/
+
+#define DDEMESSAGETIMEOUT 30000
+#define WNDCLASS_DDEMSGWINDOW _T("MirandaDdeMsgWindow")
+
+// returned pointer points into a substring of ppszString
+// returns an empty string if the string does not have enough arguments
+static TCHAR* GetExecuteParam(TCHAR **ppszString)
+{
+ TCHAR *pszParam,*p;
+ BOOL fQuoted;
+
+ fQuoted=(**ppszString==_T('"'));
+ pszParam=*ppszString;
+ if(fQuoted) pszParam++;
+ p=_tcschr(pszParam,(TCHAR)(fQuoted?_T('"'):_T(',')));
+ if(p!=NULL) {
+ *(p++)=0;
+ if(fQuoted && *p==_T(',')) p++;
+ } else p=&pszParam[lstrlen(pszParam)];
+ *ppszString=p;
+ return pszParam;
+}
+
+static LRESULT CALLBACK DdeMessageWindow(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ switch(msg) {
+ case WM_DDE_INITIATE:
+ { ATOM hSzApp,hSzTopic;
+ hSzApp=LOWORD(lParam); /* no UnpackDDElParam() here */
+ hSzTopic=HIWORD(lParam);
+ if ((hSzApp==GlobalFindAtom(DDEAPP) && hSzTopic==GlobalFindAtom(DDETOPIC)) || !hSzApp) {
+ hSzApp=GlobalAddAtom(DDEAPP);
+ hSzTopic=GlobalAddAtom(DDETOPIC);
+ if(hSzApp && hSzTopic)
+ /* PackDDElParam() only for posted msgs */
+ SendMessage((HWND)wParam,WM_DDE_ACK,(WPARAM)hwnd,MAKELPARAM(hSzApp,hSzTopic));
+ if(hSzApp) GlobalDeleteAtom(hSzApp);
+ if(hSzTopic) GlobalDeleteAtom(hSzTopic);
+ }
+ return 0;
+ }
+ case WM_DDE_EXECUTE: /* posted message */
+ { HGLOBAL hCommand;
+ TCHAR *pszCommand;
+ DDEACK ack;
+ ZeroMemory(&ack,sizeof(ack));
+ if(UnpackDDElParam(msg,lParam,NULL,(PUINT_PTR)&hCommand)) {
+
+ /* ANSI execute command can't happen for shell */
+ if(IsWindowUnicode((HWND)wParam)) {
+
+ pszCommand = (TCHAR*)GlobalLock(hCommand);
+ if(pszCommand!=NULL) {
+ TCHAR *pszAction,*pszArg;
+ pszAction=GetExecuteParam(&pszCommand);
+ pszArg=mir_tstrdup(GetExecuteParam(&pszCommand));
+ if(pszArg!=NULL) {
+ /* we are inside miranda here, we make it async so the shell does
+ * not timeout regardless what the plugins try to do. */
+ if (!lstrcmpi(pszAction,_T("file")))
+ ack.fAck=(short)(CallFunctionAsync(FileActionAsync,pszArg)!=0);
+ else if (!lstrcmpi(pszAction,_T("url")))
+ ack.fAck=(short)(CallFunctionAsync(UrlActionAsync,pszArg)!=0);
+ if (!ack.fAck) mir_free(pszArg); /* otherwise freed by asyncproc */
+ }
+ GlobalUnlock(hCommand);
+ }
+
+ }
+
+ lParam=ReuseDDElParam(lParam,msg,WM_DDE_ACK,*(PUINT)&ack,(UINT)hCommand);
+ if (!PostMessage((HWND)wParam,WM_DDE_ACK,(WPARAM)hwnd,lParam)) {
+ GlobalFree(hCommand);
+ FreeDDElParam(WM_DDE_ACK,lParam);
+ }
+ }
+ return 0;
+ }
+ case WM_DDE_TERMINATE:
+ PostMessage((HWND)wParam,msg,(WPARAM)hwnd,0); /* ack reply */
+ return 0;
+ case WM_DDE_REQUEST:
+ case WM_DDE_ADVISE:
+ case WM_DDE_UNADVISE:
+ case WM_DDE_POKE:
+ /* fail safely for those to avoid memory leak in lParam */
+ { ATOM hSzItem;
+ DDEACK ack;
+ ZeroMemory(&ack,sizeof(ack));
+ if(UnpackDDElParam(msg,lParam,NULL,(PUINT_PTR)&hSzItem)) {
+ lParam=ReuseDDElParam(lParam,msg,WM_DDE_ACK,*(PUINT)&ack,(UINT)hSzItem);
+ if (!PostMessage((HWND)wParam,WM_DDE_ACK,(WPARAM)hwnd,lParam)) {
+ if(hSzItem) GlobalDeleteAtom(hSzItem);
+ FreeDDElParam(WM_DDE_ACK,lParam);
+ }
+ }
+ return 0;
+ }
+ }
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+}
+
+// CloseHandle() the return value
+static HANDLE StartupMainProcess(TCHAR *pszDatabasePath)
+{
+ TCHAR *p,szPath[MAX_PATH];
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+
+ /* we are inside RunDll32 here */
+ if (!GetModuleFileName(hInst,szPath,SIZEOF(szPath))) return NULL;
+ p=_tcsrchr(szPath,_T('\\'));
+ if(p!=NULL) { *p=0; p=_tcsrchr(szPath,_T('\\')); }
+ if(p==NULL) return NULL;
+ lstrcpy(++p,_T("miranda32.exe"));
+
+ /* inherit startup data from RunDll32 process */
+ GetStartupInfo(&si);
+ if (!CreateProcess(szPath,pszDatabasePath,NULL,NULL,TRUE,GetPriorityClass(GetCurrentProcess()),NULL,NULL,&si,&pi))
+ return NULL;
+ CloseHandle(pi.hThread);
+ return pi.hProcess;
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// entry point for RunDll32, this is also WaitForDDEW
+__declspec(dllexport) void CALLBACK WaitForDDE(HWND hwnd,HINSTANCE hinstExe,TCHAR *pszCmdLine,int nCmdShow)
+{
+ HANDLE pHandles[2];
+ DWORD dwTick;
+ UNREFERENCED_PARAMETER(hinstExe);
+ UNREFERENCED_PARAMETER(nCmdShow); /* obeys nCmdShow using GetStartupInfo() */
+ UNREFERENCED_PARAMETER(hwnd);
+
+ /* wait for dde window to be available (avoiding race condition) */
+ pHandles[0]=CreateEvent(NULL,TRUE,FALSE,WNDCLASS_DDEMSGWINDOW);
+ if(pHandles[0]!=NULL) {
+ pHandles[1]=StartupMainProcess(pszCmdLine); /* obeys nCmdShow using GetStartupInfo() */
+ if(pHandles[1]!=NULL) {
+ dwTick=GetTickCount();
+ /* either process terminated or dde window created */
+ if(WaitForMultipleObjects(SIZEOF(pHandles),pHandles,FALSE,DDEMESSAGETIMEOUT)==WAIT_OBJECT_0) {
+ dwTick=GetTickCount()-dwTick;
+ if(dwTick<DDEMESSAGETIMEOUT)
+ WaitForInputIdle(pHandles[1],DDEMESSAGETIMEOUT-dwTick);
+ }
+ CloseHandle(pHandles[1]);
+ }
+ CloseHandle(pHandles[0]);
+ }
+ /* shell called WaitForInputIdle() on us to detect when dde is ready,
+ * we are ready now: exit helper process */
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/************************* Misc ***********************************/
+
+static int DdePreShutdown(WPARAM wParam,LPARAM lParam)
+{
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+ /* dde needs to be stopped before any plugins are unloaded */
+ if(hwndDdeMsg!=NULL) DestroyWindow(hwndDdeMsg);
+ UnregisterClass(WNDCLASS_DDEMSGWINDOW,hInst);
+ return 0;
+}
+
+static int DdeModulesLoaded2(WPARAM wParam,LPARAM lParam)
+{
+ WNDCLASS wcl;
+ HANDLE hEvent;
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+
+ /* create message window */
+ wcl.lpfnWndProc=DdeMessageWindow;
+ wcl.cbClsExtra=0;
+ wcl.cbWndExtra=0;
+ wcl.hInstance=hInst;
+ wcl.hCursor=NULL;
+ wcl.lpszClassName=WNDCLASS_DDEMSGWINDOW;
+ wcl.hbrBackground=NULL;
+ wcl.hIcon=NULL;
+ wcl.lpszMenuName=NULL;
+ wcl.style=0;
+ RegisterClass(&wcl);
+ /* Note: use of HWND_MESSAGE does not fit for DDE as the window must be a top-level one */
+ hwndDdeMsg=CreateWindow(WNDCLASS_DDEMSGWINDOW,NULL,0,0,0,0,0,NULL,NULL,hInst,NULL);
+
+ /* make known dde startup code is passed */
+ hEvent=OpenEvent(EVENT_MODIFY_STATE,FALSE,WNDCLASS_DDEMSGWINDOW);
+ if(hEvent!=NULL) {
+ SetEvent(hEvent);
+ CloseHandle(hEvent);
+ }
+
+ CleanupRegTreeBackupSettings();
+ CleanupMimeTypeAddedSettings();
+ CleanupAssocEnabledSettings();
+ return 0;
+}
+
+static int DdeModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+ /* dde needs to be loaded after all the other plugins got loaded,
+ * hook again to get the latest position in chain */
+ UnhookEvent(hHookModulesLoaded);
+ hHookModulesLoaded=HookEvent(ME_SYSTEM_MODULESLOADED,DdeModulesLoaded2);
+ return 0;
+}
+
+void InitDde(void)
+{
+ hHookModulesLoaded=HookEvent(ME_SYSTEM_MODULESLOADED,DdeModulesLoaded);
+ hHookPreShutdown=HookEvent(ME_SYSTEM_PRESHUTDOWN,DdePreShutdown);
+}
+
+void UninitDde(void)
+{
+ UnhookEvent(hHookModulesLoaded);
+ UnhookEvent(hHookPreShutdown);
+}
+
|