NO MFC - 使用 .log 除錯程式 (轉)
我一直就想自己開發一個使用 .log 來的類了,前幾天搞了一個出來,該類能夠用於 和 BCB 中。
以下是程式執行的效果,在我除錯一個服務程式的時候,生成一個 .log 日誌, 記錄了一些與啟動和關閉服務過程相關的資訊...
[ Path & FileName:] E:桌面Simple_Service_02#Simple_Service.log
[9844796] Record Start at Date: .08.06 & Time: 16:19:25 .
[9844796] _Simple_Service_07 WinMain start
[9844796] WinNT 可用!
[9844796] CommandLine by following.
[9844796] E:microsoft桌面Simple_Service_02#Simple_Service.exe
[9844796] CurrentDirectory by following.
[9844796] D:WINNTsystem32
[9844796] Current Module FileName by following.
[9844796] E:microsoft桌面Simple_Service_02#Simple_Service.exe
[9844796] 重新設定了當前目錄的位置
[9844796] CurrentDirectory by following.
[9844796] E:microsoft桌面Simple_Service_02
[9844796] NumArgunt = 0x1 (1)
[9844796] 命令列引數 0x0 (0)
[9844796] E:microsoft桌面Simple_Service_02#Simple_Service.exe
[9844796] We now Running in service_main.
[9844796] Success to RegisterServiceCtrlHandler
[9844796] 建立了同步
[9845000] 等待同步訊號超時
[9845000] SetServiceStatus 成功!
[9845500] Progress = 0x1 (1)
[9846000] Progress = 0x15 (21)
[9846500] Progress = 0x29 (41)
[9847000] Progress = 0x3D (61)
[9847500] Progress = 0x51 (81)
[9848000] Progress = 0x65 (101)
[9848500] Progress = 0x79 (121)
[9848500] SetServiceStatus to SERVICE_RUNNING !
[9849500] Doing Something...
[9849609] Doing Something...
[9849703] Doing Something...
[9849812] Doing Something...
[9849906] Doing Something...
[9850015] Doing Something...
[9850062] Go into service_ctrl Function.
[9850062] recive SERVICE_CONTROL_STOP
[9850109] Doing Something...
[9850218] Doing Something...
[9850265] 已經設定 Service 狀態為 SERVICE_STOP_PENDING ,並將同步物件設定為激發狀態.
[9850312] 同步物件被觸發
[9850312] service_mainCleanup!
[9850312] SetServiceStatus to SERVICE_STOPPED 成功!
[9850765] The Service is now Stoped
[9850765] StartServiceCtrlDispatcher Complete.
[9850765] Record End at Date: 2003.08.06 & Time: 16:19:31 .
· 基本流程介紹一下:
首先是在構造中,先取得命令列中的檔案的來源路徑和名稱,根據該名生成一個對應的 .log 的檔名(如果已存在就扔到回收站去)。 申請,建立檔名(如果重複了,末尾追加 .log 重試),設定可使用標記(active=true)。
然後是在使用過程中,使用 ::write() 的方法,把你要寫入的資訊寫入到緩衝區 (請小於 512 位元組,否則開闢更大的緩衝區,緩衝區滿了則寫入到 .log 檔案)。 使用完了後使用 ::last() 方法在 .log 檔案末尾(也是強制緩衝寫入)追加時間日期。
最後在解構函式中。自然就是三部曲,active=false; CloseHandle(); 和 釋放緩衝區
若要使用這個類,請在開頭包含類的檔案,在所有函式以外定義就是了。如下:
#include "Runtimelog.cpp"
RunTimeLog log;
以下是在視窗過程中使用的例子:
LRESULT CALLBACK
WinProc(HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam )
{
char String[128] = "";
wsprintf( String, "WinProc with uMst = 0x%x", uMsg );
log.write(String);
····
最後請記得要 ::last() 方法。否則,如果使用 ExitProcess(); 來退出程式的話,我定義的解構函式就不起作用了。
該類在 Bland C++ Builder 中的使用方法大致相同,經我測試透過... 並且 和 也基本可用 (中未知)。
(宣告:該檔案可以隨便修改、使用 或 轉載,但本人不對使用該類造成的任何後果負責):
不多說了,下面是類的原始檔: (全文完 - 2003年03月16日_am: 11時16分)
// ****************************************************************************
// ******* FileName: RunTimeLog.h ***************************************
// ****************************************************************************
#ifndef __RunTimeLogInclude
#define __RunTimeLogInclude
//Include Something here
// ******************* Start of include *****************************
#include <.h>
typedef class RunTimeLog
{
public:
RunTimeLog();
~RunTimeLog(); // 解構函式
void last(bool show);
void last();
int showResult(D delay);
bool group , nobuff, Lastshow; // 用於使資訊按時間分組
private:
// 關於函式指標的型別宣告
typedef WINSHELLAPI int (WINAPI SHELLFILE) ( LPSHFILEOPSTRUCT );
bool active, dolog, nosystime;
DWORD offset; // 指出記憶體使用偏移
DWORD BuffSize;
DWORD NumToWrite;
LPSTR SysTick;
HANDLE FileHandle;
char * lpBuff; // 用於申請記憶體
char logfile[512];
LPSTR dwNum2Str(DWORD val);
public:
DWORD hlstrcpy(LPSTR Str1, LPSTR Str2, DWORD Len );
DWORD hlstrcat(LPSTR Str, LPSTR Plus, DWORD StrLen, DWORD PlusLen );
LPSTR GetDate();
LPSTR GetTime();
LPSTR GetSysTick(DWORD * len );
int write(LPSTR lpStr);
int numberwrite(LPSTR lpStr, DWORD val);
int WriteLog(void);
void msg(LPSTR Str);
} RunTimeLog,*PRunTimeLog;
// End of class RunTimeLog
//at Include last
#endif //#ifndef __RunTimeLogInclude
// ********************* End of include ***************************
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// ****************************************************************************
// ******* FileName: RunTimeLog.cpp ***************************************
// ****************** Version: 1.12 ***************************************
// ****************************************************************************
// 宣告:該檔案可以隨便修改、使用 或 轉載,但本人不對使用該類造成的任何後果負責
// 作者:`海風 ************ E-: ">free77@163.net************************
// ****************************************************************************
// 可以在函式內部定義你的類,如下的使用 new 的定義方法。 *********************
// RunTimeLog * rtlog = new RunTimeLog; 然後在最後 delete rtlog; *********
// 也能使用如下方法定義: RunTimeLog log; 並最好顯式呼叫 解構函式 *********
// ****************************************************************************
// 對外提供的介面 主要是 ::write(""); 用於寫入資訊到緩衝記憶體中,
// 以及 ::last(); 用於最後結束部分,可以向 .log 檔案寫入緩衝內容
// 也可以直接呼叫 ::WriteLog(); 來向 .log 檔案寫入緩衝內容(如果有的話)。
// Ver 1.02 新增資訊按時間分組功能,使用 group 可以控制是否分組
// 已修正自動寫緩衝到錯誤... ,緩衝換成2048
#include <.h>
#include "RunTimeLog.h"
// 建構函式和解構函式
RunTimeLog::RunTimeLog() // 不帶引數建構函式
{
nobuff=false; Lastshow=false; dolog=false;
active=false; nosystime=false; group = true;
offset=NULL; NumToWrite=NULL;
SysTick=NULL; FileHandle=NULL;
lpBuff=NULL; BuffSize = 2048; // 設定 BuffSize 的大小
bool DelOld = false; // 設定是否要扔掉舊日誌
DWORD OverWrite = true; // 設定是否要覆蓋舊日誌,如果上面沒有丟的話
WORD ToRecyclebin = false; // 設定是否把舊日誌放到回收站
OverWrite = OverWrite? CREATE_ALWAYS : CREATE_NEW; // 一個宏定義
ToRecyclebin = ToRecyclebin ? FOF_ALLOWUNDO | FOF_SILENT | FOF_NOCONFIRMATION : FOF_SILENT | FOF_NOCONFIRMATION;
//·申請可用的記憶體作緩衝空間,指向 lpBuff, 大小為 BuffSize
// lpBuff = (char*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, BuffSize);
lpBuff = new char[BuffSize];
// lpBuff = Buffer;
if ( lpBuff != NULL )
{
//·取得程式檔名,變化成 .log 檔名,查詢是否重複了,是則送到回收站
GetModuleFileName( NULL,lpBuff,BuffSize);
hlstrcpy(logfile, lpBuff, NULL);
GetLongPathName( logfile, logfile, 512); // 如果你在 Win98 中呼叫該函式,可能會給出短檔名格式
UINT len = strlen(logfile);
UINT i = 0;
// 然後從後面去掉副檔名
for ( i=len; i>0; i-- )
{ if (logfile[i]=='.') { hlstrcat(logfile, ".log", i, 4); len = len + 3; break; } }
// 首先判斷檔案是否存在
L: // 如果不能一次建立檔案成功時用。
if (( GetFileAttributes( logfile ) == -1 )||(GetLastError()==ERROR_FILE_NOT_FOUND))
;// msg("檔案不存在");
else if(DelOld) // 該處設成 true 則要刪除原檔案
{ // 發現檔案已經存在了,需要扔到回收站裡面去
SHFILEOPSTRUCTA Fileop;
LPSHFILEOPSTRUCT lpFileOp = &Fileop;
memset( lpFileOp, NULL, sizeof(Fileop) );
Fileop.fFlags = ToRecyclebin;
Fileop.wFunc = FO_DELETE ;
Fileop.pFrom = logfile;
lpFileOp->hwnd = NULL;
//*
// 關於執行時連線的檔案操作方式,定義了 函式的指標
SHELLFILE * lpSHFileOperation = NULL; // 函式指標定義
HMODULE hlib = LoadLibrary( "shell32.dll" );
if (hlib)
{
lpSHFileOperation = (SHELLFILE *) GetProcAddress( hlib, "SHFileOperation" );
if ( lpSHFileOperation )
{
/*if (*/ lpSHFileOperation(lpFileOp); //msg( "SHFileOperation 執行過程中出現了問題");
}
else msg("shell32.dll 中沒有這個函式");
if (! FreeLibrary( hlib )) msg("釋放DLL失敗");
}
else msg("沒有 shell32.dll"); //*/
} // 扔垃圾完成
//·建立一個新檔案,寫入開始記錄的時間
FileHandle = CreateFile( logfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OverWrite, FILE_ATTRIBUTE_NORMAL, NULL);
if (FileHandle == INVALID_HANDLE_VALUE)
{ // 當不能建立新檔案的時候嘗試增加檔案字尾
if (hlstrcat( logfile, ".log", NULL, 4) < 125) goto Loop;
else { msg("CreateFile 執行過程中出現了問題,放棄重試。" ); /*ExitProcess(0);*/}
}
else { // 控制程式碼有效的時候才執行
SetFilePointer(FileHandle, GetFileSize(FileHandle,NULL), NULL, FILE_BEGIN); // 設定原始大小
WriteFile(FileHandle, "[Source Path & FileName:] ", strlen("[Source Path & FileName:] "), &NumToWrite, NULL);
WriteFile(FileHandle, logfile, strlen(logfile), &NumToWrite, NULL);
/*用於分行*/ WriteFile(FileHandle, "x0dx0a", strlen("x0dx0a"), &NumToWrite, NULL);
wsprintf( lpBuff, "Record Start at Date: %s & Time: %s .", GetDate(), GetTime() );
SysTick = GetSysTick(&NumToWrite); // 取得系統時間
WriteFile(FileHandle, SysTick, NumToWrite, &NumToWrite, NULL);
WriteFile(FileHandle, lpBuff, strlen(lpBuff), &NumToWrite, NULL);
/*用於分行*/ WriteFile(FileHandle, "x0dx0a", strlen("x0dx0a"), &NumToWrite, NULL);
if (!SetEndOfFile(FileHandle)) MessageBox(NULL, "設定結尾不成功", "??", MB_OK|MB_TOPMOST); // 寫完資料置尾
// CloseHandle( FileHandle ); FileHandle = INVALID_HANDLE_VALUE; // 收尾關閉控制程式碼
lpBuff[0] = NULL;
} // 完成控制程式碼有效時的執行
active = true; dolog = true;
}
else active = false;
nosystime = false;
write("");
return;
}
// ******************************************************************
void RunTimeLog::last() { last(0); }
void RunTimeLog::last(bool show)
{
group = false;
// 寫入結束記錄的時間
if (active)
{
WriteLog();
if (lpBuff != NULL)
{
if (FileHandle == INVALID_HANDLE_VALUE) { msg("最後 WriteLog 過程中出現了問題"); ExitProcess(0);}
else
{ // 控制程式碼有效的時候才執行
/*用於分行*/ WriteFile(FileHandle, "x0dx0a", strlen("x0dx0a"), &NumToWrite, NULL);
SysTick = GetSysTick(&NumToWrite); // 取得系統時間
WriteFile(FileHandle, SysTick, NumToWrite, &NumToWrite, NULL);
wsprintf( lpBuff, "Record End at Date: %s & Time: %s .", GetDate(), GetTime() );
WriteFile(FileHandle, lpBuff, strlen(lpBuff), &NumToWrite, NULL);
/*用於分行*/ WriteFile(FileHandle, "x0dx0a", strlen("x0dx0a"), &NumToWrite, NULL);
if (!SetEndOfFile(FileHandle)) msg( "設定結尾不成功"); // 寫完資料置尾
CloseHandle( FileHandle ); FileHandle = INVALID_HANDLE_VALUE; // 收尾關閉控制程式碼
lpBuff[0] = NULL;
if (show) showResult(0);
} // 完成控制程式碼有效時的執行
} // End of if (lpBuff != NULL)
active = false; // dolog = false;
} // End of if (active)
return ;
}
// ******************************************************************
RunTimeLog::~RunTimeLog() // 解構函式
{
// msg("析構中...");
last(Lastshow);
// msg("準備釋放記憶體");
// HeapFree( GetProcessHeap(), NULL, lpBuff); lpBuff = NULL;
dolog = false; Sleep(100);
delete lpBuff; lpBuff = NULL; dolog = false;
return;
} // End of ~RunTimeLog()
// End of 建構函式和解構函式
//***************************************************************
// 數字 到 字串 的輸出,返回值是一個字串的指標
// 不存在不成功的情況,亦不處理負數
// 第一個引數是你要轉換的數字,第二個引數是指定轉換的最小長度
// 第三個引數是字串,把第一個字元作為佔位符,可以為NULL,則採用預設
LPSTR RunTimeLog::dwNum2Str(DWORD val)
{
static char NumStr[18]="";
// _ultoa( val, NumStr, 10 );
wsprintf( NumStr, "%lu", val );
return NumStr;
}
/*/
LPSTR dwNum2Str(DWORD val, DWORD width, LPSTR lpstr)
{
// 以下是數字到 ascii 對照表
static char num[11]={48,49,50,51,52,53,54,55,56,57,48};
static DWORD base[11]= // 以下是構建一個基數表
{ 0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
static char array[16]; // 用來裝載字串的
// array[0]=0; //截斷字串
DWORD index, i, st;
index=0; st = 0;
if (width>10) width=10; // width 不能大於 10
// 根據第三個引數來改變佔位符的值
if (lpstr&&lstrlen(lpstr))
num[10]=lpstr[0];
else num[10]=num[0];
// 為了防止零作為被除數
if (val==0)
{
for ( i=width; i>1; i-- ) // 完成佔位
{ array[index]=num[10]; index++; }
array[index]=num[0]; array[index+1]=0; return array;
} // End of if (val==0)
// 正常操作的開始
for ( i=10; i>0; i--) // 這是有佔位要求的迴圈
{
if (!st)
{
if (val>=base[i])
{ st=1; i++; continue; }
else if (!(i>width)) // 準備填寫佔位符
{ array[index]=num[10]; index++; }
}
else
{ // { array[index]=num[val/base[i]]; val = val % base[i]; index++; msg(array); }
_asm {
mov eax, val // 這是被除數
mov edx, i // 注意,陣列下標一定要是暫存器
sal edx, 2 // 右移兩位等於 i*4
mov ebx, base[edx]
xor edx, edx // 做除法前一定要清空 edx
div ebx // 做除法: 現在 dx 裡面有餘數,ax 裡面則是商
mov val, edx // 儲存餘數
add eax, 30h // 調整為 ASCii 碼
mov ecx, index
mov byte ptr array[ecx], al // 儲存最後字元結果到陣列
add index, 1 // 相當於 index ++
} // End of _asm {
}
} //End of for (DWORD i=...
array[index]=0; // 最後截斷字串
return array;
} // */
// ******************************************************************
//***** 自定義函式 ***********************************
DWORD RunTimeLog::hlstrcpy(LPSTR Str1, LPSTR Str2, DWORD Len )
{
DWORD ii = 0;
if (Len == 0) // 如果沒有給出長度,則自動算出長度
{ while(!(Str2[Len] == 0)) Len++; }
if (! Len) return 0;
if (Str1==Str2) return Len;
if (Str1
for ( ii; ii
else{ ii = Len - 1;
for ( ii; ii>0; ii-- )
{ Str1[ii] = Str2[ii]; }
Str1[0] = Str2[0]; // 補做一個迴圈
}
Str1[Len] = 0; // 設定新字串結尾
return Len;
}
//******************************************************************
DWORD RunTimeLog::hlstrcat(LPSTR Str, LPSTR Plus, DWORD StrLen, DWORD PlusLen )
{
if (StrLen == 0) // 如果沒有給出長度,則自動算出長度
{ while(!(Str[StrLen] == 0)) StrLen++; }
if (PlusLen == 0) // 如果沒有給出長度,則自動算出長度
{ while(!(Plus[PlusLen] == 0)) PlusLen++; }
DWORD ii = 0; // 定義複製 plus 為 0
for ( ii; ii < PlusLen; ii++ ) // 複製字串
{ Str[StrLen] = Plus[ii]; StrLen++; }
Str[StrLen] = 0; // 設定新字串結尾
return StrLen;
}
//*******************************************************************
LPSTR RunTimeLog::GetDate()
{
static char Date[15]; Date[0]=NULL;
SYSTEMTIME SystemTime;
GetLocalTime( &SystemTime );
wsprintf(Date, "%d.%d.%d", SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay);
return Date;
}
//*******************************************************************
LPSTR RunTimeLog::GetTime()
{
static char Time[15]; Time[0]=NULL;
SYSTEMTIME SystemTime;
GetLocalTime( &SystemTime );
wsprintf(Time, "%d:%d:%d", SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond);
return Time;
}
//*******************************************************************
LPSTR RunTimeLog::GetSysTick(DWORD * len )
{ //『御風而行』
static char tick[20]="";
static DWORD dwPasTick=GetTickCount(), dwCurTick=GetTickCount();
dwPasTick = dwCurTick;
dwCurTick = GetTickCount();
tick[0]=NULL; // 清除原來的字串
if ((dwPasTick != dwCurTick) && group ) lstrcat( tick, "x0dx0a" ); // 如果前後時間不一致,則插入分行
lstrcat( tick, "[" ); // 預插入行首
// lstrcat( tick, dwNum2Str(dwCurTick, NULL, NULL) );
lstrcat( tick, dwNum2Str(dwCurTick) );
*len = hlstrcat( tick, "] ", NULL, 2 ); // 補上結尾
return tick;
}
// ******************************************************************
int RunTimeLog::write(LPSTR lpStr) // 過載為一個引數的函式
{ DWORD len,lenth,TickLen;
LPSTR temp = NULL;
len = strlen(lpStr);
if (len&&(!nosystime)) { temp = GetSysTick(&NumToWrite); TickLen = NumToWrite; }
else { TickLen = 0; }
lenth = len + TickLen + 2;
if ( lenth > BuffSize )
{ // msg("長度太大,無法寫入緩衝");
if (FileHandle != INVALID_HANDLE_VALUE)
{
WriteFile(FileHandle, temp, TickLen, &NumToWrite, NULL); // 寫入系統時間
WriteFile(FileHandle, lpStr, len, &NumToWrite, NULL); // 寫入字串內容
/*用於分行*/ WriteFile(FileHandle, "x0dx0a", strlen("x0dx0a"), &NumToWrite, NULL);
SetEndOfFile(FileHandle);
return 1;
}
return 0; // len 大於 BuffSize 而且檔案控制程式碼不可用
} // End of if ( len > BuffSize )
if ( (offset + lenth) > BuffSize) WriteLog();
if (active) // 如果是活躍的才提供寫入
{ while (!dolog); dolog = false;
if (TickLen) offset = hlstrcat( lpBuff, temp, offset, TickLen ); // 寫系統時間
if (len) offset = hlstrcat( lpBuff, lpStr, offset, len ); // 寫入字串
offset = hlstrcat( lpBuff, "x0dx0a", offset, NULL ); // 追加分行
dolog = true;
if (nobuff) WriteLog();
return 1;
}
return 0;
}
// ******************************************************************
int RunTimeLog::WriteLog(void)
{
if (active && offset)
{
while (!dolog);
dolog = false;
if (FileHandle == INVALID_HANDLE_VALUE) { msg("最後 寫入 LogFile 過程中出現問題" ); return 0;}
else
{ // 控制程式碼有效的時候才執行
WriteFile(FileHandle, lpBuff, offset, &NumToWrite, NULL);
offset = 0; // 寫入完以後記得要置 0
lpBuff[0]=NULL; // lpBuff[1]=NULL;
if (!SetEndOfFile(FileHandle)) msg( "設定結尾不成功"); // 寫完資料置尾
} // 完成控制程式碼有效時的執行
dolog = true;
return 1;
}
else return 0;
}
// ******************************************************************
void RunTimeLog::msg(LPSTR Str) { MessageBox( NULL, Str, "??", MB_OK|MB_TOPMOST|MB_SETFOREGROUND ); return; }
// ******************************************************************
int RunTimeLog::numberwrite(LPSTR lpStr, DWORD val)
{
char Temp[30];
wsprintf( Temp, " 0x%X (%lu)", val, val );
write(lpStr);
if (offset) offset = offset -2;
else { SetEndOfFile(FileHandle); SetFilePointer(FileHandle, GetFileSize(FileHandle,NULL)-2, NULL, FILE_BEGIN); }
nosystime = true;
write(Temp);
nosystime = false;
return 1L;
}
// ******************************************************************
int RunTimeLog::showResult(DWORD delay)
{
if (active)
{
WriteLog();
while (!dolog); dolog = false;
GetWindowsDirectory( lpBuff, BuffSize);
DWORD ExecLen = hlstrcat( lpBuff, " "", NULL, NULL );
ExecLen = hlstrcat( lpBuff, logfile, ExecLen, NULL );
ExecLen = hlstrcat( lpBuff, """, NULL, NULL );
PROCESS_INFORMATION pi;
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_MAXIMIZE; // SW_SHOW;
CreateProcess( NULL, lpBuff, NULL, NULL, false, 0, NULL, NULL, &si, &pi);
lpBuff[0] = NULL;
if(delay>100000) delay = 150;
if (delay) Sleep(delay);
dolog = true;
return 1L;
} else return 0L;
}
// *************************** End of File *****************************
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-1004597/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Python 程式碼除錯—使用 pdb 除錯Python除錯
- [譯]如何停止使用 console.log() 並開始使用瀏覽器除錯程式碼瀏覽器除錯
- IE console.log 除錯狀態除錯
- 使用 vscode 除錯前端程式碼VSCode除錯前端
- phpstorm 使用 Xdebug 除錯程式碼PHPORM除錯
- Linux中使用GDB除錯程式Linux除錯
- 使用 VSCode 除錯 Electron 主程式程式碼VSCode除錯
- js除錯命令,不止於console.log()JS除錯
- MFC下CSocket程式設計詳解(轉)程式設計
- 10.3 除錯事件轉存程式記憶體除錯事件記憶體
- 使用Intellij IDEA遠端除錯Spark程式IntelliJIdea除錯Spark
- 使用GDB除錯Android Native 層程式碼除錯Android
- Visual Studio 2015 MFC之Button顏色變化-斷點除錯(Debug)斷點除錯
- 在MacOS上使用gdb(cgdb)除錯Golang程式Mac除錯Golang
- gdbserver連線Ubuntu除錯程式(使用串列埠)ServerUbuntu除錯串列埠
- 【轉載】Linux核心除錯之使用模組引數Linux除錯
- vscode使用chrome除錯報錯VSCodeChrome除錯
- GDB 除錯程式碼除錯
- repr除錯python程式除錯Python
- vscode 除錯linux程式VSCode除錯Linux
- 使用 Eclipse 遠端除錯 Java 應用程式(mark)Eclipse除錯Java
- 反除錯&反反除錯 -- 利用sysctl檢測偵錯程式是否存在除錯
- Flutter 應用程式除錯Flutter除錯
- 用GDB除錯程式(六)除錯
- vue 程式碼除錯神器Vue除錯
- 使用spyder3除錯python程式的簡明教程除錯Python
- MFC程式設計(六)C程式程式設計
- MFC程式設計(一)C程式程式設計
- MFC程式設計(二)C程式程式設計
- MFC程式設計(三)C程式程式設計
- MFC程式設計(四)C程式程式設計
- MFC程式設計(五)C程式程式設計
- MFC 程式基本介面配置
- Java程式中除錯Python程式方法Java除錯Python
- Xcode中使用LLDB除錯XCodeLLDB除錯
- vscode 使用 PHP debug 除錯VSCodePHP除錯
- Linux核心使用gdb除錯Linux除錯
- vscode 使用nodejs 除錯jsVSCodeNodeJS除錯
- GDB除錯使用記錄除錯