2014-07-20 27 views
0

我开始开发Firefox附加组件,但是我找不到专门针对Firefox的任何IDE。大多数情况下,它并不重要,因为我可以打开Javascript文件并编辑它们(我使用VS2013和Web Essentials(我认为))。使用IDE开发Firefox SDK(可能是Visual Studio 2013)

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

所以我的 - 是否有某种方式来启动,开发和登录Firefox插件就像Visual Studio 2013中的任何代码?其他IDE也是受欢迎的。

回答

0

嗯,我认为这将有可能创建Visual Studio插件,但它只是太多的工作。但是,我设法部分将Firefox附加组件创建整合到VS2013中,并使用C++代码。它重定向cmd窗口,这意味着,您将在调试时在“输出”窗口中从cmd输出。

我要走了完整的代码在案件别人步骤需要这个(C++ 11是必需的):

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

代码:

#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 
相关问题