2018-09-11 09:01:44 +00:00
using System ;
using System.Collections ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.IO ;
using System.Linq ;
using System.Reflection ;
using WindowsDisplayAPI ;
using WindowsDisplayAPI.DisplayConfig ;
using NvAPIWrapper.GPU ;
using NvAPIWrapper.Mosaic ;
2020-12-05 08:40:20 +00:00
using AudioSwitcher.AudioApi.CoreAudio ;
2020-12-20 07:42:04 +00:00
using DisplayMagicianShared ;
2018-09-11 09:01:44 +00:00
2020-12-20 07:42:04 +00:00
namespace DisplayMagicianLogReporter
2018-09-11 09:01:44 +00:00
{
internal class Program
{
2020-12-19 23:45:50 +00:00
2018-09-11 09:01:44 +00:00
private static StreamWriter _writer ;
2020-12-02 08:11:23 +00:00
internal static string AppDataPath = Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . LocalApplicationData ) , "DisplayMagician" ) ;
2020-12-27 21:14:01 +00:00
internal static string LoggingDirPath = Path . Combine ( AppDataPath , "Logs" ) ;
2018-09-11 09:01:44 +00:00
2020-12-01 09:34:25 +00:00
private static void DumpObject < T > (
2018-09-11 09:01:44 +00:00
IEnumerable < T > items ,
string title ,
Tuple < Func < T , object > , string > [ ] actions = null ,
int deepIn = 0 )
{
2020-12-01 09:34:25 +00:00
Console . Write ( $"- {title}..." ) ;
2018-09-11 09:01:44 +00:00
_writer . WriteLine ( title + new string ( '=' , Console . BufferWidth - title . Length ) ) ;
var totalTime = TimeSpan . Zero ;
var stopWatch = new Stopwatch ( ) ;
stopWatch . Start ( ) ;
foreach ( var item in items )
{
var actionResults = actions ? . Select ( tuple = >
new Tuple < string , object > ( tuple . Item2 , tuple . Item1 . Invoke ( item ) ) ) . ToArray ( ) ;
stopWatch . Stop ( ) ;
WriteObject ( item , 0 , stopWatch . Elapsed , actionResults , deepIn ) ;
totalTime + = stopWatch . Elapsed ;
stopWatch . Reset ( ) ;
stopWatch . Start ( ) ;
}
stopWatch . Stop ( ) ;
totalTime + = stopWatch . Elapsed ;
2020-12-01 09:34:25 +00:00
Console . WriteLine ( @"(Took {0} to complete)" , totalTime ) ;
2018-09-11 09:01:44 +00:00
_writer . WriteLine ( @"-- Total Elapsed: {0}" , totalTime ) ;
2020-12-01 09:34:25 +00:00
_writer . WriteLine ( ) ;
_writer . WriteLine ( new string ( '#' , Console . BufferWidth ) ) ;
2018-09-11 09:01:44 +00:00
_writer . WriteLine ( ) ;
}
2020-12-01 09:34:25 +00:00
private static void IngestFile ( string fileName , string title )
{
Console . Write ( $"- {title}..." ) ;
_writer . WriteLine ( new string ( '=' , Console . BufferWidth ) ) ;
_writer . WriteLine ( title + new string ( '=' , Console . BufferWidth - title . Length ) ) ;
_writer . WriteLine ( new string ( '=' , Console . BufferWidth ) ) ;
var totalTime = TimeSpan . Zero ;
var stopWatch = new Stopwatch ( ) ;
if ( File . Exists ( fileName ) )
{
stopWatch . Start ( ) ;
StreamReader reader = new StreamReader ( fileName ) ;
string fileContents = reader . ReadToEnd ( ) ;
_writer . WriteLine ( fileContents ) ;
stopWatch . Stop ( ) ;
totalTime + = stopWatch . Elapsed ;
Console . WriteLine ( @"(Took {0} to complete)" , totalTime ) ;
_writer . WriteLine ( @"-- Total Elapsed: {0}" , totalTime ) ;
_writer . WriteLine ( ) ;
_writer . WriteLine ( new string ( '#' , Console . BufferWidth ) ) ;
_writer . WriteLine ( ) ;
}
else
{
}
}
2018-09-11 09:01:44 +00:00
private static void Main ( string [ ] args )
{
2020-12-19 23:45:50 +00:00
// This sets the Application User Model ID to "LittleBitBig.DisplayMagician" so that
// Windows 10 recognises the application, and allows features such as Toasts,
// taskbar pinning and similar.
// This is a helper function that sets the AUMID to a static default defined
2020-12-20 07:42:04 +00:00
// within ShellUtils under the DisplayMagicianShared project.
2020-12-19 23:45:50 +00:00
ShellUtils . SetDefaultProcessExplicitAppUserModelID ( ) ;
2020-12-02 08:11:23 +00:00
Console . WriteLine ( "DisplayMagician LogReporter" ) ;
2020-12-01 09:34:25 +00:00
Console . WriteLine ( "======================" ) ;
Console . WriteLine ( ) ;
2020-12-02 08:11:23 +00:00
Console . WriteLine ( "This program will interrogate your DisplayMagician configuration settings, the Windows Display " ) ;
2020-12-01 09:34:25 +00:00
Console . WriteLine ( "Subsystem and any NVIDIA Display Drivers to record what they can detect and report. This" ) ;
Console . WriteLine ( "recorded information is then stored in a log file. If you report a problem then you may be" ) ;
Console . WriteLine ( "asked to send us the log file generated by this program in order for us to help you." ) ;
Console . WriteLine ( ) ;
Console . WriteLine ( "Starting the interrogation..." ) ;
Console . WriteLine ( ) ;
2020-12-27 21:14:01 +00:00
try
{
Directory . CreateDirectory ( LoggingDirPath ) ;
}
catch ( UnauthorizedAccessException ex )
{
Console . WriteLine ( $"ERROR - Cannot create logging directory as unauthorised: {LoggingDirPath}" ) ;
}
catch ( ArgumentException ex )
{
Console . WriteLine ( $"ERROR - Cannot create logging directory as LoggingDirPath argument caused an ArgumentException: {LoggingDirPath}" ) ;
}
catch ( PathTooLongException ex )
{
Console . WriteLine ( $"ERROR - Cannot create logging directory as the path is too long for Windows to create: {LoggingDirPath}" ) ;
}
catch ( DirectoryNotFoundException ex )
{
Console . WriteLine ( $"ERROR - Cannot create logging directory as the DisplayMagician Local Application Data directory doesn't exist: {LoggingDirPath}" ) ;
}
catch ( NotSupportedException ex )
{
Console . WriteLine ( $"ERROR - Cannot create logging directory as the Directory.CreateDirectory function isn't supported: {LoggingDirPath}" ) ;
}
2020-12-01 09:34:25 +00:00
string date = DateTime . Now . ToString ( "yyyyMMdd.HHmmss" ) ;
2020-12-27 21:14:01 +00:00
string logFile = Path . Combine ( LoggingDirPath , $"LogReporter.{date}.log" ) ;
try
{
_writer = new StreamWriter ( new FileStream (
logFile ,
2018-09-11 09:01:44 +00:00
FileMode . CreateNew ) ) ;
2020-12-27 21:14:01 +00:00
}
catch ( System . Security . SecurityException ex )
{
Console . WriteLine ( $"ERROR - Cannot create log file due to a security exception: {logFile}" ) ;
}
catch ( UnauthorizedAccessException ex )
{
Console . WriteLine ( $"ERROR - Cannot create log file as unauthorised: {logFile}" ) ;
}
catch ( ArgumentException ex )
{
Console . WriteLine ( $"ERROR - Cannot create log file as LogFile argument caused an ArgumentException while creating Filestream or StreamWriter: {logFile}" ) ;
}
catch ( PathTooLongException ex )
{
Console . WriteLine ( $"ERROR - Cannot create log file as the path is too long for Windows to create: {logFile}" ) ;
}
catch ( DirectoryNotFoundException ex )
{
Console . WriteLine ( $"ERROR - Cannot create log file as the DisplayMagician\\Logs Local Application Data directory doesn't exist: {logFile}" ) ;
}
2018-09-11 09:01:44 +00:00
try
{
2020-12-02 08:11:23 +00:00
IngestFile ( Path . Combine ( AppDataPath , "Settings_1.0.json" ) , "Storing DisplayMagician Settings JSON File" ) ;
2018-09-11 09:01:44 +00:00
}
catch ( Exception e )
{
WriteException ( e ) ;
}
try
{
2020-12-02 08:11:23 +00:00
IngestFile ( Path . Combine ( AppDataPath , "Profiles" , "DisplayProfiles_1.0.json" ) , "Storing DisplayMagician Display Profiles JSON File" ) ;
2020-12-01 09:34:25 +00:00
}
catch ( Exception e )
{
WriteException ( e ) ;
}
try
{
2020-12-02 08:11:23 +00:00
IngestFile ( Path . Combine ( AppDataPath , "Shortcuts" , "Shortcuts_1.0.json" ) , "Storing DisplayMagician Shortcuts JSON File" ) ;
2020-12-01 09:34:25 +00:00
}
catch ( Exception e )
{
WriteException ( e ) ;
}
try
{
DumpObject ( DisplayAdapter . GetDisplayAdapters ( ) , "Storing a list of Display Adapters currently in this computer" ) ;
}
catch ( Exception e )
{
WriteException ( e ) ;
}
try
{
DumpObject ( Display . GetDisplays ( ) , "Storing a list of possible settings for Displays currently connected to this computer" , new [ ]
2018-09-11 09:01:44 +00:00
{
new Tuple < Func < Display , object > , string > ( display = > display . GetPossibleSettings ( ) ,
"GetPossibleSettings()" )
} ) ;
}
catch ( Exception e )
{
WriteException ( e ) ;
}
try
{
2020-12-01 09:34:25 +00:00
DumpObject ( UnAttachedDisplay . GetUnAttachedDisplays ( ) ,
"Storing a list of Displays not currently in use, but currently connected to this computer" ) ;
2018-09-11 09:01:44 +00:00
}
catch ( Exception e )
{
WriteException ( e ) ;
}
try
{
2020-12-01 09:34:25 +00:00
DumpObject ( PathDisplayAdapter . GetAdapters ( ) ,
"Storing a list of Displays Targets for all Display Adapters currently in this computer" ,
2018-09-11 09:01:44 +00:00
new [ ]
{
new Tuple < Func < PathDisplayAdapter , object > , string > ( adapter = > adapter . ToDisplayAdapter ( ) ,
"ToDisplayAdapter()" )
} ) ;
}
catch ( Exception e )
{
WriteException ( e ) ;
}
try
{
2020-12-01 09:34:25 +00:00
DumpObject ( PathDisplaySource . GetDisplaySources ( ) ,
"Storing a list of Display Sources for Displays currently connected to this computer" , new [ ]
2018-09-11 09:01:44 +00:00
{
new Tuple < Func < PathDisplaySource , object > , string > ( source = > source . ToDisplayDevices ( ) ,
"ToDisplayDevices()" )
} ) ;
}
catch ( Exception e )
{
WriteException ( e ) ;
}
try
{
2020-12-01 09:34:25 +00:00
DumpObject ( PathDisplayTarget . GetDisplayTargets ( ) ,
"Storing a list of Displays Targets for Displays currently connected to this computer" , new [ ]
2018-09-11 09:01:44 +00:00
{
new Tuple < Func < PathDisplayTarget , object > , string > ( target = > target . ToDisplayDevice ( ) ,
"ToDisplayDevice()" )
} ) ;
}
catch ( Exception e )
{
WriteException ( e ) ;
}
try
{
if ( PathInfo . IsSupported )
{
2020-12-01 09:34:25 +00:00
DumpObject ( PathInfo . GetActivePaths ( ) , "Storing a list of Active Displays currently connected to this computer" , null ,
2018-10-20 00:27:25 +00:00
2 ) ;
2018-09-11 09:01:44 +00:00
}
}
catch ( Exception e )
{
WriteException ( e ) ;
}
try
{
2020-12-01 09:34:25 +00:00
DumpObject ( LogicalGPU . GetLogicalGPUs ( ) , "Storing a list of logical NVIDIA GPUs formed by NVIDIA GPUs currently in this computer (e.g. SLI)" , null , 1 ) ;
2018-09-11 09:01:44 +00:00
}
catch ( Exception e )
{
WriteException ( e ) ;
}
try
{
2020-12-01 09:34:25 +00:00
DumpObject ( PhysicalGPU . GetPhysicalGPUs ( ) , "Storing a list of physical NVIDIA GPUs currently in this computer" ) ;
2018-09-11 09:01:44 +00:00
}
catch ( Exception e )
{
WriteException ( e ) ;
}
try
{
2020-12-01 09:34:25 +00:00
DumpObject ( NvAPIWrapper . Display . Display . GetDisplays ( ) , "Storing a list of Displays currently connected to this computer through a NVIDIA GPU" , new [ ]
2018-09-11 09:01:44 +00:00
{
2018-10-20 00:27:25 +00:00
new Tuple < Func < NvAPIWrapper . Display . Display , object > , string > (
display = > display . GetSupportedViews ( ) ,
2018-09-11 09:01:44 +00:00
"GetSupportedViews()" )
} ) ;
}
catch ( Exception e )
{
WriteException ( e ) ;
}
try
{
2020-12-01 09:34:25 +00:00
DumpObject ( NvAPIWrapper . Display . UnAttachedDisplay . GetUnAttachedDisplays ( ) ,
"Storing a list of Displays currently connected to this computer through a NVIDIA GPU but not active" ) ;
2018-09-11 09:01:44 +00:00
}
catch ( Exception e )
{
WriteException ( e ) ;
}
try
{
2020-12-01 09:34:25 +00:00
DumpObject ( NvAPIWrapper . Display . PathInfo . GetDisplaysConfig ( ) ,
"Storing a list of configuration of Displays currently connected to this computer through a NVIDIA GPU" ,
2018-09-11 09:01:44 +00:00
null , 3 ) ;
}
catch ( Exception e )
{
WriteException ( e ) ;
}
try
{
2020-12-05 08:40:20 +00:00
DumpObject ( GridTopology . GetGridTopologies ( ) , "Storing a list of configured NVIDIA Surround/Mosaic settings involving multiple Displays via a NVIDIA GPU" , null , 3 ) ;
}
catch ( Exception e )
{
WriteException ( e ) ;
}
try
{
CoreAudioController audioController = new CoreAudioController ( ) ;
DumpObject ( audioController . GetPlaybackDevices ( ) , "Storing a list of detected Audio Devices" , null , 3 ) ;
2018-09-11 09:01:44 +00:00
}
catch ( Exception e )
{
WriteException ( e ) ;
}
_writer . Flush ( ) ;
_writer . Close ( ) ;
_writer . Dispose ( ) ;
2020-12-01 09:34:25 +00:00
Console . WriteLine ( new string ( '=' , Console . BufferWidth ) ) ;
Console . WriteLine ( ) ;
2020-12-27 21:14:01 +00:00
Console . WriteLine ( @"Finished! Press enter to exit LogReporter." ) ;
2018-09-11 09:01:44 +00:00
Console . ReadLine ( ) ;
}
private static void WriteException ( Exception ex )
{
2020-12-01 09:34:25 +00:00
Console . WriteLine ( "{0} - Error: {1}" , ex . GetType ( ) . Name , ex . Message ) ;
2018-09-11 09:01:44 +00:00
_writer . WriteLine ( "{0} - Error: {1}" , ex . GetType ( ) . Name , ex . Message ) ;
}
private static void WriteObject (
object obj ,
int padding = 0 ,
TimeSpan elapsed = default ( TimeSpan ) ,
Tuple < string , object > [ ] extraProperties = null ,
int deepIn = 0 )
{
try
{
if ( padding = = 0 )
{
if ( ! elapsed . Equals ( TimeSpan . Zero ) )
{
var elapsedFormated = string . Format ( "_{0}_" , elapsed ) ;
_writer . WriteLine ( elapsedFormated +
new string ( '_' , Console . BufferWidth - elapsedFormated . Length ) ) ;
}
else
{
_writer . WriteLine ( new string ( '_' , Console . BufferWidth ) ) ;
}
2018-10-20 00:27:25 +00:00
2018-09-11 09:01:44 +00:00
_writer . WriteLine ( "({0}) {{" , obj . GetType ( ) . Name ) ;
}
if ( obj . GetType ( ) . IsValueType | | obj is string )
{
_writer . WriteLine ( new string ( ' ' , padding * 3 + 2 ) + obj ) ;
}
else if ( obj is IEnumerable )
{
var i = 0 ;
foreach ( var arrayItem in ( IEnumerable ) obj )
{
2018-10-20 00:27:25 +00:00
_writer . WriteLine ( new string ( ' ' , padding * 3 + 2 ) + "[{0}]: ({1}) {{" , i ,
arrayItem ? . GetType ( ) . Name ) ;
2018-09-11 09:01:44 +00:00
WriteObject ( arrayItem , padding + 1 , default ( TimeSpan ) , null , deepIn - 1 ) ;
_writer . WriteLine ( new string ( ' ' , padding * 3 + 2 ) + "}," ) ;
i + + ;
}
}
else
{
foreach ( var propertyInfo in obj . GetType ( ) . GetProperties ( ) . OrderBy ( info = > info . Name ) )
{
if ( propertyInfo . CanRead )
{
object value ;
try
{
value = propertyInfo . GetValue ( obj ) ;
}
catch ( TargetInvocationException ex )
{
value = ex . InnerException ? . GetType ( ) . ToString ( ) ;
}
catch ( Exception ex )
{
value = ex . GetType ( ) . ToString ( ) ;
}
if ( deepIn > 0 & &
value ! = null & &
! value . GetType ( ) . IsValueType & &
value . GetType ( ) ! = typeof ( string ) )
{
2018-10-20 00:27:25 +00:00
_writer . WriteLine ( new string ( ' ' , padding * 3 + 2 ) + "{0}: ({1}) {{" , propertyInfo . Name ,
propertyInfo . PropertyType . Name ) ;
2018-09-11 09:01:44 +00:00
WriteObject ( value , padding + 1 , default ( TimeSpan ) , null , deepIn - 1 ) ;
_writer . WriteLine ( new string ( ' ' , padding * 3 + 2 ) + "}," ) ;
}
else
{
_writer . WriteLine (
$"{new string(' ', padding * 3 + 2)}{propertyInfo.Name}: {value ?? " [ NULL ] "}," ) ;
}
}
}
}
if ( extraProperties ! = null )
{
foreach ( var extraProperty in extraProperties )
{
2018-10-20 00:27:25 +00:00
_writer . WriteLine ( new string ( ' ' , padding * 3 + 2 ) + "{0}: ({1}) {{" , extraProperty . Item1 ,
extraProperty . Item2 ? . GetType ( ) . Name ) ;
2018-09-11 09:01:44 +00:00
WriteObject ( extraProperty . Item2 , padding + 1 , default ( TimeSpan ) , null , deepIn ) ;
_writer . WriteLine ( new string ( ' ' , padding * 3 + 2 ) + "}," ) ;
}
}
if ( padding = = 0 )
{
_writer . WriteLine ( "};" ) ;
_writer . WriteLine ( new string ( '_' , Console . BufferWidth ) ) ;
}
}
catch ( Exception ex )
{
WriteException ( ex ) ;
}
}
}
}