c# - क्या एक निष्पादन योग्य कंसोल और जीयूआई आवेदन दोनों हो सकता है?




user-interface command-line-interface (9)

मैं एक C# प्रोग्राम बनाना चाहता हूं जिसे सीएलआई या जीयूआई एप्लीकेशन के रूप में चलाया जा सकता है, इस पर निर्भर करता है कि इसमें क्या झंडे हैं। क्या यह किया जा सकता है?

मुझे इन संबंधित प्रश्न मिल गए हैं, लेकिन वे मेरी स्थिति को बिल्कुल सही नहीं करते हैं:


Answers

एक स्थिर कन्स्ट्रक्टर में AllocConsole () चलाएं मेरे लिए काम करता है


/*
** dual.c    Runs as both CONSOLE and GUI app in Windows.
**
** This solution is based on the "Momentary Flicker" solution that Robert Kennedy
** discusses in the highest-rated answer (as of Jan 2013), i.e. the one drawback
** is that the console window will briefly flash up when run as a GUI.  If you
** want to avoid this, you can create a shortcut to the executable and tell the
** short cut to run minimized.  That will minimize the console window (which then
** immediately quits), but not the GUI window.  If you want the GUI window to
** also run minimized, you have to also put -minimized on the command line.
**
** Tested under MinGW:  gcc -o dual.exe dual.c -lgdi32
**
*/
#include <windows.h>
#include <stdio.h>

static int my_win_main(HINSTANCE hInstance,int argc,char *argv[],int iCmdShow);
static LRESULT CALLBACK WndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam);
static int win_started_from_console(void);
static BOOL CALLBACK find_win_by_procid(HWND hwnd,LPARAM lp);

int main(int argc,char *argv[])

    {
    HINSTANCE hinst;
    int i,gui,relaunch,minimized,started_from_console;

    /*
    ** If not run from command-line, or if run with "-gui" option, then GUI mode
    ** Otherwise, CONSOLE app.
    */
    started_from_console = win_started_from_console();
    gui = !started_from_console;
    relaunch=0;
    minimized=0;
    /*
    ** Check command options for forced GUI and/or re-launch
    */
    for (i=1;i<argc;i++)
        {
        if (!strcmp(argv[i],"-minimized"))
            minimized=1;
        if (!strcmp(argv[i],"-gui"))
            gui=1;
        if (!strcmp(argv[i],"-gui-"))
            gui=0;
        if (!strcmp(argv[i],"-relaunch"))
            relaunch=1;
        }
    if (!gui && !relaunch)
        {
        /* RUN AS CONSOLE APP */
        printf("Console app only.\n");
        printf("Usage:  dual [-gui[-]] [-minimized].\n\n");
        if (!started_from_console)
            {
            char buf[16];
            printf("Press <Enter> to exit.\n");
            fgets(buf,15,stdin);
            }
        return(0);
        }

    /* GUI mode */
    /*
    ** If started from CONSOLE, but want to run in GUI mode, need to re-launch
    ** application to completely separate it from the console that started it.
    **
    ** Technically, we don't have to re-launch if we are not started from
    ** a console to begin with, but by re-launching we can avoid the flicker of
    ** the console window when we start if we start from a shortcut which tells
    ** us to run minimized.
    **
    ** If the user puts "-minimized" on the command-line, then there's
    ** no point to re-launching when double-clicked.
    */
    if (!relaunch && (started_from_console || !minimized))
        {
        char exename[256];
        char buf[512];
        STARTUPINFO si;
        PROCESS_INFORMATION pi;

        GetStartupInfo(&si);
        GetModuleFileNameA(NULL,exename,255);
        sprintf(buf,"\"%s\" -relaunch",exename);
        for (i=1;i<argc;i++)
            {
            if (strlen(argv[i])+3+strlen(buf) > 511)
                break;
            sprintf(&buf[strlen(buf)]," \"%s\"",argv[i]);
            }
        memset(&pi,0,sizeof(PROCESS_INFORMATION));
        memset(&si,0,sizeof(STARTUPINFO));
        si.cb = sizeof(STARTUPINFO);
        si.dwX = 0; /* Ignored unless si.dwFlags |= STARTF_USEPOSITION */
        si.dwY = 0;
        si.dwXSize = 0; /* Ignored unless si.dwFlags |= STARTF_USESIZE */
        si.dwYSize = 0;
        si.dwFlags = STARTF_USESHOWWINDOW;
        si.wShowWindow = SW_SHOWNORMAL;
        /*
        ** Note that launching ourselves from a console will NOT create new console.
        */
        CreateProcess(exename,buf,0,0,1,DETACHED_PROCESS,0,NULL,&si,&pi);
        return(10); /* Re-launched return code */
        }
    /*
    ** GUI code starts here
    */
    hinst=GetModuleHandle(NULL);
    /* Free the console that we started with */
    FreeConsole();
    /* GUI call with functionality of WinMain */
    return(my_win_main(hinst,argc,argv,minimized ? SW_MINIMIZE : SW_SHOWNORMAL));
    }


