Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

169 lines
5.6 KiB

  1. #include <windows.h>
  2. #include <shlwapi.h>
  3. #include <commctrl.h>
  4. #include "dataitem.h"
  5. #include "resource.h"
  6. #include "autorun.h"
  7. #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
  8. CDataItem::CDataItem()
  9. {
  10. m_pszTitle = m_pszMenuName = m_pszDescription = m_pszCmdLine = m_pszArgs = NULL;
  11. m_dwFlags = 0;
  12. m_chAccel = NULL;
  13. }
  14. CDataItem::~CDataItem()
  15. {
  16. if ( m_pszTitle )
  17. delete [] m_pszTitle;
  18. if ( m_pszMenuName )
  19. delete [] m_pszMenuName;
  20. if ( m_pszDescription )
  21. delete [] m_pszDescription;
  22. if ( m_pszCmdLine )
  23. delete [] m_pszCmdLine;
  24. if ( m_pszArgs )
  25. delete [] m_pszArgs;
  26. }
  27. BOOL CDataItem::SetData( LPTSTR szTitle, LPTSTR szMenu, LPTSTR szDesc, LPTSTR szCmd, LPTSTR szArgs, DWORD dwFlags, int iImgIndex )
  28. {
  29. TCHAR * psz;
  30. // This function should only be called once or else we will leak like a, like a, a thing that leaks a lot.
  31. ASSERT( NULL==m_pszTitle && NULL==m_pszMenuName && NULL==m_pszDescription && NULL==m_pszCmdLine && NULL==m_pszArgs );
  32. m_pszTitle = new TCHAR[lstrlen(szTitle)+1];
  33. if ( m_pszTitle )
  34. lstrcpy( m_pszTitle, szTitle );
  35. if ( szMenu )
  36. {
  37. // menuname is allowed to remain NULL. This is only used if you want the
  38. // text on the menu item to be different than the description. This could
  39. // be useful for localization where a shortened name might be required.
  40. m_pszMenuName = new TCHAR[lstrlen(szMenu)+1];
  41. if ( m_pszMenuName )
  42. lstrcpy( m_pszMenuName, szMenu );
  43. psz = StrChr(szMenu, TEXT('&'));
  44. if ( psz )
  45. m_chAccel = *(CharNext(psz));
  46. }
  47. m_pszDescription = new TCHAR[lstrlen(szDesc)+1];
  48. if ( m_pszDescription )
  49. lstrcpy( m_pszDescription, szDesc );
  50. m_pszCmdLine = new TCHAR[lstrlen(szCmd)+1];
  51. if ( m_pszCmdLine )
  52. lstrcpy( m_pszCmdLine, szCmd );
  53. if ( szArgs )
  54. {
  55. // Some commands don't have any args so this can remain NULL. This is only used
  56. // if the executable requires arguments.
  57. m_pszArgs = new TCHAR[lstrlen(szArgs)+1];
  58. if ( m_pszArgs )
  59. lstrcpy( m_pszArgs, szArgs );
  60. }
  61. m_dwFlags = dwFlags;
  62. m_iImage = iImgIndex;
  63. return TRUE;
  64. }
  65. BOOL CDataItem::Invoke(HWND hwnd)
  66. {
  67. BOOL fResult;
  68. TCHAR szCmdLine[MAX_PATH*2];
  69. PROCESS_INFORMATION ei;
  70. STARTUPINFO si = {0};
  71. si.cb = sizeof(si);
  72. lstrcpy( szCmdLine, m_pszCmdLine );
  73. if ( m_pszArgs )
  74. {
  75. strcat( szCmdLine, TEXT(" ") );
  76. strcat( szCmdLine, m_pszArgs );
  77. }
  78. fResult = CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &ei);
  79. if (fResult)
  80. {
  81. if (NULL != ei.hProcess)
  82. {
  83. DWORD dwObject;
  84. // passing in a NULL HWND is used as a signal not to wait in this inner loop.
  85. while (hwnd)
  86. {
  87. dwObject = MsgWaitForMultipleObjects(1, &ei.hProcess, FALSE, INFINITE, QS_ALLINPUT);
  88. if (WAIT_OBJECT_0 == dwObject)
  89. {
  90. break;
  91. }
  92. else if (WAIT_OBJECT_0+1 == dwObject)
  93. {
  94. MSG msg;
  95. while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
  96. {
  97. if ( WM_QUIT == msg.message )
  98. {
  99. CloseHandle(ei.hProcess);
  100. return fResult;
  101. }
  102. else
  103. {
  104. GetMessage(&msg, NULL, 0, 0);
  105. // IsDialogMessage cannot understand the concept of ownerdraw default pushbuttons. It treats
  106. // these attributes as mutually exclusive. As a result, we handle this ourselves. We want
  107. // whatever control has focus to act as the default pushbutton.
  108. if ( (WM_KEYDOWN == msg.message) && (VK_RETURN == msg.wParam) )
  109. {
  110. HWND hwndFocus = GetFocus();
  111. if ( hwndFocus )
  112. {
  113. SendMessage(hwnd, WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndFocus), BN_CLICKED), (LPARAM)hwndFocus);
  114. }
  115. continue;
  116. }
  117. if ( IsDialogMessage(hwnd, &msg) )
  118. continue;
  119. TranslateMessage(&msg);
  120. DispatchMessage(&msg);
  121. }
  122. }
  123. }
  124. }
  125. if ( !hwnd )
  126. {
  127. // A NULL hwnd means we were called in the mode by which we execute the item and then immediately
  128. // exit. If our process exits before the other process is ready it'll end up in the wrong place
  129. // in the z-order. To prevent this, when we're in "exit when done" mode we need to wait for the
  130. // process we created to be ready. The way to do this is to call WaitForInputIdle. This is really
  131. // only needed on NT5 and above due to the new "rude window activation" stuff, but since this API
  132. // is available all the way back to NT 3.1 we simply call it blindly.
  133. WaitForInputIdle(ei.hProcess, 20*1000); // we wait a maximum of 20 seconds
  134. }
  135. CloseHandle(ei.hProcess);
  136. }
  137. }
  138. else
  139. {
  140. // do something if we fail to create a process?
  141. }
  142. return fResult;
  143. }