Beberapa waktu lalu saya ingin membuat aplikasi desktop namun yang juga dapat berjalan di console. Jadi, ketika memanggil file executable aplikasi tersebut tanpa argumen maka akan menjalankan versi GUI dari aplikasi tersebut, namun bila memanggil file executable aplikasi tersebut dengan argumen maka akan menjalankan versi Console dari aplikasi tersebut (atau versi GUI namun dengan form yang berbeda dengan form utama, tergantung dari argumen dan parameter yang diberikan).
Setelah Googling, melalui .NET C# hal ini dapat dilakukan dengan beberapa trik, antara lain:
- Awalnya membuat WinForms Application, namun nanti diset menjadi Console Application, dan di
void Mainprogram lakukan seleksi kondisi bila argumen diberikan maka menjalankan versi Console, bila tidak diberikan maka menjalankan versi GUI menggunakanFreeConsole(); Application.Run(new Form1());
FreeConsoledigunakan untuk mem-free-kan console yang dibuat otomatis karena kita pilih Console Application. Namun, sayangnya melalui cara ini, maka ketika kita menjalankan program maka akan terlihat di layar window Console dibuat dan hilang dan digantikan olehForm1. Sehingga program kita terlihat kurang “elegan”. (dicuplik dari web milik Ben) - Cara yang ini lebih baik, yaitu dengan
AttachConsoleuntuk “menempelkan” Console pada program yang sejak awal dibuat sebagai WinForms Application. Walau mengkoding lebih banyak namun setidaknya ini jauh lebih elegan dibanding cara pertama yang menampilkan sekilas window console sebelum versi GUI ditampilkan. (dicuplik dari web milik Timm)using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Windows.Forms; using Microsoft.Win32.SafeHandles; using System.Diagnostics; namespace ConsoleTest { static class Program { [DllImport("kernel32.dll")] static extern bool AttachConsole(UInt32 dwProcessId); [DllImport("kernel32.dll")] private static extern bool GetFileInformationByHandle(SafeFileHandle hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation); [DllImport("kernel32.dll")] private static extern SafeFileHandle GetStdHandle(UInt32 nStdHandle); [DllImport("kernel32.dll")] private static extern bool SetStdHandle(UInt32 nStdHandle, SafeFileHandle hHandle); [DllImport("kernel32.dll")] private static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, SafeFileHandle hSourceHandle, IntPtr hTargetProcessHandle, out SafeFileHandle lpTargetHandle, UInt32 dwDesiredAccess, Boolean bInheritHandle, UInt32 dwOptions); private const UInt32 ATTACH_PARENT_PROCESS = 0xFFFFFFFF; private const UInt32 STD_OUTPUT_HANDLE = 0xFFFFFFF5; private const UInt32 STD_ERROR_HANDLE = 0xFFFFFFF4; private const UInt32 DUPLICATE_SAME_ACCESS = 2; struct BY_HANDLE_FILE_INFORMATION { public UInt32 FileAttributes; public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime; public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime; public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime; public UInt32 VolumeSerialNumber; public UInt32 FileSizeHigh; public UInt32 FileSizeLow; public UInt32 NumberOfLinks; public UInt32 FileIndexHigh; public UInt32 FileIndexLow; } static void InitConsoleHandles() { SafeFileHandle hStdOut, hStdErr, hStdOutDup, hStdErrDup; BY_HANDLE_FILE_INFORMATION bhfi; hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); hStdErr = GetStdHandle(STD_ERROR_HANDLE); // Get current process handle IntPtr hProcess = Process.GetCurrentProcess().Handle; // Duplicate Stdout handle to save initial value DuplicateHandle(hProcess, hStdOut, hProcess, out hStdOutDup, 0, true, DUPLICATE_SAME_ACCESS); // Duplicate Stderr handle to save initial value DuplicateHandle(hProcess, hStdErr, hProcess, out hStdErrDup, 0, true, DUPLICATE_SAME_ACCESS); // Attach to console window – this may modify the standard handles AttachConsole(ATTACH_PARENT_PROCESS); // Adjust the standard handles if (GetFileInformationByHandle(GetStdHandle(STD_OUTPUT_HANDLE), out bhfi)) { SetStdHandle(STD_OUTPUT_HANDLE, hStdOutDup); } else { SetStdHandle(STD_OUTPUT_HANDLE, hStdOut); } if (GetFileInformationByHandle(GetStdHandle(STD_ERROR_HANDLE), out bhfi)) { SetStdHandle(STD_ERROR_HANDLE, hStdErrDup); } else { SetStdHandle(STD_ERROR_HANDLE, hStdErr); } } /// /// The main entry point for the application. /// [STAThread] static void Main(string[] args) { bool NoGui = false; string name = ""; int number = 0; for (int i = 0; i != args.Length; ++i) { switch (args[i]) { case "/NoGui": NoGui = true; break; case "/name": name = args[++i]; break; case "/number": number = int.Parse(args[++i]); break; default: Console.WriteLine("Invalid args!"); return; } } if (!NoGui) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } else { // initialize console handles InitConsoleHandles(); // to demonstrate where the console output is going int argCount = args == null ? 0 : args.Length; Console.WriteLine("nnn************Console Application Starting!!!*************"); Console.WriteLine("You specified {0} arguments:", argCount); Console.Error.WriteLine("This is the error channel"); for (int i = 0; i < argCount; i++) { Console.WriteLine(" {0}", args[i]); } Console.WriteLine("*************Console Application Ended!***********"); System.Windows.Forms.SendKeys.SendWait("{ENTER}"); } } } }Misal bila file executable nya adalah
ConsoleTest.exe,
Untuk memanggil versi GUI maka langsung saja panggilConsoleTest.exe
Untuk versi Console-nya maka panggil
ConsoleTest.exe /NoGui /name testing /number 123
void Main
English
Indonesia 
