يمكن واحد قابل للتنفيذ تكون وحدة التحكم واجهة المستخدم الرسومية التطبيق ؟

StackOverflow https://stackoverflow.com/questions/493536

سؤال

أنا تريد أن تجعل من C# البرنامج يمكن تشغيل CLI أو واجهة المستخدم الرسومية تطبيق اعتمادا على ما أعلام يتم تمريرها إلى ذلك.يمكن أن يتم ذلك ؟

لقد وجدت هذه الأسئلة ذات الصلة ، لكنها لا تغطي بالضبط حالتي:

هل كانت مفيدة؟

المحلول

Jdigital الجواب نقاط ريمون تشن بلوق, مما يفسر لماذا لا يمكن أن يكون تطبيق هذا على حد سواء برنامج وحدة غير وحدة* البرنامج:نظام التشغيل يحتاج إلى معرفة قبل تشغيل البرنامج تشغيل التي الفرعي للاستخدام.مرة واحدة وقد بدأ البرنامج تشغيل فوات الأوان أن نعود طلب طريقة أخرى.

كايد الجواب نقاط مقال حول تشغيل .صافي WinForms مع تطبيق وحدة التحكم.فإنه يستخدم تقنية استدعاء AttachConsole بعد تشغيل البرنامج تشغيل.وهذا له تأثير يتيح البرنامج الكتابة مرة أخرى إلى وحدة التحكم نافذة موجه الأوامر الذي بدأ تشغيل البرنامج.ولكن التعليقات في هذا المقال نشير إلى ما أعتبره خطأ فادح: عملية طفل لا تحكم وحدة التحكم. وحدة التحكم يستمر قبول الإدخال باسم الوالد العملية ، عملية الأصل ليست على علم أنه يجب أن ننتظر الطفل على إنهاء التشغيل قبل استخدام وحدة التحكم عن أشياء أخرى.

تشن المادة النقاط مقال Junfeng تشانغ أن يفسر اثنين من التقنيات الأخرى.

أول ما devenv الاستخدامات.وهو يعمل عن طريق وجود في الواقع اثنين من البرامج.واحد هو devenv.exe, الذي هو أهم برنامج واجهة المستخدم الرسومية الأخرى devenv.com, الذي يتعامل مع وحدة التحكم في وضع المهام ، ولكن إذا استعملت في غير وحدة تشبه الطريقة ، إلى الأمام مهامها إلى devenv.exe والمخارج.هذه التقنية تعتمد على Win32 القاعدة التي com ملفات الحصول على المختار قبل exe الملفات عند كتابة الأوامر دون امتداد الملف.

هناك أبسط الاختلاف على هذا أن Windows Script Host لا.فإنه يوفر اثنين منفصلة تماما الثنائيات ، wscript.exe و cscript.exe.وبالمثل, جافا يوفر java.exe بالنسبة برامج وحدة التحكم ، javaw.exe غير برامج وحدة التحكم.

Junfeng الثاني تقنية ما ildasm الاستخدامات.وقال انه يقتبس عملية ildasm's المؤلف مرت عند اتخاذ تشغيله في كل من وسائط.في نهاية المطاف, وهنا ما يفعل:

  1. هذا البرنامج هو علامة وحدة التحكم في وضع ثنائي, لذلك دائما ما يبدأ مع وحدة التحكم.هذا يسمح الإدخال والإخراج إعادة توجيه إلى العمل كالمعتاد.
  2. إذا كان البرنامج لا تحكم وضع معلمات سطر الأوامر ، إعادة تطلق نفسها.

أنه لا يكفي مجرد الاتصال FreeConsole لجعل الابتدائية يتوقف عن أن يكون برنامج وحدة.ذلك لأن العملية التي بدأت في البرنامج ، cmd.exe, "يعلم" أنه بدأ وحدة-وضع برنامج في انتظار البرنامج إلى إيقاف تشغيل.الدعوة FreeConsole من شأنه أن يجعل ildasm التوقف عن استخدام وحدة التحكم, ولكن ذلك لن يجعل عملية الأصل تبدأ باستخدام وحدة التحكم.

لذلك المقام الأول إعادة تشغيل نفسه (مع إضافية معلمة سطر الأوامر, أعتقد).عند استدعاء CreateProcess, هناك نوعان من أعلام مختلفة في محاولة ، DETACHED_PROCESS و CREATE_NEW_CONSOLE, إما من الذي سيضمن أن الحالة الثانية لن يكون تعلق الوالد وحدة التحكم.بعد ذلك ، في المقام الأول يمكن إنهاء والسماح موجه الأوامر استئناف معالجة الأوامر.

