Application = StartedFromIDE IDEVersion = 1.10b GalleryName = GalleryPage = GalleryDefaultName = Target = 0 Platform = AnyCPU Language = XSharp Runtime = CLR4 Dialect = Core Folder = %ProjectPath%\Applications\StartedFromIDE\ PrgSubFolder = \Prg ResourcesSubFolder = \Resources Description = is the program started from IDE? NameSpace = Assembly = StartedFromIDE Extension = ApplicationIcon = OutputFolder = Frameworks = 1 GUID = 42CA5E7C-85B6-41E4-8904-914713D6192D IncludeInProjectBuild = 1 IncludeInProjectSearch = 1 IncludeInProjectExport = 1 IncludePath = SignAssembly = 0 KeyFile = [ExportOptions] ExportResources = 1 ExportImages = 1 [StartedFromIDE FileGroups] [StartedFromIDE Files] File = %AppPath%\Prg\Start.prg FileGUID = 8F867DB4-5D3B-4272-8EAC-85B7FD2ACF3F FileType = Code File = %AppPath%\Prg\WindowsAPI.prg FileGUID = 076BAA94-7CE7-4FBD-BAEB-9B0B642BC49B FileType = Code File = %AppPath%\Prg\Utility.prg FileGUID = 31D8807C-DE0F-4B3E-BFC8-F616A501D344 FileType = Code File = %AppPath%\Prg\Readme.txt FileGUID = D8834CE4-E750-4D0A-BF62-ED1ABC6E234E FileType = Text [StartedFromIDE References] ReferenceGAC = CLR4,System,1,0,4.0.0.0 ReferenceGAC = CLR4,System.Management,1,0,4.0.0.0 [StartedFromIDE Resources] [StartedFromIDE Native Resources] [StartedFromIDE License files] [StartedFromIDE General Options] Switches= ZeroArrays=0 CaseSensitive=0 ImplicitNamespace=0 VO1=0 VO2=0 VO3=0 VO4=0 VO5=0 VO6=0 VO7=0 VO8=0 VO9=0 VO10=0 VO11=0 VO12=0 VO13=0 VO14=0 VO16=0 LateBound=0 Unsafe=0 IgnoreStdDefs=0 Ovf=0 FOvf=0 ResponseOnly=0 [StartedFromIDE Configurations] AppConfig = Debug,11111111-1111-1111-1111-111111111111 Switches= SwitchesCF= CommandLine= CommandLineCF= Debug=1 DebugInit=1 DefineDebug=1 DefineTrace=0 SyntaxOnly=0 WarningsErrors=0 ForceConsole=0 ForceX86=0 AppConfig = Release,22222222-2222-2222-2222-222222222222 Switches= SwitchesCF= CommandLine= CommandLineCF= Debug=0 DebugInit=0 DefineDebug=0 DefineTrace=0 SyntaxOnly=0 WarningsErrors=0 ForceConsole=0 ForceX86=0 ENDApplication = StartedFromIDE [FileContents] %#IDE#%File=TEXT,8F867DB4-5D3B-4272-8EAC-85B7FD2ACF3F function Start( ) as void if Utility.IsStartedFromIDE( true ) System.Console.WriteLine( "I'm started from IDE (WMI)" ) else System.Console.WriteLine( "I'm NOT started from IDE (WMI)" ) endif if Utility.IsStartedFromIDE( false ) System.Console.WriteLine( "I'm started from IDE (Win32 API)" ) else System.Console.WriteLine( "I'm NOT started from IDE (Win32 API)" ) endif System.Console.WriteLine( "Press a key" ) System.Console.ReadKey() return %#IDE#%File=TEXT,076BAA94-7CE7-4FBD-BAEB-9B0B642BC49B // Application : StartedFromIDE // WindowsAPI.prg , Created : 30.08.2017 04:30 // User : Wolfgang using System.Runtime.InteropServices static class WindowsAPI #region API calls [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 #endregion #region Structures [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 // unsafe FIXED dim szExeFile[260] as byte // requires /unsafe compiler switch to compile end structure #endregion #region Properties static property TH32CS_SNAPPROCESS as dword get winTH32CS_SNAPPROCESS #endregion end class static define winTH32CS_SNAPPROCESS := 2 as dword %#IDE#%File=TEXT,31D8807C-DE0F-4B3E-BFC8-F616A501D344 // Application : StartedFromIDE // Utility.prg , Created : 30.08.2017 04:32 // User : Wolfgang using System.Diagnostics using System.Management static class Utility static method GetParentProcess( nId as int ) as Process local nParentId as int local oHandle as IntPtr local oProcInfo as WindowsAPI.PROCESSENTRY32 local oReturn as Process nParentId := 0 oReturn := null try oHandle := WindowsAPI.CreateToolhelp32Snapshot( WindowsAPI.TH32CS_SNAPPROCESS, dword( nId ) ) if oHandle != IntPtr.Zero oProcInfo := WindowsAPI.PROCESSENTRY32{} oProcInfo.dwSize := dword( System.Runtime.InteropServices.Marshal.SizeOf( typeof( WindowsAPI.PROCESSENTRY32 ) ) ) // System.Console.WriteLine( String.Format( "Size is {0}", oProcInfo:dwSize:ToString() ) ) if WindowsAPI.Process32First( oHandle, oProcInfo ) // System.Console.WriteLine( String.Format( "ProcessId {0}, ProcessName {1}, ParentProcessId {2}", oProcInfo:th32ProcessID:ToString(), oProcInfo:szExeFile, oProcInfo:th32ParentProcessID:ToString() ) ) while nId != oProcInfo.th32ProcessID .and. WindowsAPI.Process32Next( oHandle, oProcInfo ) // System.Console.WriteLine( String.Format( "ProcessId {0}, ProcessName {1}, ParentProcessId {2}", oProcInfo:th32ProcessID:ToString(), oProcInfo:szExeFile, oProcInfo:th32ParentProcessID:ToString() ) ) end if nId == oProcInfo.th32ProcessID nParentId := int( oProcInfo.th32ParentProcessID ) endif endif endif if nParentId != 0 try oReturn := Process.GetProcessById( nParentId ) end try endif catch oEx as Exception System.Console.WriteLine( String.Format( e"Error occurred: {0} \n{1}", oEx:Message, oEx:StackTrace ) ) end try return oReturn static method GetParentProcessWMI( 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:ToString() ) oSearch := ManagementObjectSearcher{ "root\CIMV2", cQuery } if oSearch != null oResults := oSearch:Get() if oResults != null oEnumerator := oResults:GetEnumerator() if oEnumerator != null oEnumerator:MoveNext() oQueryObj := oEnumerator:Current nParentId := ( dword ) oQueryObj["ParentProcessId"] if nParentId > 0 oParent := Process.GetProcessById( int( nParentId ) ) endif endif endif endif catch oEx as Exception System.Console.WriteLine( String.Format( e"Error occurred: {0} \n{1}", oEx:Message, oEx:StackTrace ) ) end try return oParent static method IsStartedFromIDE( lUseWMI as logic ) as logic local lReturn as logic local oProcess as Process local oParent as Process local nId as int local cProcessName as string lReturn := false oProcess := Process.GetCurrentProcess() nId := oProcess:Id if lUseWMI oParent := Utility.GetParentProcessWMI( nId ) else oParent := Utility.GetParentProcess( nId ) endif if oParent != null cProcessName := oParent:ProcessName:Tolower() if cProcessName == "cmd" if lUseWMI oParent := Utility.GetParentProcessWMI( oParent:Id ) else oParent := Utility.GetParentProcess( oParent:Id ) endif if oParent != null cProcessName := oParent:ProcessName:Tolower() endif endif if cProcessName == "xide" .or. cProcessName == "devenv" lReturn := true endif endif return lReturn end class %#IDE#%File=TEXT,D8834CE4-E750-4D0A-BF62-ED1ABC6E234E This sample shows how to use the Windows API in X#. I use the function IsStartedFromIDE() extensively in my applications to change the behavior when running from the IDE: mostly diagnostic output, sometimes default parameters Unfortunately, sometimes in summer 2017, my function based on WMI stopped working, so I needed to find another way. Wolfgang Riedmann wolfgang@riedmann.it