static int my_win_main(HINSTANCE hInstance,int argc,char *argv[],int iCmdShow)

    {
    HWND        hwnd;
    MSG         msg;
    WNDCLASSEX  wndclass;
    static char *wintitle="GUI Window";

    wndclass.cbSize        = sizeof (wndclass) ;
    wndclass.style         = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc   = WndProc;
    wndclass.cbClsExtra    = 0 ;
    wndclass.cbWndExtra    = 0 ;
    wndclass.hInstance     = hInstance;
    wndclass.hIcon         = NULL;
    wndclass.hCursor       = NULL;
    wndclass.hbrBackground = NULL;
    wndclass.lpszMenuName  = NULL;
    wndclass.lpszClassName = wintitle;
    wndclass.hIconSm       = NULL;
    RegisterClassEx (&wndclass) ;

    hwnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,wintitle,0,
                          WS_VISIBLE|WS_OVERLAPPEDWINDOW,
                          100,100,400,200,NULL,NULL,hInstance,NULL);
    SetWindowText(hwnd,wintitle);
    ShowWindow(hwnd,iCmdShow);
    while (GetMessage(&msg,NULL,0,0))
        {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
        }
    return(msg.wParam);
    }


static LRESULT CALLBACK WndProc (HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)

    {
    if (iMsg==WM_DESTROY)
        {
        PostQuitMessage(0);
        return(0);
        }
    return(DefWindowProc(hwnd,iMsg,wParam,lParam));
    }


static int fwbp_pid;
static int fwbp_count;
static int win_started_from_console(void)

    {
    fwbp_pid=GetCurrentProcessId();
    if (fwbp_pid==0)
        return(0);
    fwbp_count=0;
    EnumWindows((WNDENUMPROC)find_win_by_procid,0L);
    return(fwbp_count==0);
    }


static BOOL CALLBACK find_win_by_procid(HWND hwnd,LPARAM lp)

    {
    int pid;

    GetWindowThreadProcessId(hwnd,(LPDWORD)&pid);
    if (pid==fwbp_pid)
        fwbp_count++;
    return(TRUE);
    }

आप जो चाहते हैं उसे करने का एक आसान तरीका है। जब मैं एक सीएलआई और एक जीयूआई होना चाहिए, तो मैं हमेशा इसका उपयोग कर रहा हूं। काम करने के लिए आपको अपने "आउटपुट टाइप" को "कंसोल एप्लिकेशन" पर सेट करना होगा।

class Program {
  [DllImport("kernel32.dll", EntryPoint = "GetConsoleWindow")]
  private static extern IntPtr _GetConsoleWindow();