الآثار الجانبية من هذه التقنية هو أنه عند بدء تشغيل البرنامج من واجهة المستخدم الرسومية, سوف تكون هناك وحدة التحكم.فإنه سيتم وميض على الشاشة للحظات ثم تختفي.

جزء في Junfeng مقال حول استخدام editbin لتغيير برنامج التحكم-وضع العلم هو ذر الرماد في العيون ، على ما أعتقد.المترجم الخاص بك أو بيئة التطوير ينبغي أن توفر الإعداد أو خيار التحكم في أي نوع من الثنائية يخلق.ينبغي أن يكون هناك حاجة لتعديل أي شيء بعد ذلك.

الخلاصة من كل هذا أن يمكنك إما أن يكون اثنين من ثنائيات ، أو يمكن أن يكون هناك وميض لحظة من إطار وحدة تحكم.بمجرد أن تقرر الذي هو أهون الشرور ، عليك اختيارك من تطبيقات.

* أقول غير وحدة بدلا من واجهة المستخدم الرسومية لأن خلاف ذلك هو زائف.فقط لأن البرنامج لا وحدة لا يعني أنه يحتوي على واجهة المستخدم الرسومية.خدمة التطبيق هو مثال على ذلك.كما يمكن للبرنامج أن يكون وحدة و يقوم نظام ويندوز.

نصائح أخرى

تحقق من ريمون بلوق حول هذا الموضوع:

https://devblogs.microsoft.com/oldnewthing/20090101-00/?p=19643

أول الجملة:"لا يمكنك, ولكن يمكنك محاولة وهمية."

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

مجرد التحقق من وسيطات سطر الأوامر قبل WinForms Application. الاشياء.

وأود أن أضيف أن في .صافي هو يبعث على السخرية من السهل ببساطة جعل وحدة التحكم واجهة المستخدم الرسومية مشاريع في نفس الحل الذي تشترك جميع الجمعيات إلا الرئيسية.و في هذه الحالة يمكن أن تجعل إصدار سطر الأوامر ببساطة إطلاق واجهة المستخدم الرسومية النسخة إذا أطلقت دون المعلمات.سوف تحصل وامض وحدة التحكم.

هناك طريقة سهلة للقيام بما تريد.أنا دائما استخدامه عند كتابة التطبيقات التي ينبغي أن يكون كل CLI واجهة المستخدم الرسومية.لديك لوضع الخاص بك "OutputType" إلى "ConsoleApplication" لهذا العمل.

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
        });
      }
    }
  }

أعتقد المفضل الأسلوب هو ما روب يسمى devenv تقنية استخدام اثنين التنفيذية:قاذفة ".كوم" الأصلي ".إكس".هذه ليست صعبة الاستخدام إذا كان لديك رمز المتداول للعمل مع (انظر الرابط أدناه).

هذه التقنية يستخدم الحيل أن يكون هذا ".كوم" أن وكيل ستدين/stdout/stderr وإطلاق نفس المسمى .ملف exe.هذا يعطي سلوك يسمح هذا البرنامج التشكيل في وضع سطر الأوامر عندما دعا شكل وحدة (يحتمل أن تكون فقط عند بعض وسيطات سطر الأوامر يتم الكشف عنها) حين لا تزال قادرة على إطلاق مثل واجهة المستخدم الرسومية التطبيق مجانا من وحدة التحكم.

لقد استضافت مشروع يسمى dualsubsystem على مدونة جوجل أن التحديثات القديمة codeguru حل هذه التقنية توفر التعليمات البرمجية المصدر و العمل على سبيل المثال الثنائيات.

هنا هو ما أعتقد أن تكون بسيطة .NET C# حل المشكلة.فقط أن أكرر المشكلة عند تشغيل وحدة التحكم "نسخة" من التطبيق من سطر الأوامر مع التبديل وحدة التحكم يبقي الانتظار (لا العودة إلى موجه الأوامر و عملية يحتفظ تشغيل) حتى إذا كان لديك Environment.Exit(0) في نهاية التعليمات البرمجية الخاصة بك.لحل هذه المشكلة, فقط قبل الدعوة Environment.Exit(0), اتصل هذا:

SendKeys.SendWait("{ENTER}");

ثم تحكم يحصل النهائي مفتاح 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());
            }
        }
    }
}

آمل أن يساعد شخص ما من أيام الإنفاق على هذه المشكلة.شكرا على التلميح الذهاب إلى @dantill.

/*
** 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);
    }

تشغيل AllocConsole() في منشئ ثابت يعمل بالنسبة لي

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top