使用带有IDE的Firefox SDK开发(Visual Studio 2013)
我开始开发Firefox插件,但是我找不到任何专门用于Firefox的IDE。在大多数情况下,这并不重要,因为我可以打开Javascript文件并编辑它们(我想我使用VS2013和Web Essentials) 到目前为止,一切都是可以接受的,但当我每次都必须使用cmd来运行这个插件,然后从cmd读取控制台日志时,这就变成了一场噩梦使用带有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
那么,我的问题是——是否有办法像VisualStudio2013中的任何代码一样启动、开发和记录Firefox插件?其他IDE也很受欢迎。我认为可以创建Visual Studio附加组件,但工作量太大了。不过,我成功地将Firefox附加创建部分与C++代码集成到VS2013中。它重定向cmd窗口,这意味着您将在调试时在“输出”窗口中从cmd输出 我将留下完整的代码和步骤,以防其他人需要(需要C++11):
扩展名更改为附加名
#包括
#包括
#包括
#包括
#包括
#包括
#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