  /// <summary>
  /// The main entry point for the application.
  /// </summary>
  [STAThread]
  static void Main(string[] args) {
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    /*
     * This works as following:
     * First we look for command line parameters and if there are any of them present, we run the CLI version.
     * If there are no parameters, we try to find out if we are run inside a console and if so, we spawn a new copy of ourselves without a console.
     * If there is no console at all, we show the GUI.
     * We make an exception if we find out, that we're running inside visual studio to allow for easier debugging the GUI part.
     * This way we're both a CLI and a GUI.
     */
    if (args != null && args.Length > 0) {

      // execute CLI - at least this is what I call, passing the given args.
      // Change this call to match your program.
      CLI.ParseCommandLineArguments(args);

    } else {
      var consoleHandle = _GetConsoleWindow();

      // run GUI
      if (consoleHandle == IntPtr.Zero || AppDomain.CurrentDomain.FriendlyName.Contains(".vshost"))

        // we either have no console window or we're started from within visual studio
        // This is the form I usually run. Change it to match your code.
        Application.Run(new MainForm());
      else {

        // we found a console attached to us, so restart ourselves without one
        Process.Start(new ProcessStartInfo(Assembly.GetEntryAssembly().Location) {
          CreateNoWindow = true,
          UseShellExecute = false
        });
      }
    }
  }

http://www.csharp411.com/console-output-from-winforms-application/

WinForms Application. से पहले कमांड लाइन तर्कों की जांच करें Application. सामान।

मुझे इसे .NET में जोड़ना चाहिए, यह एक ही समाधान में कंसोल और जीयूआई परियोजनाओं को सरल बनाना आसान है जो मुख्य को छोड़कर उनके सभी असेंबली साझा करते हैं। और इस मामले में, आप कमांड लाइन संस्करण को जीयूआई संस्करण लॉन्च कर सकते हैं यदि इसे बिना पैरामीटर के लॉन्च किया गया हो। आपको एक चमकदार कंसोल मिलेगा।



मुझे लगता है कि पसंदीदा तकनीक वह है जिसे रॉब ने दो एक्जिक्यूटिव का उपयोग करने की डेवेन तकनीक कहा: एक लॉन्चर ".com" और मूल ".exe"। यदि आपके पास बॉयलरप्लेट कोड के साथ काम करने के लिए है (नीचे लिंक देखें) तो यह उपयोग करना मुश्किल नहीं है।

यह तकनीक ट्रिक्स का उपयोग करती है ताकि ".com" stdin / stdout / stderr के लिए प्रॉक्सी हो और समान नाम वाली .exe फ़ाइल लॉन्च करे। यह प्रोग्राम को कमांड लाइन मोड में प्रीफ़ॉर्म करने की अनुमति देता है जब फॉर्म कंसोल कहा जाता है (संभावित रूप से केवल कुछ कमांड लाइन तर्कों का पता लगाया जाता है) जबकि अभी भी एक कंसोल से जीयूआई एप्लिकेशन के रूप में लॉन्च करने में सक्षम होता है।

मैंने Google Code पर ड्यूलसब्ससिस्टम नामक एक प्रोजेक्ट की मेजबानी की जो इस तकनीक के पुराने कोडगुरु समाधान को अपडेट करता है और स्रोत कोड और कामकाजी उदाहरण बाइनरी प्रदान करता है।


यहां समस्या है जो मुझे समस्या के लिए सरल .NET C # समाधान माना जाता है। बस समस्या को पुन: स्थापित करने के लिए, जब आप स्विच के साथ कमांड लाइन से ऐप का कंसोल "संस्करण" चलाते हैं, तो कंसोल प्रतीक्षा करता रहता है (यह कमांड प्रॉम्प्ट पर वापस नहीं आता है और प्रक्रिया चलती रहती है) भले ही आपके पास Environment.Exit(0) । अपने कोड के अंत में Environment.Exit(0) । इसे ठीक करने के लिए, Environment.Exit(0) कॉल करने से पहले। एक्सिट Environment.Exit(0) , इसे कॉल करें:

SendKeys.SendWait("{ENTER}");

फिर कंसोल को अंतिम एंटर कुंजी मिलती है जिसे इसे कमांड प्रॉम्प्ट पर लौटने की आवश्यकता होती है और प्रक्रिया समाप्त होती है। नोट: SendKeys.Send() कॉल न करें, या ऐप क्रैश हो जाएगा।

AttachConsole() को कई पोस्टों में उल्लिखित करना अभी भी जरूरी है, लेकिन ऐप के WinForm संस्करण को लॉन्च करते समय मुझे कोई कमांड विंडो फ्लिकर नहीं मिलता है।

मैंने बनाया नमूना ऐप में पूरा कोड यहां दिया है (WinForms कोड के बिना):

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace ConsoleWriter
{
    static class Program
    {
        [DllImport("kernel32.dll")]
        private static extern bool AttachConsole(int dwProcessId);
        private const int ATTACH_PARENT_PROCESS = -1;

        [STAThread]
        static void Main(string[] args)
        {
            if(args.Length > 0 && args[0].ToUpperInvariant() == "/NOGUI")
            {
                AttachConsole(ATTACH_PARENT_PROCESS);
                Console.WriteLine(Environment.NewLine + "This line prints on console.");

                Console.WriteLine("Exiting...");
                SendKeys.SendWait("{ENTER}");
                Environment.Exit(0);
            }
            else
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
        }
    }
}

उम्मीद है कि यह किसी को भी इस समस्या पर दिन बिताने में मदद करता है। संकेत के लिए धन्यवाद @ डेंटिल पर जाएं।


जेडिजिटल का जवाब रेमंड चेन के ब्लॉग को इंगित करता है, जो बताता है कि आपके पास एक ऐसा एप्लिकेशन क्यों नहीं हो सकता है जो कंसोल प्रोग्राम और गैर-कंसोल * प्रोग्राम दोनों हो: ओएस को प्रोग्राम शुरू होने से पहले पता होना चाहिए कि किस उपप्रणाली का उपयोग करना है। एक बार कार्यक्रम चलने शुरू हो जाने के बाद, वापस जाने और अन्य मोड का अनुरोध करने में बहुत देर हो चुकी है।

कैड का उत्तर एक कंसोल के साथ .Net WinForms एप्लिकेशन चलाने के बारे में एक लेख को इंगित करता है । कार्यक्रम शुरू होने के बाद यह AttachConsole को कॉल करने की तकनीक का उपयोग करता है। इस कार्यक्रम को प्रोग्राम शुरू करने वाले कमांड प्रॉम्प्ट की कंसोल विंडो पर वापस लिखने की अनुमति देने का प्रभाव है। लेकिन उस लेख में टिप्पणियां बताती हैं कि मैं क्या घातक दोष मानता हूं: बाल प्रक्रिया वास्तव में कंसोल को नियंत्रित नहीं करती है। कंसोल मूल प्रक्रिया की तरफ से इनपुट स्वीकार कर रहा है, और माता-पिता की प्रक्रिया इस बात से अवगत नहीं है कि इसे अन्य चीजों के लिए कंसोल का उपयोग करने से पहले बच्चे को दौड़ना समाप्त करना चाहिए।

चेन का लेख जूनफेंग झांग द्वारा एक लेख को इंगित करता है जो कुछ अन्य तकनीकों को बताता है

पहला यह है कि डेवेनव क्या उपयोग करता है। यह वास्तव में दो कार्यक्रमों के द्वारा काम करता है। एक devenv.exe है , जो मुख्य जीयूआई प्रोग्राम है, और दूसरा devenv.com है , जो कंसोल-मोड कार्यों को संभालता है, लेकिन यदि इसका उपयोग गैर-कंसोल-जैसी तरीके से किया जाता है, तो यह इसके कार्यों को devenv.exe पर आगे बढ़ाता है और बाहर निकलता है। तकनीक Win32 नियम पर निर्भर करती है कि जब आप फ़ाइल एक्सटेंशन के बिना कमांड टाइप करते हैं तो कॉम फ़ाइलों को exe फ़ाइलों से पहले चुना जाता है।

इस पर एक सरल भिन्नता है कि विंडोज स्क्रिप्ट होस्ट करता है। यह दो पूरी तरह से अलग बाइनरी, wscript.exe और cscript.exe प्रदान करता है। इसी तरह, जावा कंसोल प्रोग्राम्स के लिए java.exe प्रदान करता है और गैर-कंसोल प्रोग्राम्स के लिए javaw.exe प्रदान करता है।

जुन्फेंग की दूसरी तकनीक हल्का उपयोग करता है। उन्होंने इस प्रक्रिया को उद्धृत किया कि ildasm के लेखक दोनों मोड में इसे चलाने के दौरान चले गए। आखिरकार, यह वही है जो यह करता है:

