使用带有IDE的Firefox SDK开发(Visual Studio 2013)

使用带有IDE的Firefox SDK开发(Visual Studio 2013),firefox,ide,visual-studio-2013,Firefox,Ide,Visual Studio 2013,我开始开发Firefox插件,但是我找不到任何专门用于Firefox的IDE。在大多数情况下,这并不重要,因为我可以打开Javascript文件并编辑它们(我想我使用VS2013和Web Essentials) 到目前为止,一切都是可以接受的,但当我每次都必须使用cmd来运行这个插件,然后从cmd读取控制台日志时,这就变成了一场噩梦 那么,我的问题是——是否有办法像VisualStudio2013中的任何代码一样启动、开发和记录Firefox插件?其他IDE也很受欢迎。我认为可以创建Visual

我开始开发Firefox插件,但是我找不到任何专门用于Firefox的IDE。在大多数情况下,这并不重要,因为我可以打开Javascript文件并编辑它们(我想我使用VS2013和Web Essentials)

到目前为止,一切都是可以接受的,但当我每次都必须使用cmd来运行这个插件,然后从cmd读取控制台日志时,这就变成了一场噩梦


那么,我的问题是——是否有办法像VisualStudio2013中的任何代码一样启动、开发和记录Firefox插件?其他IDE也很受欢迎。

我认为可以创建Visual Studio附加组件,但工作量太大了。不过,我成功地将Firefox附加创建部分与C++代码集成到VS2013中。它重定向cmd窗口,这意味着您将在调试时在“输出”窗口中从cmd输出

