Buat WinForms Application Beserta Versi Console-nya

Posted in: Pemrograman |

winforms-console

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 menggunakan
    FreeConsole();
    Application.Run(new Form1());

    FreeConsole digunakan 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 oleh Form1. Sehingga program kita terlihat kurang “elegan”. (dicuplik dari web milik Ben)

  • Cara yang ini lebih baik, yaitu dengan AttachConsole untuk “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("\n\n\n************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 panggil

    ConsoleTest.exe

    Untuk versi Console-nya maka panggil

    ConsoleTest.exe /NoGui /name testing /number 123
void Main



Speak Up!

Leave your own comment

Notify me of follow-up comments via e-mail (or subscribe here).




 

Share

Subscribe Feed

Email

Facebook

Twitter

Delicious

Digg

StumbleUpon

Google Buzz

Deviantart