  1. कार्यक्रम को कंसोल-मोड बाइनरी के रूप में चिह्नित किया गया है, इसलिए यह हमेशा कंसोल से शुरू होता है। यह सामान्य और सामान्य रूप से काम करने के लिए इनपुट और आउटपुट रीडायरेक्शन की अनुमति देता है।
  2. यदि प्रोग्राम में कोई कंसोल-मोड कमांड-लाइन पैरामीटर नहीं है, तो यह स्वयं को फिर से लॉन्च करता है।

पहला उदाहरण कंसोल प्रोग्राम होने के लिए बस FreeConsole को कॉल करने के लिए पर्याप्त नहीं है। ऐसा इसलिए है क्योंकि प्रोग्राम शुरू करने वाली प्रक्रिया, cmd.exe , "जानता है" कि यह एक कंसोल-मोड प्रोग्राम शुरू कर दिया है और प्रोग्राम को चलना बंद करने का इंतजार कर रहा है। कॉलिंग FreeConsole कंसोल का उपयोग करके ildasm स्टॉप कर देगा, लेकिन यह कंसोल का उपयोग करके मूल प्रक्रिया शुरू नहीं करेगा।

तो पहला उदाहरण खुद को पुन: प्रारंभ करता है (एक अतिरिक्त कमांड लाइन पैरामीटर के साथ, मुझे लगता है)। जब आप CreateProcess कॉल करते हैं, तो DETACHED_PROCESS और CREATE_NEW_CONSOLE को आजमाने के लिए दो अलग-अलग झंडे हैं, जिनमें से कोई भी यह सुनिश्चित करेगा कि दूसरा उदाहरण पैरेंट कंसोल से जुड़ा नहीं होगा। उसके बाद, पहला उदाहरण कमांड प्रॉम्प्ट को प्रोसेसिंग कमांड को फिर से शुरू करने की अनुमति दे सकता है।

इस तकनीक का दुष्प्रभाव यह है कि जब आप एक जीयूआई इंटरफेस से प्रोग्राम शुरू करते हैं, तब भी एक कंसोल होगा। यह स्क्रीन पर क्षणिक रूप से फ्लैश करेगा और फिर गायब हो जाएगा।

कार्यक्रम के कंसोल-मोड ध्वज को बदलने के लिए एडिटबिन का उपयोग करने के बारे में जूनफेंग के आलेख में हिस्सा एक लाल हेरिंग है, मुझे लगता है। आपके कंपाइलर या विकास पर्यावरण को यह नियंत्रित करने के लिए एक सेटिंग या विकल्प प्रदान करना चाहिए कि यह किस प्रकार की बाइनरी बनाता है। बाद में कुछ भी संशोधित करने की आवश्यकता नहीं होनी चाहिए।

तब नीचे की रेखा यह है कि आप या तो दो द्विआधारी हो सकते हैं, या आप कंसोल विंडो का एक क्षणिक झिलमिलाहट कर सकते हैं । एक बार जब आप कम बुराई तय करते हैं, तो आपके पास कार्यान्वयन की आपकी पसंद है।

* मैं जीयूआई के बजाय गैर-कंसोल कहता हूं क्योंकि अन्यथा यह एक झूठी डिचोटोमी है। सिर्फ इसलिए कि किसी प्रोग्राम में कंसोल नहीं होता है इसका मतलब यह नहीं है कि इसमें एक जीयूआई है। एक सेवा आवेदन एक प्रमुख उदाहरण है। इसके अलावा, एक प्रोग्राम में एक कंसोल और खिड़कियां हो सकती हैं।


Simply use something like this:

 this.Invoke((MethodInvoker)delegate
            {
                progressBar1.Value = e.ProgressPercentage; // runs on UI thread
            });




c# user-interface command-line-interface