我将留下完整的代码和步骤,以防其他人需要(需要C++11):

  • 创建Win32 C++项目(不是CMD一)。
  • 将代码(如下)粘贴到cpp文件中
  • 扩展名更改为附加名
  • 运行代码一次,它会抛出一个消息框,其中包含将加载项放在SDK上的信息
  • 将SDK文件复制到该文件夹
  • 再次运行代码并退出(您可以根据需要退出,它应该终止剩余的窗口)
  • 现在有3个文件(.js、.css等)链接选项:
  • 在SDK文件夹中手动创建文件,并将其手动添加到项目中
  • 通过VS2013菜单创建文件,然后在do while循环中取消注释和修改、添加、删除行
  • 通过VS2013菜单创建文件,但选择SDK文件夹
  • 代码:

    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #pragma注释(lib,“Shlwapi.lib”)
    //定时器代码启动
    /*
    //
    //这段代码归功于詹姆斯·多特里
    //
    */
    班级计时器{
    typedef std::chrono::高分辨率时钟高分辨率时钟;
    typedef std::chrono::毫秒;
    公众:
    计时器(bool run=false)
    {
    如果(运行)重置();
    }
    无效重置()
    {
    _开始=高分辨率时钟::现在();
    }
    已用毫秒()常量
    {
    返回std::chrono::duration\u cast(高分辨率\u clock::now()-\u start);
    }
    私人:
    高分辨率时钟:时间点开始;
    };
    //计时器代码结束
    //Cmd重定向代码开始
    /*
    //
    //StackOverflow的一些人负责指导,CodeProject的Randor负责基本代码
    //
    */
    结构作业包装器
    {
    处理hJob;
    _JOBWRAPPER():hJob(NULL){}
    ~\u JOBWRAPPER(){if(this->hJob!=NULL)CloseHandle(hJob);}
    运算符句柄()常量{返回this->hJob;}
    }hJob;
    typedef void(*TextOutFunction)(LPCSTR);
    结构参数
    {
    把手;
    时钟超时;
    LPCSTR pchBreakText;
    TextOutFunction函数;
    boolbgotinfo;
    _THREADARGUMENTS():bGotInfo(false)、hOutRead(NULL)、stTimeout(NULL)、pchBreakText(nullptr)、函数(nullptr){}
    };
    void ReadCMDThread(_THREADARGUMENTS*参数)
    {
    if(参数->houtrade!=NULL)
    {
    UINT CheckForAnyResponseOnLoop=5,CurrentLoop=0;
    时钟扫描间隔=50;
    DWORD dwAvailable=0;
    DWORD字节读=0;
    CHAR szOut[4096]={0};
    如果(参数->stTimeout==0)
    {
    while(true)
    {
    CurrentLoop++;
    PeekNamedPipe(参数->hOutRead,szOut,sizeof(szOut),&bytesRead,&dwAvailable,NULL);
    如果(0!=字节读取)
    {
    if(ReadFile(Arguments->hOutRead,szOut,sizeof(szOut),&bytesRead,NULL))
    参数->bGotInfo=true;
    参数->函数(szOut);
    if(Arguments->pchBreakText!=nullptr&&Arguments->pchBreakText!=“”&&str(szOut,Arguments->pchBreakText)!=nullptr)
    打破
    memset(szOut,'\0',sizeof(char)*4096);
    }
    如果(CheckForAnyResponseOnLoop==CurrentLoop&&Arguments->pchBreakText==“”)
    打破
    std::this_thread::sleep_for((std::chrono::毫秒)扫描间隔);
    }
    }
    其他的
    {
    定时器(真);
    while(timer.appeased()<(std::chrono::millides)参数->stTimeout)
    {
    CurrentLoop++;
    PeekNamedPipe(参数->hOutRead,szOut,sizeof(szOut),&bytesRead,&dwAvailable,NULL);
    如果(0!=字节读取)
    {
    if(ReadFile(Arguments->hOutRead,szOut,sizeof(szOut),&bytesRead,NULL))
    参数->bGotInfo=true;
    参数->函数(szOut);
    timer.Reset();
    if(Arguments->pchBreakText!=nullptr&&Arguments->pchBreakText!=“”&&str(szOut,Arguments->pchBreakText)!=nullptr)
    打破
    memset(szOut,'\0',sizeof(char)*4096);
    }
    如果(CheckForAnyResponseOnLoop==CurrentLoop&&Arguments->pchBreakText==“”)
    打破
    std::this_thread::sleep_for((std::chrono::毫秒)扫描间隔);
    }
    }
    }
    }
    类CMDREDIRECTION{
    私人:
    处理hInRead、hInWrite、houtrade、hOutWrite;
    处理信息;
    STARTUPINFO si;
    安全(a);
    TextOutFunction自定义函数;
    公众:
    CMDREDIRECTION(TextOutFunction函数):hInRead(NULL)、hInWrite(NULL)、Houtrade(NULL),
    hOutWrite(NULL),CustomFunction(Function){}
    ~CMDREDIRECTION(){
    if(hInRead!=NULL)
    闭合手柄(hInRead);
    if(hInWrite!=NULL)
    闭合手柄(hInWrite);
    if(houtrade!=NULL)
    闭柄(houtrade);
    if(hOutWrite!=NULL)
    握把
    
    #include <windows.h> 
    #include <tchar.h>
    #include <thread>
    #include <chrono>
    #include <typeinfo>
    #include <Shlwapi.h>
    #pragma comment(lib,"Shlwapi.lib")
    
    // Timer code start
    
    /*
    //
    //Credit goes to James Daughtry for this piece of code
    //
    */
    
    class Timer {
        typedef std::chrono::high_resolution_clock high_resolution_clock;
        typedef std::chrono::milliseconds milliseconds;
    public:
        Timer(bool run = false)
        {
            if (run) Reset();
        }
        void Reset()
        {
            _start = high_resolution_clock::now();
        }
        milliseconds Elapsed() const
        {
            return std::chrono::duration_cast<milliseconds>(high_resolution_clock::now() - _start);
        }
    private:
        high_resolution_clock::time_point _start;
    };
    
    // Timer code end
    
    // Cmd redirection code start
    
    /*
    //
    //Credit goes to some guys from StackOverflow for directions and Randor from CodeProject for base code
    //
    */
    
    struct _JOBWRAPPER
    {
        HANDLE hJob;
        _JOBWRAPPER() : hJob(NULL) {}
        ~_JOBWRAPPER() { if (this->hJob != NULL) CloseHandle(hJob); }
        operator HANDLE() const { return this->hJob; }
    }hJob;
    
    typedef void(*TextOutFunction)(LPCSTR);
    
    struct _THREADARGUMENTS
    {
        HANDLE hOutRead;
        clock_t stTimeout;
        LPCSTR pchBreakText;
        TextOutFunction Function;
        bool bGotInfo;
        _THREADARGUMENTS() : bGotInfo(false), hOutRead(NULL), stTimeout(NULL), pchBreakText(nullptr), Function(nullptr) {}
    };
    
    void ReadCMDThread(_THREADARGUMENTS* Arguments)
    {
        if (Arguments->hOutRead != NULL)
        {
            UINT CheckForAnyResponseOnLoop = 5, CurrentLoop = 0;
            clock_t ScanInterval = 50;
            DWORD dwAvailable = 0;
            DWORD bytesRead = 0;
            CHAR szOut[4096] = { 0 };
    
            if (Arguments->stTimeout == 0)
            {
                while (true)
                {
                    CurrentLoop++;
    
                    PeekNamedPipe(Arguments->hOutRead, szOut, sizeof(szOut), &bytesRead, &dwAvailable, NULL);
                    if (0 != bytesRead)
                    {
                        if (ReadFile(Arguments->hOutRead, szOut, sizeof(szOut), &bytesRead, NULL))
                            Arguments->bGotInfo = true;
                        Arguments->Function(szOut);
    
                        if (Arguments->pchBreakText != nullptr && Arguments->pchBreakText != "" && strstr(szOut, Arguments->pchBreakText) != nullptr)
                            break;
    
                        memset(szOut, '\0', sizeof(char) * 4096);
                    }
                    if (CheckForAnyResponseOnLoop == CurrentLoop && Arguments->pchBreakText == "")
                        break;
    
                    std::this_thread::sleep_for((std::chrono::milliseconds)ScanInterval);
                }
            }
            else
            {
                Timer timer(true);
                while (timer.Elapsed() < (std::chrono::milliseconds)Arguments->stTimeout)
                {
                    CurrentLoop++;
    
                    PeekNamedPipe(Arguments->hOutRead, szOut, sizeof(szOut), &bytesRead, &dwAvailable, NULL);
                    if (0 != bytesRead)
                    {
                        if (ReadFile(Arguments->hOutRead, szOut, sizeof(szOut), &bytesRead, NULL))
                            Arguments->bGotInfo = true;
                        Arguments->Function(szOut);
                        timer.Reset();
    
                        if (Arguments->pchBreakText != nullptr && Arguments->pchBreakText != "" && strstr(szOut, Arguments->pchBreakText) != nullptr)
                            break;
    
                        memset(szOut, '\0', sizeof(char) * 4096);
                    }
                    if (CheckForAnyResponseOnLoop == CurrentLoop && Arguments->pchBreakText == "")
                        break;
    
                    std::this_thread::sleep_for((std::chrono::milliseconds)ScanInterval);
                }
            }
        }
    }
    
    class CMDREDIRECTION{
    
    private:
        HANDLE hInRead, hInWrite, hOutRead, hOutWrite;
        PROCESS_INFORMATION pi;
        STARTUPINFO si;
        SECURITY_ATTRIBUTES sa;
        TextOutFunction CustomFunction;
    public:
        CMDREDIRECTION(TextOutFunction Function) : hInRead(NULL), hInWrite(NULL), hOutRead(NULL),
            hOutWrite(NULL), CustomFunction(Function) {}
        ~CMDREDIRECTION(){
            if (hInRead != NULL)
                CloseHandle(hInRead);
            if (hInWrite != NULL)
                CloseHandle(hInWrite);
            if (hOutRead != NULL)
                CloseHandle(hOutRead);
            if (hOutWrite != NULL)
                CloseHandle(hOutWrite);
        }
    
        DWORD WriteToCmd(LPSTR pchString, bool PressEnter = false)
        {
            DWORD dwWritten = 0;
            size_t GivenStringLength = strlen(pchString);
            LPSTR TemporaryString = pchString;
            bool bSuccess = false;
    
            if (GivenStringLength != 0)
            {
                if (PressEnter)
                {
                    size_t StringSize = GivenStringLength + 2;
                    TemporaryString = new CHAR[StringSize];
                    for (size_t i = 0; i < GivenStringLength; i++)
                        TemporaryString[i] = pchString[i];
                    TemporaryString[StringSize - 2] = '\n';
                    TemporaryString[StringSize - 1] = '\0';
                    bSuccess = (WriteFile(hInWrite, TemporaryString, strlen(TemporaryString), &dwWritten, NULL) && dwWritten);
                    delete[] TemporaryString;
                }
                else
                    bSuccess = (WriteFile(hInWrite, TemporaryString, strlen(TemporaryString), &dwWritten, NULL) && dwWritten);
            }
    
            return bSuccess;
        }
    
        bool GetAnswer(clock_t stTimeout, LPCSTR pchBreakText)
        {
            _THREADARGUMENTS Arguments;
            Arguments.hOutRead = hOutRead;
            Arguments.pchBreakText = pchBreakText;
            Arguments.stTimeout = stTimeout;
            Arguments.Function = CustomFunction;
    
            std::thread CMDWatcher(ReadCMDThread, &Arguments);
    
            CMDWatcher.join();
    
            return Arguments.bGotInfo;
        }
    
        bool WriteToCmdAndWaitForAnswer(LPSTR pchString, clock_t stTimeout, LPCSTR pchBreakText, bool PressEnter = false)
        {
            if (WriteToCmd(pchString, PressEnter))
            {
                return (GetAnswer(stTimeout, pchBreakText));
            }
            else
            {
                return false;
            }
        }
    
        bool Start()
        {
            if (hJob.hJob == NULL)
            {
                hJob.hJob = CreateJobObject(NULL, NULL);
                if (hJob.hJob != NULL)
                {
                    JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
    
                    jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
                    if (!SetInformationJobObject((HANDLE)hJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
                    {
                        return false;
                    }
                }
                else
                {
                    return false;
                }
            }
    
            ZeroMemory(&sa, sizeof(sa));
            sa.nLength = sizeof(SECURITY_ATTRIBUTES);
            sa.bInheritHandle = TRUE;
    
            CreatePipe(&hInRead, &hInWrite, &sa, 0);
            CreatePipe(&hOutRead, &hOutWrite, &sa, 0);
    
            ZeroMemory(&si, sizeof(si));
            GetStartupInfo(&si);
    
            si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
            si.hStdOutput = hOutWrite;
            si.hStdError = hOutWrite;
            si.hStdInput = hInRead;
            si.wShowWindow = SW_HIDE;
    
            TCHAR Path[MAX_PATH] = { 0 };
    
            GetSystemDirectory(Path, MAX_PATH);
            _tcscat_s(Path, TEXT("\\cmd.exe"));
    
            if (CreateProcess(Path, NULL, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
            {
                BOOL bResult = AssignProcessToJobObject(hJob, pi.hProcess);
    
                CloseHandle(pi.hProcess);
                CloseHandle(pi.hThread);
    
                return (bResult != 0);
            }
            else
            {
                return false;
            }
        }
    };
    
    // Cmd redirection code end
    
    // TString code start
    
    #ifdef UNICODE
    #define TCat TCatW
    #define TString _TString<WCHAR>
    #else
    #define TCat TCatA
    #define TString _TString<CHAR>
    #endif
    
    struct AnyString
    {
        PVOID String;
        bool bWide;
        AnyString(LPSTR String)
        {
            this->String = String;
            bWide = false;
        }
        AnyString(LPWSTR String)
        {
            this->String = String;
            bWide = true;
        }
        operator LPSTR() { return (LPSTR)String; }
        operator LPSTR() const { return (LPSTR)String; }
        operator LPWSTR() { return (LPWSTR)String; }
        operator LPWSTR() const { return (LPWSTR)String; }
    };
    
    template<class T>
    class _TString
    {
        friend void SeAnyString(LPSTR String, _TString<CHAR> &TempString);
        T *String;
        size_t size;
    
        void free()
        {
            if (String != nullptr && size != 0)
            {
                delete[] String;
                String = nullptr;
                size = 0;
            }
        }
    
        _TString<CHAR> ToCHAR(LPWSTR wch)
        {
            _TString<CHAR> TempString;
    
            LPSTR Buffer = nullptr;
            size_t size = wcslen(wch),
                realsize = size + 1;
            if (size != 0)
            {
                Buffer = new CHAR[realsize];
    
                wcstombs_s(nullptr, Buffer, realsize, wch, size);
    
                TempString.SetAllocatedString(Buffer, size);
            }
    
            return TempString;
        }
        _TString<WCHAR> ToWCHAR(LPSTR ch)
        {
            _TString<WCHAR> TempString;
    
            LPWSTR Buffer = nullptr;
            size_t size = strlen(ch),
                realsize = size + 1;
            if (size != 0)
            {
                Buffer = new WCHAR[realsize];
    
                mbstowcs_s(nullptr, Buffer, realsize, ch, size);
    
                TempString.SetAllocatedString(Buffer, size);
            }
    
            return TempString;
        }
    public:
        _TString(T *String)
        {
            free();
            if (typeid(T) == typeid(CHAR))
            {
                size = strlen(String);
                if (size != 0)
                {
                    this->String = new T[size + 1];
                    for (size_t i = 0; i < size; i++)
                        this->String[i] = String[i];
                    this->String[size] = '\0';
                }
            }
            else if (typeid(T) == typeid(WCHAR))
            {
                size = wcslen(String);
                if (size != 0)
                {
                    this->String = new T[size + 1];
                    for (size_t i = 0; i < size; i++)
                        this->String[i] = String[i];
                    this->String[size] = L'\0';
                }
            }
        }
        _TString() : String(nullptr), size(0) {}
        ~_TString() { free(); }
        _TString(_TString&& OldTempStr)
        {
            this->String = OldTempStr.String;
            this->size = OldTempStr.size;
            OldTempStr.size = 0;
            OldTempStr.String = nullptr;
        }
        _TString& operator=(_TString&& OldTempStr)
        {
            this->String = OldTempStr.String;
            this->size = OldTempStr.size;
            OldTempStr.size = 0;
            OldTempStr.String = nullptr;
            return *this;
        }
        operator T*() const { return String; }
        operator T*() { return String; }
        T& operator[] (size_t i) { return String[i]; }
    
        void SetAllocatedString(T *String, size_t size)
        {
            free();
            this->String = String;
            this->size = size;
        }
        void join(LPWSTR StringToJoin)
        {
            join(AnyString(StringToJoin));
        }
        void join(LPSTR StringToJoin)
        {
            join(AnyString(StringToJoin));
        }
        void join(AnyString StringToJoin)
        {
            if (typeid(T) == typeid(CHAR))
            {
                size_t length = 0;
                _TString<CHAR> TempString;
                LPSTR StringLiteral = nullptr;
                if (StringToJoin.bWide)
                {
                    TempString = ToCHAR(StringToJoin);
                    StringLiteral = TempString;
                }
                else
                {
                    StringLiteral = StringToJoin;
                }
    
                if (StringLiteral != nullptr)
                    length = strlen(StringLiteral);
    
                if (length != 0)
                {
                    size_t newsize = size + length, realsize = newsize + 1;
                    T *Buffer = new T[realsize];
                    for (size_t i = 0; i < size; i++)
                        Buffer[i] = String[i];
                    for (size_t i = size, j = 0; i < newsize; i++, j++)
                        Buffer[i] = StringLiteral[j];
                    Buffer[newsize] = '\0';
                    free();
                    size = newsize;
                    String = Buffer;
                }
            }
            else if (typeid(T) == typeid(WCHAR))
            {
                size_t length = 0;
                _TString<WCHAR> TempString;
                LPWSTR StringLiteral = nullptr;
                if (StringToJoin.bWide)
                {
                    StringLiteral = StringToJoin;
                }
                else
                {
                    TempString = ToWCHAR(StringToJoin);
                    StringLiteral = TempString;
                }
    
                if (StringLiteral != nullptr)
                    length = wcslen(StringLiteral);
    
                if (length != 0)
                {
                    size_t newsize = size + length, realsize = newsize + 1;
                    T *Buffer = new T[realsize];
                    for (size_t i = 0; i < size; i++)
                        Buffer[i] = String[i];
                    for (size_t i = size, j = 0; i < newsize; i++, j++)
                        Buffer[i] = StringLiteral[j];
                    Buffer[newsize] = L'\0';
                    free();
                    size = newsize;
                    String = Buffer;
                }
            }
        }
        size_t GetSize() { return size; }
        T* GetString() { return String; }
    };
    
    _TString<CHAR> TCatA(std::initializer_list<AnyString> list)
    {
        _TString<CHAR> String;
    
        for (auto iterator = list.begin(), end = list.end(); iterator != end; ++iterator)
            String.join(*iterator);
    
        return String;
    }
    
    _TString<WCHAR> TCatW(std::initializer_list<AnyString> list)
    {
        _TString<WCHAR> String;
    
        for (auto iterator = list.begin(), end = list.end(); iterator != end; ++iterator)
            String.join(*iterator);
    
        return String;
    }
    
    // TString code end
    
    // Main code start
    
    #define EXTENSION_NAME YOUR_EXTENSION_NAME //"my-extension" in ANSI
    
    void WriteToOutputWindow(LPCSTR Text) { OutputDebugStringA(Text); }
    
    void GetProjectDirectory(TString &Path)
    {
        TCHAR MaxPath[MAX_PATH] = { 0 };
        GetModuleFileName(NULL, MaxPath, MAX_PATH);
    
        for (int i = _tcslen(MaxPath), ch = 0; i > 0; i--)
        {
            if (MaxPath[i] == TEXT('\\') && ++ch == 2)
                break;
            else
                MaxPath[i] = TEXT('\0');
        }
    
        Path.join(MaxPath);
    }
    
    void GetDataDirectory(TString &Path)
    {
        GetProjectDirectory(Path);
    
        TCHAR TempBuffer[MAX_PATH] = { 0 }, FinalBuffer[MAX_PATH] = { 0 };
    
        for (size_t i = Path.GetSize() - 1, ch = 0, j = 0; i > 0; i--, j++)
        {
            if (Path[i] == TEXT('\\') && ++ch == 2)
                break;
            else
                TempBuffer[j] = Path[i];
        }
    
        for (size_t i = _tcslen(TempBuffer), j = 0; i > 0; i--, j++)
            FinalBuffer[j] = TempBuffer[i - 1];
    
        Path.join(FinalBuffer);
    }
    
    bool Restart()
    {
        int msgboxID = MessageBox(NULL, TEXT("Firefox has been closed. Save changes and press \"Yes\" to run again."), TEXT("Run again?"), MB_YESNO | MB_ICONQUESTION);
    
        switch (msgboxID)
        {
        case IDYES:
            return true;
        case IDNO:
            return false;
        }
    }
    
    int WINAPI _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrev, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow)
    {
        CMDREDIRECTION Window(WriteToOutputWindow);
        TString ExtensionDir;
        TString DataDir;
    
        if (Window.Start())
        {
            GetProjectDirectory(ExtensionDir);
            GetDataDirectory(DataDir);
            ExtensionDir.join(TEXT("Firefox SDK\\"));
    
            if (!PathIsDirectory(ExtensionDir))
                Window.WriteToCmdAndWaitForAnswer(TCatA({ "mkdir \"", ExtensionDir.GetString(), "\"" }), 0, "", true);
    
            if (PathIsDirectoryEmpty(ExtensionDir))
            {
                MessageBox(NULL, TCat({ TEXT("Firefox SDK directory is empty, please copy SDK files to this directory: "), ExtensionDir.GetString() }), TEXT("Failure!"), MB_ICONINFORMATION);
                return EXIT_FAILURE;
            }
    
            Window.WriteToCmdAndWaitForAnswer(TCatA({ "cd ", ExtensionDir.GetString() }), 0, "", true);
    
            Window.WriteToCmdAndWaitForAnswer("bin\\activate", 0, "", true);
    
            ExtensionDir.join(TCat({ TEXT(EXTENSION_NAME), TEXT("\\") }));
    
            if (!PathIsDirectory(ExtensionDir))
                Window.WriteToCmdAndWaitForAnswer(TCatA({ "mkdir ", EXTENSION_NAME }), 0, "", true);
    
            Window.WriteToCmdAndWaitForAnswer(TCatA({ "cd ", EXTENSION_NAME }), 0, "", true);
    
            if (PathIsDirectoryEmpty(ExtensionDir))
                Window.WriteToCmdAndWaitForAnswer("cfx init", 0, "", true);
    
            do
            {
                /*
                Window.WriteToCmdAndWaitForAnswer(TCatA({ "cd ", DataDir.GetString() }), 0, "", true);
                Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"main.js\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\lib\\\" /Y" }), 0, "", true);
                Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"*.js\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\data\\\" /Y /EXCLUDE:exclude.txt" }), 0, "", true);
                Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"*.html\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\data\\\" /Y" }), 0, "", true);
                Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"*.png\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\data\\\" /Y" }), 0, "", true);
                Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"*.css\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\data\\\" /Y" }), 0, "", true);
                */
                Window.WriteToCmdAndWaitForAnswer("cfx run --profiledir=\"./dir\"", 0, "Program terminated successfully.", true);
            } while (Restart());
        }
    
        return EXIT_SUCCESS;
    }
    
    // Main code end