Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Получение PID процесса, запущенного из программы (http://forum.oszone.net/showthread.php?t=159116)

Delirium 04-12-2009 01:52 1286328

Получение PID процесса, запущенного из программы
 
Имеется приложение на C#. В приложении есть опция - создать отчет. Отчет формируется в Excel.

Код:

//экземпляр Excel
            oXL = new Excel.Application();
            //экземпляр книги
            oWB = (Excel._Workbook)(oXL.Workbooks.Add(Missing.Value));
            //экземпляр листа
            oSheet = (Excel._Worksheet)oWB.ActiveSheet;

и т.д. Т.е. все стандартно. Формирование отчета запускается в параллельном потоке, и после завершения формирования отчет выводится на экран (excel.Visible=true). Все работает, но иногда, крайне редко (например, отчет слишком большой, а пользователь закрыл программу и забыл что формировал его) в процессах остается экземпляр Excel.
Вот и подумал, может имеет смысл при закрытии программы проверять PID процессов Excel и закрывать их принудительно? В таком случае возникает проблема с уже запущенными клиентом копиями Excel.
Я думал взять список процессов Excel до запуска отчета и после
Код:

listBoxBefore.Text = System.Diagnostics.Process.GetProcessesByName("Excel")[0].Id.ToString();
listBoxAfter.Text = System.Diagnostics.Process.GetProcessesByName("Excel")[0].Id.ToString();

И при закрытии программы проверять, есть ли в списке новые PID. Но этот вариант мало подходит, т.к. пользователь мог во время работы программы сам запустить дополнительно Excel.
Может есть способ сразу при активации экземпляра Excel из программы, получать его PID? Чтобы быть уверенным на 100%, что закрывается нужное приложение.

Admiral 05-12-2009 20:01 1287589

Delirium, когда в МультиБут понадобилось определить кто запускал консоль/GUI процесс, нашёл эту тему Как узнать имя процесса-родителя, а там ссылку в посте под номер 4;)
Тем не менее, код, переписанный с Делфи на С, не добавил, так как представил, что помимо explorer.exe и cmd.exe, программу может запускать totalcmd.exe, far.exe и т.д., что делает данный подход не надёжным.


Код:

#define PSAPI_VERSION 1

#include <windows.h>
#include <stdio.h>
#include <Winternl.h>
#include <Psapi.h>

#pragma comment(lib, "Psapi.lib")

int WINAPI wWinMain (HINSTANCE hThisInst, HINSTANCE hPrevInst, LPWSTR lpszArgs, int nWinMode)
{
        HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId());
        if(hProcess == INVALID_HANDLE_VALUE)
                return -1;

        HMODULE hNtDll = LoadLibrary(L"ntdll.dll");
        if(hNtDll == NULL)
                return -1;

        typedef NTSTATUS (NTAPI *pfnNtQueryInformationProcess)(
                IN  HANDLE ProcessHandle,
                IN  PROCESSINFOCLASS ProcessInformationClass,
                OUT PVOID ProcessInformation,
                IN  ULONG ProcessInformationLength,
                OUT PULONG ReturnLength    OPTIONAL
                );

        pfnNtQueryInformationProcess gNtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(hNtDll, "NtQueryInformationProcess");
    if(gNtQueryInformationProcess == NULL)
        {
        FreeLibrary(hNtDll);
        return -1;
    }
       
        typedef struct _PROCESS_BASIC_INFORMATION {
                NTSTATUS ExitStatus;
                PPEB PebBaseAddress;
                ULONG_PTR AffinityMask;
                LONG BasePriority;
                ULONG_PTR UniqueProcessId;
                ULONG_PTR InheritedFromUniqueProcessId;
        };
        _PROCESS_BASIC_INFORMATION Info ={0};

        gNtQueryInformationProcess(hProcess, ProcessBasicInformation, &Info, sizeof(Info), NULL);// == NO_ERROR)
        CloseHandle(hProcess);
       
        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, (DWORD)Info.InheritedFromUniqueProcessId);
        wchar_t szFileName[MAX_PATH] = L"";
        GetModuleFileNameEx(hProcess, NULL, szFileName, MAX_PATH);
        CloseHandle(hProcess);

        MessageBox(NULL, szFileName, L"Hi", MB_ICONINFORMATION);
       
        if(hNtDll != NULL)
                FreeLibrary(hNtDll);

        return 0;
}

На C# наверное можно перенести, а там и в Excel.
Не писал под .NET в Excel, так что не знаю нюансов, но разве при запуске второго экземпляра Excel не создаёт новой вкладке в своём окне? Или с рапортами выделяется отдельный поток и всё?

Delirium 07-12-2009 02:17 1288296

Цитата:

Цитата Admiral
разве при запуске второго экземпляра Excel не создаёт новой вкладке в своём окне »

Это зависит от настроек самого Excel. У меня всегда открывает новое окно при формировании запроса, тестировал на Excel 2003 и 2007 с разными настройками.


Время: 09:44.

Время: 09:44.
© OSzone.net 2001-