使用带有IDE的Firefox SDK进行开发(可能是Visual Studio 2013)

时间:2014-07-20 19:56:51

标签: firefox ide visual-studio-2013

我开始开发一个Firefox附加组件,但是我找不到专门用于Firefox的IDE。在大多数情况下,它并不重要,因为我可以打开Javascript文件并进行编辑(我使用VS2013和Web Essentials(我认为))。

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

所以我的 - 是否有一些方法可以像Visual Studio 2013中的任何代码一样启动,开发和登录Firefox插件?其他IDE也是受欢迎的。

1 个答案:

答案 0 :(得分:0)

我认为可以创建Visual Studio附加组件,但它的工作量太大了。但是,我设法使用c ++代码将Firefox附加组件创建部分集成到VS2013中。它重定向cmd窗口,这意味着您将从cmd输出"输出"调试时的窗口。

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

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

    #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