I'm using this for special debugging output or other specific behavior.
Unfortunately this is not so easy in X# as there is no special executable when started from XIDE or Visual Studio.
The solution is to check whether the executable was started from XIDE or devenv (Visual Studio's executable).
This is the code (and you'll find a complete XIDE export attached to this message):
// Source (C#):
// http://stackoverflow.com/questions/2531837/how-can-i-get-the-pid-of-the-parent-process-of-my-application
// translated to X# and adapted by Wolfgang Riedmann wolfgang@riedmann.it
using System
using System.Diagnostics
using System.Management
function Start( ) as void
local oProcess as Process
local oParent as Process
local nId as int
oProcess := Process.GetCurrentProcess()
nId := oProcess:Id
oParent := ProcessUtil.GetParentProcess( nId )
if oParent != null
if oParent:ProcessName:Tolower() == "cmd"
oParent := ProcessUtil.GetParentProcess( oParent:Id )
endif
if oParent:ProcessName:ToLower() == "xide"
System.Console.WriteLine( String.Format( "Executable was launched from development environment {0}", oParent:ProcessName ) )
else
System.Console.WriteLine( String.Format( "Executable was launched by {0}", oParent:ProcessName ) )
endif
else
System.Console.WriteLine( "No parent process!" )
endif
return
static class ProcessUtil
static method GetParentProcess( nProcessId as int ) as Process
local oParent as Process
local nParentId as dword
local cQuery as string
local oSearch as ManagementObjectSearcher
local oResults as ManagementObjectCollection
local oEnumerator as ManagementObjectCollection.ManagementObjectEnumerator
local oQueryObj as ManagementBaseObject
oParent := null
try
cQuery := String.Format( "SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = {0}", nProcessId )
oSearch := ManagementObjectSearcher{ "rootCIMV2", cQuery }
oResults := oSearch:Get()
oEnumerator := oResults:GetEnumerator()
oEnumerator:MoveNext()
oQueryObj := oEnumerator:Current
nParentId := ( dword ) oQueryObj["ParentProcessId"]
if nParentId > 0
oParent := Process.GetProcessById( int( nParentId ) )
endif
catch oEx as Exception
Debug.WriteLine( String.Format( e"Error occurred: {0} n{1}", oEx:Message, oEx:StackTrace ) )
end try
return oParent
end class
sometimes in the last weeks my code to detect if my executables were started from the IDE stopped working - I suspect Microsoft has changed something in the WMI interface to fix a security issue.
So I had to change the implementation of the GetParentProcess() function.
using System.Diagnostics
using System.Management
static class Utility
static method GetParentProcess( nId as dword ) as Process
local nParentId as dword
local oHandle as IntPtr
local oProcInfo as WindowsAPI.PROCESSENTRY32
local oReturn as Process
nParentId := 0
oReturn := null
oHandle := WindowsAPI.CreateToolhelp32Snapshot( WindowsAPI.TH32CS_SNAPPROCESS, nId )
if oHandle != IntPtr.Zero
oProcInfo := WindowsAPI.PROCESSENTRY32{}
oProcInfo.dwSize := dword( System.Runtime.InteropServices.Marshal.SizeOf( typeof( WindowsAPI.PROCESSENTRY32 ) ) )
if WindowsAPI.Process32First( oHandle, oProcInfo )
while nId != oProcInfo.th32ProcessID .and. WindowsAPI.Process32Next( oHandle, oProcInfo )
end
if nId == oProcInfo.th32ProcessID
nParentId := oProcInfo.th32ParentProcessID
endif
endif
endif
if nParentId != 0
oReturn := Process.GetProcessById( nParentId )
endif
return oReturn
using System.Runtime.InteropServices
static class WindowsAPI
[DllImport("kernel32.dll",SetLastError:= true,EntryPoint:="CreateToolhelp32Snapshot")];
static method CreateToolhelp32Snapshot( dwFlags as dword, th32ProcessID as dword ) as IntPtr
[DllImport("kernel32.dll",EntryPoint:="Process32First")];
static method Process32First( hSnapshot as IntPtr, oEntry ref PROCESSENTRY32 ) as logic
[DllImport("kernel32.dll",EntryPoint:="Process32Next")];
static method Process32Next( hSnapshot as IntPtr, oEntry ref PROCESSENTRY32 ) as logic
[StructLayout(LayoutKind.Sequential)];
structure PROCESSENTRY32
dwSize as dword
cntUsage as dword
th32ProcessID as dword
th32DefaultHeapID as IntPtr
th32ModuleID as dword
cntThreads as dword
th32ParentProcessID as dword
pcPriClassBase as int
dwFlags as dword
[MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)] szExeFile as string
// requires /unsafe compiler switch to compile
// unsafe FIXED dim szExeFile[260] as byte
end structure
static property TH32CS_SNAPPROCESS as dword get winTH32CS_SNAPPROCESS
end class
static define winTH32CS_SNAPPROCESS := 2 as dword
You can find a complete (working) sample together with the old WMI based function here: