From 5cc675212e96d87ebbf00f4fd7a8106b06a490ff Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期三, 13 八月 2025 14:00:50 +0800
Subject: [PATCH] 1. 侧面检功能添加优化(主要是现场获取图像问题)

---
 EdgeInspector_App/Grabber/RadientControl.cpp |  678 ++++++++++++++++++++++++++++++++++----------------------
 1 files changed, 409 insertions(+), 269 deletions(-)

diff --git a/EdgeInspector_App/Grabber/RadientControl.cpp b/EdgeInspector_App/Grabber/RadientControl.cpp
index 37ddb61..1496118 100644
--- a/EdgeInspector_App/Grabber/RadientControl.cpp
+++ b/EdgeInspector_App/Grabber/RadientControl.cpp
@@ -2,8 +2,12 @@
 #include "RadientControl.h"
 #include "FrameBufferController.h"
 
-MIL_ID		g_MilApplication_Radient	= M_NULL;	/* Application identifier.  */
-int			g_nGrabberCount_Radient		= 0;		// grabber count
+MIL_ID g_MilApplication_Radient	= M_NULL;	/* Application identifier.  */
+int	   g_nGrabberCount_Radient	= 0;		// grabber count
+
+// 璋冭瘯
+#define GRAB_DEBUG_ENABLE	0				// 缃� 0 鍏抽棴鎵�鏈夎皟璇曡緭鍑轰笌杞瓨
+#define GRAB_DUMP_DIR		_T("D:\\Dump")  // 杈撳嚭鐩綍
 
 //==========================================================================================================================================================================
 // Grabber Radient
@@ -23,152 +27,161 @@
 
 CGrabberRadient::~CGrabberRadient()
 {
-	if(m_pFrameBuffer != NULL)
+	if (m_pFrameBuffer != NULL) {
 		delete m_pFrameBuffer;
-	m_pFrameBuffer = NULL;
+		m_pFrameBuffer = NULL;
+	}
 }
 
 BOOL CGrabberRadient::Initialize(void *pParam, int *pErrorCode,int iBoard)
 {
 	_GRABBER_INIT_PARAM_ *pParameter = (_GRABBER_INIT_PARAM_ *)pParam;
-
-	if(NULL != pParameter)
-	{
-		m_Param = *pParameter;		
-		
-	//	return TRUE;
-
-		CString			strDCF;
-		strDCF = m_Param.cDCFPath;
-
-		CString strTmp;		
-
-		if(g_nGrabberCount_Radient == 0)
-		{
-			MappAlloc(M_NULL,M_DEFAULT, &g_MilApplication_Radient);
-		}		
-
-		g_nGrabberCount_Radient++;				
-
-		MsysAlloc(M_SYSTEM_RADIENTEVCL, m_Param.nBoardIdx, M_DEFAULT, &m_MilSystem);
-		//MsysAlloc(M_DEFAULT, MIL_TEXT("M_DEFAULT"), m_Param.nBoardIdx, M_DEFAULT, &m_MilSystem);
-		if(CheckLastError())
-			return FALSE;		
-		
-		MdigAlloc(m_MilSystem  , m_Param.nBoardCh , strDCF, M_DEFAULT, &m_MilDigitizer);
-		if(CheckLastError())
-			return FALSE;
-
-		for(int j = 0; j < BUFFERING_SIZE_MAX ;j++)
-		{
-			MbufAlloc2d(m_MilSystem, m_Param.nFrameWidth, m_Param.nFrameHeight, 8+M_UNSIGNED, M_IMAGE+M_GRAB, &m_Milbufgrab[j]);
-		}		
-		if(CheckLastError())
-			return FALSE;
-
-		/*
-		INT nExposureTimer = m_Param.nExposure*1000;
-		INT nExposureTimerDelay = m_Param.nExposureDelay*1000;
-
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME+M_TIMER1,  nExposureTimer);                        //10us
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME_DELAY+M_TIMER1,  nExposureTimerDelay);                 //10us
-
-		if(m_Param.nImgFlipX == 1)
-			SetImageFlipX(TRUE);
-		else
-			SetImageFlipX(FALSE);
-		*/
-
-		//MdigControl(m_MilDigitizer,M_GRAB_MODE   , M_ASYNCHRONOUS);
-		MdigControl(m_MilDigitizer,M_GRAB_TIMEOUT, M_INFINITE);
-		if(CheckLastError())
-			return FALSE;
-		
-		m_DigitizerStatus.status = M_STOP;	
-		
-	}
-	else
+	if(NULL == pParameter) {
 		return FALSE;
+	}
+	m_Param = *pParameter;
+
+	CString	strDCF;
+	strDCF = m_Param.cDCFPath;
+
+	if (g_nGrabberCount_Radient == 0) {
+		MappAlloc(M_NULL, M_DEFAULT, &g_MilApplication_Radient);
+	}
+	g_nGrabberCount_Radient++;
+
+	// 鍒嗛厤绯荤粺
+	MsysAlloc(M_SYSTEM_RADIENTEVCL, m_Param.nBoardIdx, M_DEFAULT, &m_MilSystem);
+	if (CheckLastError()) {
+		return FALSE;
+	}
+
+	// 鍒嗛厤 digitizer锛孧_DEV0/M_DEV1 鍖哄垎 CH0/CH1
+	MIL_INT nDev = m_Param.nBoardCh;
+	MdigAlloc(m_MilSystem, nDev, strDCF, M_DEFAULT, &m_MilDigitizer);
+	if (CheckLastError()) {
+		MIL_INT nErrorCode = 0;
+		MappGetError(M_GLOBAL, &nErrorCode);
+		g_pLog->DisplayMessage(_T("Digitizer Alloc Error | BoardIdx=%d, BoardCh=%d, DCF=\"%s\", MIL_Error=%ld"), m_Param.nBoardIdx, m_Param.nBoardCh, strDCF, nErrorCode);
+		return FALSE;
+	}
+	g_pLog->DisplayMessage(_T("Digitizer Alloc | BoardIdx=%d, BoardCh=%d, DCF=\"%s\""), m_Param.nBoardIdx, m_Param.nBoardCh, strDCF);
+
+	// 鏌ヨ鐪熷疄灏哄
+	MIL_INT nSizeX = 0, nSizeY = 0, nBands = 1, nType = 0;
+	MdigInquire(m_MilDigitizer, M_SIZE_X, &nSizeX);
+	MdigInquire(m_MilDigitizer, M_SIZE_Y, &nSizeY);
+	MdigInquire(m_MilDigitizer, M_SIZE_BAND, &nBands);
+	MdigInquire(m_MilDigitizer, M_TYPE, &nType);
+
+	// 鐢ㄧ‖浠跺疄闄呭�艰鐩栭厤缃�
+	if (m_Param.nFrameWidth != (int)nSizeX || m_Param.nFrameHeight != (int)nSizeY) {
+		g_pLog->DisplayMessage(_T("Digitizer Size sync: cfg %dx%d -> hw %dx%d"), m_Param.nFrameWidth, m_Param.nFrameHeight, (int)nSizeX, (int)nSizeY);
+		m_Param.nFrameWidth = (int)nSizeX;
+		m_Param.nFrameHeight = (int)nSizeY;
+	}
+
+	// 鍒嗛厤缂撳啿
+	for (int j = 0; j < BUFFERING_SIZE_MAX; j++) {
+		MbufAlloc2d(m_MilSystem, m_Param.nFrameWidth, m_Param.nFrameHeight, (/*nType ? nType : */8 + M_UNSIGNED), M_IMAGE + M_GRAB + M_PROC, &m_Milbufgrab[j]);
+	}
+
+	if (CheckLastError()) {
+		return FALSE;
+	}
+
+	/*
+	INT nExposureTimer = m_Param.nExposure*1000;
+	INT nExposureTimerDelay = m_Param.nExposureDelay*1000;
+
+	MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME+M_TIMER1,  nExposureTimer);                        //10us
+	MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME_DELAY+M_TIMER1,  nExposureTimerDelay);             //10us
+
+	if(m_Param.nImgFlipX == 1)
+		SetImageFlipX(TRUE);
+	else
+		SetImageFlipX(FALSE);
+	*/
+
+	// 鎶撳彇鎺у埗
+	MdigControl(m_MilDigitizer, M_GRAB_MODE, M_ASYNCHRONOUS);
+	MdigControl(m_MilDigitizer, M_GRAB_TIMEOUT, M_INFINITE);
+	if (CheckLastError()) {
+		return FALSE;
+	}
+
+	m_DigitizerStatus.status = M_STOP;
 
 	return TRUE;
 }
 
 BOOL CGrabberRadient::SetImageFlipX(BOOL bOn)
 {
-	if(bOn == TRUE)
+	if (bOn == TRUE) {
 		MdigControl(m_MilDigitizer, M_GRAB_DIRECTION_X, M_REVERSE);
-	else
+	}
+	else {
 		MdigControl(m_MilDigitizer, M_GRAB_DIRECTION_X, M_FORWARD);
+	}
 
 	return TRUE;
 }
 
 BOOL CGrabberRadient::CheckLastError()
 {
-	BOOL bReturn = FALSE;
-
 	MIL_INT nErrorCode; 
-	CString strMsg;
-
-	if(MappGetError(M_GLOBAL, &nErrorCode))
-	{
+	if(MappGetError(M_GLOBAL, &nErrorCode)) {
 		int	iCam = m_Param.nCameraIdx;	
 		int	iScan = m_Param.nCameraScan;
 		int	iBoard = m_Param.nBoardIdx;
 		int	iBoardCh = m_Param.nBoardCh;
 		
-		strMsg.Format(_T("[Board:%d,ch %d] [Camera:%d,Scan %d] MIL Error Code : %d"), iBoard,iBoardCh,iCam,iScan, nErrorCode);
+		CString strMsg;
+		strMsg.Format(_T("[Board=%d,ch=%d] [Camera=%d,Scan=%d] MIL Error Code : %d"), iBoard,iBoardCh,iCam,iScan, nErrorCode);
 		g_pLog->DisplayMessage(strMsg);	
 		
-		bReturn = TRUE;
+		return TRUE;
 	}	
-	else
-		bReturn = FALSE;
 
-	return bReturn;
+	return FALSE;
 }
 
 BOOL CGrabberRadient::InitializeBuffer(void *pParam)
 {
 	_GRABBER_INIT_PARAM_ *pParameter = (_GRABBER_INIT_PARAM_ *)pParam;
-
-	BOOL		bRet = TRUE;
-	if(NULL != pParameter)
-	{
-		m_Param = *pParameter;
-
-		bRet = CreateGrabBuffer(m_Param.nScanCount,m_Param.nGrabBufCount,m_Param.nFrameWidth,m_Param.nFrameHeight);
+	if (NULL == pParameter) {
+		g_pLog->DisplayMessage(_T("InitializeBuffer : pParameter is NULL"));
+		return FALSE;
 	}
 
-	return bRet;
+	m_Param = *pParameter;
+	return CreateGrabBuffer(m_Param.nScanCount, m_Param.nGrabBufCount, m_Param.nFrameWidth, m_Param.nFrameHeight);
 }
 
 BOOL CGrabberRadient::Deinitialize(void)
 {	
-	if (IsGrabbing())
+	if (IsGrabbing()) {
 		GrabScanStop();
+	}
 
 	g_nGrabberCount_Radient--;
 
-	for(int i = 0; i < BUFFERING_SIZE_MAX ;i++)
-	{
+	for(int i = 0; i < BUFFERING_SIZE_MAX ;i++) {
 		MbufFree(m_Milbufgrab[i]);
 	}		
 
-	MdigFree(m_MilDigitizer);	
-	
+	MdigFree(m_MilDigitizer);		
 	MsysFree(m_MilSystem);
 
-	if(g_nGrabberCount_Radient == 0)
+	if (g_nGrabberCount_Radient == 0) {
 		MappFree(g_MilApplication_Radient);
+	}
 
 	return TRUE;
 }
 
 BOOL CGrabberRadient::GrabLiveStart(int nExposure)
 {
-	if (IsGrabbing())
-	{
+	if (IsGrabbing()) {
 		g_pLog->DisplayMessage(_T("Start Live Acq : IsGrabbing -> Stop Acq %d"), m_nEndFrameIdx);
 		GrabScanStop();
 		Sleep(100);				
@@ -179,11 +192,10 @@
 	m_nSetBufferIdx = -1;
 	m_nScanIndex = 0;	
 
-	if(m_DigitizerStatus.status == M_STOP)
-	{				
-		m_DigitizerStatus.status			= M_FREE_START;
-		m_DigitizerStatus.nCount			= 0;
-		m_DigitizerStatus.nIndex			= m_Param.nCameraScan;					
+	if(m_DigitizerStatus.status == M_STOP) {				
+		m_DigitizerStatus.status = M_FREE_START;
+		m_DigitizerStatus.nCount = 0;
+		m_DigitizerStatus.nIndex = m_Param.nCameraScan;					
 
 		MdigProcess(m_MilDigitizer,&m_Milbufgrab[0],BUFFERING_SIZE_MAX, M_START, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackFreeRunFunction, this);				
 	}
@@ -197,9 +209,11 @@
 
 BOOL CGrabberRadient::GrabScanStart(int iScan, BOOL bFreeRun, int nPeriod, int nExposure, BOOL bAuto)
 {	
-	if (IsGrabbing())
-	{
-		g_pLog->DisplayMessage(_T("Start Acq : IsGrabbing -> Stop Acq %d"), m_nEndFrameIdx);
+	int nCameraIdx = m_Param.nCameraIdx;
+	g_pLog->DisplayMessage(_T("%d Start Acq : Camera=%d, Scan=%d, GrabFrameCount=%d, FrameHeight=%d"), m_Param.nBoardIdx, nCameraIdx, iScan, g_pStatus->GetGrabFrameCount(nCameraIdx, iScan), m_Param.nFrameHeight);
+
+	if (IsGrabbing()) {
+		g_pLog->DisplayMessage(_T("%d Start Acq : Camera=%d, Scan=%d, IsGrabbing -> Stop Acq %d"), m_Param.nBoardIdx, nCameraIdx, iScan, m_nEndFrameIdx);
 		GrabScanStop();
 		Sleep(100);
 	}
@@ -209,84 +223,73 @@
 	m_nSetBufferIdx = -1;
 	m_nScanIndex = iScan;
 
-	if(bAuto == TRUE)
-	{
+	if (bAuto == TRUE) {
 		int nDigitizer = 0;
 
-		if(bFreeRun == FALSE)
-		{
+		if (bFreeRun == FALSE) {
 			SetTriggerMode(TRUE);
 
 			/* Start the processing. The processing function is called for every frame grabbed. */
-			if(m_DigitizerStatus.status == M_STOP)
-			{				
-				m_DigitizerStatus.status			= M_START;
-				m_DigitizerStatus.nCount			= 0;
-				m_DigitizerStatus.nIndex			= iScan;				
-				
-				MdigProcess(m_MilDigitizer,&m_Milbufgrab[0],BUFFERING_SIZE_MAX, M_START, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackHookFunction, this);				
+			if (m_DigitizerStatus.status == M_STOP) {
+				m_DigitizerStatus.status = M_START;
+				m_DigitizerStatus.nCount = 0;
+				m_DigitizerStatus.nIndex = iScan;
+
+				MdigProcess(m_MilDigitizer, &m_Milbufgrab[0], BUFFERING_SIZE_MAX, M_START, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackHookFunction, this);
 			}
 		}
-		else
-		{
-			if(m_DigitizerStatus.status == M_STOP)
-			{				
-				m_DigitizerStatus.status			= M_FREE_START;
-				m_DigitizerStatus.nCount			= 0;
-				m_DigitizerStatus.nIndex			= iScan;				
+		else {
+			if (m_DigitizerStatus.status == M_STOP) {
+				m_DigitizerStatus.status = M_FREE_START;
+				m_DigitizerStatus.nCount = 0;
+				m_DigitizerStatus.nIndex = iScan;
 
-				MdigProcess(m_MilDigitizer,&m_Milbufgrab[0],BUFFERING_SIZE_MAX, M_START, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackFreeRunFunction, this);				
+				MdigProcess(m_MilDigitizer, &m_Milbufgrab[0], BUFFERING_SIZE_MAX, M_START, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackFreeRunFunction, this);
 			}
 		}
 
 		m_isGrabbing = TRUE;
 		m_isLiveGrab = FALSE;
 	}
-	else
-	{
+	else {
 		SimulationGrab(iScan);
-	}	
-
-	g_pLog->DisplayMessage(_T("Start Acq : %d"), iScan);
+	}
 
 	return TRUE;
 }
 
 void CGrabberRadient::SimulationGrab(int iScan)
 {
-	if(m_pFrameBuffer == NULL)
+	if (m_pFrameBuffer == NULL) {
 		return;
-		
-	int			nFrameCnt = m_pFrameBuffer->GetFrameCount();
+	}
+	
+	int	nFrameCnt = m_pFrameBuffer->GetFrameCount();
 
 	m_nEndFrameIdx = nFrameCnt;
-	m_nSetBufferIdx = nFrameCnt -1;
+	m_nSetBufferIdx = nFrameCnt - 1;
 	
-	for(int i=0;i<nFrameCnt;i++)
-	{
-		SetInsertFrame(iScan,i);
+	for (int i = 0; i < nFrameCnt; i++) {
+		SetInsertFrame(iScan, i);
 	}
 }
 
 BOOL CGrabberRadient::GrabScanStop(void)
 {
-	g_pLog->DisplayMessage(_T("%d StopAcq : Scan %d, Grab %d, End %d"), m_Param.nBoardIdx,m_nScanIndex,m_nSetBufferIdx, m_nEndFrameIdx);
-	
+	g_pLog->DisplayMessage(_T("%d StopAcq : Camera %d, Scan %d, Grab %d, End %d"), m_Param.nBoardIdx, m_Param.nCameraIdx, m_nScanIndex, m_nSetBufferIdx, m_nEndFrameIdx);
+
 	CString strMsg;
-	
-	if( m_DigitizerStatus.status == M_START)
-	{
-		MdigProcess(m_MilDigitizer,&m_Milbufgrab[0],BUFFERING_SIZE_MAX, M_STOP, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackHookFunction, this);
-		m_DigitizerStatus.nIndex	= m_nScanIndex;
-		m_DigitizerStatus.status	= M_STOP;				
-	}	
-	else if(m_DigitizerStatus.status == M_FREE_START)
-	{
-		MdigProcess(m_MilDigitizer,&m_Milbufgrab[0],BUFFERING_SIZE_MAX, M_STOP, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackFreeRunFunction, this);
-		m_DigitizerStatus.nIndex	= m_nScanIndex;
-		m_DigitizerStatus.status	= M_STOP;		
+	if (m_DigitizerStatus.status == M_START) {
+		MdigProcess(m_MilDigitizer, &m_Milbufgrab[0], BUFFERING_SIZE_MAX, M_STOP, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackHookFunction, this);
+		m_DigitizerStatus.nIndex = m_nScanIndex;
+		m_DigitizerStatus.status = M_STOP;
 	}
-	
+	else if (m_DigitizerStatus.status == M_FREE_START) {
+		MdigProcess(m_MilDigitizer, &m_Milbufgrab[0], BUFFERING_SIZE_MAX, M_STOP, M_DEFAULT, (MIL_BUF_HOOK_FUNCTION_PTR)CallbackFreeRunFunction, this);
+		m_DigitizerStatus.nIndex = m_nScanIndex;
+		m_DigitizerStatus.status = M_STOP;
+	}
+
 	m_isGrabbing = FALSE;
 	m_isLiveGrab = FALSE;
 
@@ -303,57 +306,62 @@
 	return m_nSetBufferIdx - nFrameNo;		
 }
 
-LPBYTE	CGrabberRadient::GetFrameHeaderLine(int iScan,int nLine, BOOL* bSuccess)
+LPBYTE CGrabberRadient::GetFrameHeaderLine(int iScan,int nLine, BOOL* bSuccess)
 {	
-	if(m_pFrameBuffer == NULL)
+	if (m_pFrameBuffer == NULL) {
 		return NULL;
-
+	}
 	return m_pFrameBuffer->GetFrameHeaderLine(iScan,nLine);
 }
 
 LPBYTE CGrabberRadient::GetFrameHeader(int iScan,int nFrameNo, BOOL* bRet)
 {		
-	if(m_pFrameBuffer == NULL)
+	if (m_pFrameBuffer == NULL) {
 		return NULL;
-
-	return m_pFrameBuffer->GetFrameBuferHeader(iScan,nFrameNo);
+	}
+	return m_pFrameBuffer->GetFrameBuferHeader(iScan, nFrameNo);
 }
 
-BOOL CGrabberRadient::GetSmallImage(int iScan,LPBYTE lpIn, int nXStart, int nYStart, int nXSize, int nYSize, BOOL bMustMapping) 
+BOOL CGrabberRadient::GetSmallImage(int iScan, LPBYTE lpIn, int nXStart, int nYStart, int nXSize, int nYSize, BOOL bMustMapping)
 {
 	int nBufSizeX = m_Param.nFrameWidth;
 	int nBufSizeY = m_Param.nFrameHeight;
 
-	if (nXStart < 0 || nYStart < 0)
+	if (nXStart < 0 || nYStart < 0) {
+		g_pLog->DisplayMessage(_T("GetSmallImage : Invalid Start Position X=%d, Y=%d"), nXStart, nYStart);
 		return FALSE;
-	if (nXStart + nXSize > nBufSizeX)
+	}
+
+	if (nXStart + nXSize > nBufSizeX) {
+		g_pLog->DisplayMessage(_T("GetSmallImage : Invalid X Size Start=%d, Size=%d, BufferSizeX=%d"), nXStart, nXSize, nBufSizeX);
 		return FALSE;
-	if (nYStart + nYSize > nBufSizeY* GetEndFrameIdx())
+	}
+
+	if (nYStart + nYSize > nBufSizeY * GetEndFrameIdx()) {
+		g_pLog->DisplayMessage(_T("GetSmallImage : Invalid Y Size Start=%d, Size=%d, BufferSizeY=%d"), nYStart, nYSize, nBufSizeY);
 		return FALSE;
+	}
 	
-	// 鐭疮 姗囬キ鐑� 閿呴緥瀹� 鍦� 姗囬キ鐑� 閿呴緥.
 	int nStartFrameNo = nYStart / nBufSizeY;
 	int nEndFrameNo = (nYStart + nYSize) / nBufSizeY;
-	LPBYTE	lpHeadAddr = GetFrameHeader(iScan,nStartFrameNo);
-	if (!lpHeadAddr)
-	{
+	LPBYTE lpHeadAddr = GetFrameHeader(iScan, nStartFrameNo);
+	if (!lpHeadAddr) {
+		g_pLog->DisplayMessage(_T("GetSmallImage : GetFrameHeader Failed for Scan %d, Frame %d"), iScan, nStartFrameNo);
 		return FALSE;
 	}
 	LPBYTE lpStart = lpHeadAddr + (nYStart % nBufSizeY) * nBufSizeX + nXStart;
 	
 	int nLine = 0;
-	for (int i = 0; i < nYSize; i++)
-	{
+	for (int i = 0; i < nYSize; i++) {
 		memcpy(lpIn + i * nXSize, lpStart + nLine * nBufSizeX, nXSize);
-		if (nStartFrameNo <= nEndFrameNo && (nYStart + i + 1) % nBufSizeY  == 0)
-		{
-			// 鎹炲浐鐦ょ敨 铦堕兇鍏风獚缁� 搴峰紑鎹� MemFrameNo 鐗堟媽淇� 鍚у獨涔愮话 鐗堝揩 璐稿簻.
-			lpHeadAddr = GetFrameHeader(iScan,++nStartFrameNo);
+		if (nStartFrameNo <= nEndFrameNo && (nYStart + i + 1) % nBufSizeY == 0) {
+			lpHeadAddr = GetFrameHeader(iScan, ++nStartFrameNo);
 			lpStart = lpHeadAddr + nXStart;
 			nLine = 0;
 		}
-		else
+		else {
 			nLine++;
+		}
 	}
 	
 	return TRUE;
@@ -361,107 +369,201 @@
 
 void CGrabberRadient::SetSimulFrame(int nFrame)
 {
-// 	if(nFrame == 0)
-// 	{
-// 		for(int i = 0; i < g_pBase->m_nProcessMargin; i++)
-// 			SetSimulBuffer(i, m_nScanIndex % 2 == 1);
-// 	}
-// 
-// 	m_nEndFrameIdx = CHKMIN(GetGrabFrameNo(m_nScanIndex), nFrame + g_pBase->m_nProcessMargin + 1);
-// 	SetSimulBuffer(m_nEndFrameIdx - 1, m_nScanIndex % 2 == 1);
-// 
-// 	if(GetParents() != NULL)
-// 		GetParents()->PostMessage(UM_IMAGE_GRAB, m_nEndFrameIdx - 1,NULL);
+	return;
 }
 
 BOOL CGrabberRadient::Processing(long HookType, MIL_ID HookId)
 {
-	if(m_pFrameBuffer == NULL)
+	if (m_pFrameBuffer == NULL) {
 		return FALSE;
-	
+	}
+
+	m_nEndFrameIdx++;	//Count
+	m_nSetBufferIdx++;	//index
+
+	int nCameraIdx = m_Param.nCameraIdx;
+	if (m_nEndFrameIdx > g_pStatus->GetGrabFrameCount(nCameraIdx, m_nScanIndex)) {
+		GrabScanStop();
+		g_pStatus->SetGrabEnd(nCameraIdx, m_nScanIndex);
+		g_pLog->DisplayMessage(_T("%d Over Grab Count : Stop Grab [Cam:%d][Scan:%d] - EndFrameIdx=%d  FrameCount=%d"), m_Param.nBoardIdx, nCameraIdx, m_nScanIndex, m_nEndFrameIdx, g_pStatus->GetGrabFrameCount(nCameraIdx, m_nScanIndex));
+		return TRUE;
+	}
+
+	if (m_nSetBufferIdx > m_pFrameBuffer->GetFrameCount()) {
+		GrabScanStop();
+		g_pStatus->SetGrabEnd(nCameraIdx, m_nScanIndex);
+		g_pLog->DisplayMessage(_T("%d BufferIndex Overflow : Stop Grab [Cam:%d][Scan:%d] - FrameIdx=%d  BufferCount=%d"), m_Param.nBoardIdx, nCameraIdx, m_nScanIndex, m_nEndFrameIdx, m_pFrameBuffer->GetFrameCount());
+		return TRUE;
+	}
+
 	MIL_ID ModifiedImage = 0;
-
-	m_nEndFrameIdx++;			//Count
-	m_nSetBufferIdx++;		//index
-
-	if (m_nEndFrameIdx > g_pStatus->GetGrabFrameCount(m_nScanIndex))
-	{
-		GrabScanStop();		
-		g_pStatus->SetGrabEnd(m_nScanIndex);
-		g_pLog->DisplayMessage(_T("%d Over Grab Count : Stop Grab[%d][%d] - %d"), m_Param.nBoardIdx, m_nScanIndex, m_nEndFrameIdx,g_pStatus->GetGrabFrameCount(m_nScanIndex));
+	LPBYTE pBuffer = m_pFrameBuffer->GetFrameBuferHeader(m_nScanIndex, m_nSetBufferIdx);
+	if (pBuffer == NULL) {
+		GrabScanStop();
+		g_pStatus->SetGrabEnd(nCameraIdx, m_nScanIndex);
+		g_pLog->DisplayMessage(_T("%d BufferPointer NULL : Stop Grab [Cam:%d][Scan:%d] - FrameIdx=%d  BufferCount=%d"), m_Param.nBoardIdx, nCameraIdx, m_nScanIndex, m_nEndFrameIdx, m_pFrameBuffer->GetFrameCount());
 		return TRUE;
 	}
 
-	if (m_nSetBufferIdx > m_pFrameBuffer->GetFrameCount())
-	{
-		GrabScanStop();		
-		g_pStatus->SetGrabEnd(m_nScanIndex);
-		g_pLog->DisplayMessage(_T("%d Over Grab Buffer Stop Grab[%d][%d] - %d"), m_Param.nBoardIdx, m_nScanIndex, m_nEndFrameIdx,m_pFrameBuffer->GetFrameCount());
-		return TRUE;
+	MdigGetHookInfo(HookId, M_MODIFIED_BUFFER + M_BUFFER_ID, &ModifiedImage);
+	MbufControl(ModifiedImage, M_LOCK, M_DEFAULT);
+	MbufGet2d(ModifiedImage, 0, 0, m_Param.nFrameWidth, m_Param.nFrameHeight, pBuffer);
+	MbufControl(ModifiedImage, M_UNLOCK, M_DEFAULT);
+
+	SetInsertFrame(m_nScanIndex, m_nSetBufferIdx);
+
+#if GRAB_DEBUG_ENABLE
+	// 璋冭瘯鐢ㄧ殑璇︾粏鏃ュ織
+	g_pLog->DisplayMessage(
+		_T("[Grab-Processing] FrameAcquired | Board=%d Cam=%d Scan=%d FrameIdx=%d BufIdx=%d Size=%dx%d BufCount=%d"),
+		m_Param.nBoardIdx,
+		m_Param.nCameraIdx,
+		m_nScanIndex,
+		m_nEndFrameIdx,
+		m_nSetBufferIdx,
+		m_Param.nFrameWidth,
+		m_Param.nFrameHeight,
+		m_pFrameBuffer->GetFrameCount()
+	);
+#endif // GRAB_DEBUG_ENABLE
+
+	return TRUE;
+}
+
+BOOL CGrabberRadient::DumpCurrentBuffer(LPBYTE pBuffer, LPCTSTR pszDir)
+{
+	if (!pszDir || !*pszDir) {
+		g_pLog->DisplayMessage(_T("Dump invalid dir"));
+		return FALSE;
 	}
 
-	LPBYTE		pBuffer = m_pFrameBuffer->GetFrameBuferHeader(m_nScanIndex,m_nSetBufferIdx);
-	if(pBuffer == NULL)
-	{
-		GrabScanStop();		
-		g_pStatus->SetGrabEnd(m_nScanIndex);
-		g_pLog->DisplayMessage(_T("%d Over Grab Buffer Stop Grab[%d][%d] - %d"), m_Param.nBoardIdx, m_nScanIndex, m_nEndFrameIdx,m_pFrameBuffer->GetFrameCount());
-		return TRUE;
+	const MIL_INT W = m_Param.nFrameWidth;
+	const MIL_INT H = m_Param.nFrameHeight;
+
+	MIL_INT bits = 8;
+	if (m_MilDigitizer) { 
+		MdigInquire(m_MilDigitizer, M_SIZE_BIT, &bits);
+	}
+	const MIL_INT milType = (bits > 8) ? (16 + M_UNSIGNED) : (8 + M_UNSIGNED);
+
+	if (CreateDirectory(pszDir, nullptr) == 0) {
+		DWORD e = GetLastError();
+		if (e != ERROR_ALREADY_EXISTS) {
+			g_pLog->DisplayMessage(_T("DumpFB CreateDirectory failed (%lu): %s"), e, pszDir);
+			return FALSE;
+		}
 	}
 
-	MdigGetHookInfo(HookId, M_MODIFIED_BUFFER+M_BUFFER_ID, &ModifiedImage);
-	MbufControl(ModifiedImage, M_LOCK, M_DEFAULT);	
-	MbufGet2d(ModifiedImage,0,0,m_Param.nFrameWidth,m_Param.nFrameHeight,pBuffer);
-	MbufControl(ModifiedImage, M_UNLOCK, M_DEFAULT);	
-			
+	MIL_ID img = M_NULL;
+	MbufAlloc2d(m_MilSystem, W, H, milType, M_IMAGE + M_PROC, &img);
+	if (img == M_NULL) {
+		g_pLog->DisplayMessage(_T("DumpFB MbufAlloc2d failed: %dx%dx%dbit"), (int)W, (int)H, (int)bits);
+		return FALSE;
+	}
 
-	SetInsertFrame(m_nScanIndex,m_nSetBufferIdx);
+	static LONG sSeq = 0;
+	LONG seq = InterlockedIncrement(&sSeq);
 
+	MbufPut2d(img, 0, 0, W, H, pBuffer);
+
+	CString path;
+	path.Format(_T("%s\\Cam%d_Scan%d_seq%06ld.tif"), pszDir, m_Param.nCameraIdx, m_nScanIndex, (long)seq);
+
+	MIL_INT dummy = 0;
+	MappGetError(M_GLOBAL, &dummy);
+
+	MbufExport((MIL_CONST_TEXT_PTR)(LPCTSTR)path, M_TIFF, img);
+
+	MIL_INT err = 0;
+	if (MappGetError(M_GLOBAL, &err)) {
+		g_pLog->DisplayMessage(_T("DumpFB export failed (MIL_ERR=%lld): %s"), err, path);
+	}
+
+	MbufFree(img);
 	return TRUE;
 }
 
 long MFTYPE CGrabberRadient::CallbackHookFunction(long HookType, MIL_ID HookId, void MPTYPE *HookDataPtr)
 {
-	if(GetThreadPriority(GetCurrentThread()) != THREAD_PRIORITY_HIGHEST)
+	if (GetThreadPriority(GetCurrentThread()) != THREAD_PRIORITY_HIGHEST) {
 		SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+		g_pLog->DisplayMessage(_T("[Grab] CallbackHookFunction : thread priority set to HIGHEST"));
+	}
 
+	MIL_ID nEventDig = M_NULL;
 	CGrabberRadient	*pRadient = (CGrabberRadient*)HookDataPtr;
+	if (nullptr == pRadient){
+		return 0;
+	}
 
-	pRadient->Processing(HookType,HookId);	
+	MdigGetHookInfo(HookId, M_DIGITIZER_ID, &nEventDig);
+	if (nEventDig != pRadient->m_MilDigitizer) {
+		g_pLog->DisplayMessage(_T("CallbackHookFunction : HookId %lld does not match Digitizer %lld"), HookId, pRadient->m_MilDigitizer);
+		return 0;
+	}
 
-	return 0;
+	return pRadient->Processing(HookType, HookId) ? 0 : 1;
 }
 
 long MFTYPE CGrabberRadient::CallbackFreeRunFunction(long HookType, MIL_ID HookId, void MPTYPE *HookDataPtr)
 {
-	if(GetThreadPriority(GetCurrentThread()) != THREAD_PRIORITY_HIGHEST)
+	if (GetThreadPriority(GetCurrentThread()) != THREAD_PRIORITY_HIGHEST) {
 		SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+		g_pLog->DisplayMessage(_T("CallbackFreeRunFunction : thread priority set to HIGHEST"));
+	}
 
+	MIL_ID nEventDig = M_NULL;
 	CGrabberRadient	*pRadient = (CGrabberRadient*)HookDataPtr;
+	if (nullptr == pRadient) {
+		return 0;
+	}
 
-	if(pRadient->m_isLiveGrab == TRUE)		// Live Grab 鐭�.
-	{
+	MdigGetHookInfo(HookId, M_DIGITIZER_ID, &nEventDig);
+	if (nEventDig != pRadient->m_MilDigitizer) {
+		g_pLog->DisplayMessage(_T("CallbackFreeRunFunction : HookId %lld does not match Digitizer %lld"), HookId, pRadient->m_MilDigitizer);
+		return 0;
+	}
+
+	if(pRadient->m_isLiveGrab == TRUE) {
 		pRadient->m_nSetBufferIdx = 0;
+		int nCameraIdx = pRadient->m_Param.nCameraIdx;
 
-		LPBYTE		pBuffer = pRadient->m_pFrameBuffer->GetFrameBuferHeader(pRadient->m_nScanIndex,pRadient->m_nSetBufferIdx);
-		if(pBuffer == NULL)
-		{
+		LPBYTE pBuffer = pRadient->m_pFrameBuffer->GetFrameBuferHeader(pRadient->m_nScanIndex, pRadient->m_nSetBufferIdx);
+		if(pBuffer == NULL) {
 			pRadient->GrabScanStop();		
-			g_pStatus->SetGrabEnd(pRadient->m_nScanIndex);
+			g_pStatus->SetGrabEnd(nCameraIdx, pRadient->m_nScanIndex);
 			g_pLog->DisplayMessage(_T("%d Over Grab Buffer Stop Grab[%d][%d] - %d"), pRadient->m_Param.nBoardIdx, pRadient->m_nScanIndex, pRadient->m_nEndFrameIdx,pRadient->m_pFrameBuffer->GetFrameCount());
 			return TRUE;
 		}
 
 		MIL_ID ModifiedImage = 0;
-		MdigGetHookInfo(HookId, M_MODIFIED_BUFFER+M_BUFFER_ID, &ModifiedImage);
-		MbufControl(ModifiedImage, M_LOCK, M_DEFAULT);	
-		MbufGet2d(ModifiedImage,0,0,pRadient->m_Param.nFrameWidth,pRadient->m_Param.nFrameHeight,pBuffer);
-		MbufControl(ModifiedImage, M_UNLOCK, M_DEFAULT);	
+		MdigGetHookInfo(HookId, M_MODIFIED_BUFFER + M_BUFFER_ID, &ModifiedImage);
+		MbufControl(ModifiedImage, M_LOCK, M_DEFAULT);
+		MbufGet2d(ModifiedImage, 0, 0, pRadient->m_Param.nFrameWidth, pRadient->m_Param.nFrameHeight, pBuffer);
+		MbufControl(ModifiedImage, M_UNLOCK, M_DEFAULT);
 		
 		/*
-		int			iGrab = pRadient->m_nSetBufferIdx%pRadient->m_Param.nGrabBufCount;
+		int iGrab = pRadient->m_nSetBufferIdx%pRadient->m_Param.nGrabBufCount;
 		MbufGet(pRadient->m_MilImageChild[iGrab],pBuffer);
 		*/
+
+#if GRAB_DEBUG_ENABLE
+		// 鎵撳嵃閲囬泦璇︾粏淇℃伅
+		g_pLog->DisplayMessage(
+			_T("[Grab-FreeRun] FrameAcquired | Board=%d Cam=%d Scan=%d FrameIdx=%d BufIdx=%d Size=%dx%d BufCount=%d"),
+			pRadient->m_Param.nBoardIdx,
+			pRadient->m_Param.nCameraIdx,
+			pRadient->m_nScanIndex,
+			pRadient->m_nEndFrameIdx,
+			pRadient->m_nSetBufferIdx,
+			pRadient->m_Param.nFrameWidth,
+			pRadient->m_Param.nFrameHeight,
+			pRadient->m_pFrameBuffer->GetFrameCount()
+		);
+
+		// 璋冭瘯鐢ㄧ殑鍥惧儚杞瓨
+		 pRadient->DumpCurrentBuffer(pBuffer, GRAB_DUMP_DIR);
+#endif  // GRAB_DEBUG_ENABLE
 
 		return TRUE;
 	}	
@@ -471,24 +573,22 @@
 
 BOOL CGrabberRadient::CreateGrabBuffer(int nScanCount,int nBufSize, int nBufSizeX, int nBufSizeY)
 {
-	SIZE_T tempBufferSize= nBufSize;
-	SIZE_T tempFrmCX = nBufSizeX;
-	SIZE_T tempFrmCY = nBufSizeY;
-	SIZE_T TotalBufferSize= tempBufferSize*tempFrmCX*tempFrmCY;	
+	SIZE_T nTempBufferSize= nBufSize;
+	SIZE_T nTempFrmCX = nBufSizeX;
+	SIZE_T nTempFrmCY = nBufSizeY;
+	SIZE_T nTotalBufferSize= nTempBufferSize * nTempFrmCX * nTempFrmCY;
 	m_nAllocatedGrabBufSize = nBufSize;	
 
-	if(m_pFrameBuffer != NULL)
+	if (m_pFrameBuffer != NULL) {
 		delete m_pFrameBuffer;
-	m_pFrameBuffer = NULL;
+		m_pFrameBuffer = NULL;
+	}
 
 	m_pFrameBuffer = new CFrameBufferController;
-
-	if(TRUE == m_pFrameBuffer->CreateBuffer(m_Param.nCameraIdx,nBufSizeX ,nBufSizeY,nBufSize, nScanCount))
-	{		
+	if (TRUE == m_pFrameBuffer->CreateBuffer(m_Param.nCameraIdx, nBufSizeX, nBufSizeY, nBufSize, nScanCount)) {		
 		g_pLog->DisplayMessage(_T("Create Buffer success!:Id[%d],Frame[%d,%d],Cnt[%d]"),m_Param.nCameraIdx,nBufSizeX,nBufSizeY,nBufSize);		
 	}
-	else
-	{
+	else {
 		g_pLog->DisplayMessage(_T("Create Buffer Fail!:Id[%d],Frame[%d,%d],Cnt[%d]"),m_Param.nCameraIdx,nBufSizeX,nBufSizeY,nBufSize);
 		return FALSE;
 	}
@@ -498,8 +598,9 @@
 
 void CGrabberRadient::ClearBuffer()
 {
-	if(m_pFrameBuffer != NULL)
+	if (m_pFrameBuffer != NULL) {
 		m_pFrameBuffer->ClearBuffer();
+	}
 }
 
 void CGrabberRadient::ClearGrabIdx()
@@ -525,21 +626,19 @@
 	return TRUE;
 }
 
-BOOL CGrabberRadient::FindGrabIdx(int iScan,int iFrame)
+BOOL CGrabberRadient::FindGrabIdx(int iScan, int iFrame)
 {
 	CSingleLock MyLock(&m_csIdxLock);
 	MyLock.Lock();
 
-	BOOL				bRet = FALSE;
-	stFrameIndex		stFrame;
-	for(dqGrabIdxIt it=m_dqCallbackFrame.begin();it!=m_dqCallbackFrame.end();it++)
-	{
+	BOOL bRet = FALSE;
+	stFrameIndex stFrame;
+	for (dqGrabIdxIt it = m_dqCallbackFrame.begin(); it != m_dqCallbackFrame.end(); it++) {
 		stFrame = *it;
-
-		if(stFrame.nScanIdx == iScan)
-		{
-			if(stFrame.nFrameIdx < iFrame)
+		if (stFrame.nScanIdx == iScan) {
+			if (stFrame.nFrameIdx < iFrame) {
 				bRet = TRUE;
+			}
 		}
 	}
 	MyLock.Unlock();
@@ -558,8 +657,7 @@
 
 	CSingleLock MyLock(&m_csIdxLock);
 	MyLock.Lock();
-	if(IsHasGrabFrame() == FALSE)
-	{
+	if(IsHasGrabFrame() == FALSE) {
 		MyLock.Unlock();
 		return stPop;
 	}
@@ -574,11 +672,9 @@
 stFrameIndex CGrabberRadient::GetGrabFrame()
 {
 	stFrameIndex stPop(-1, -1);	
-
 	CSingleLock MyLock(&m_csIdxLock);
 	MyLock.Lock();
-	if(IsHasGrabFrame() == FALSE)
-	{
+	if(IsHasGrabFrame() == FALSE) {
 		MyLock.Unlock();
 		return stPop;
 	}
@@ -598,29 +694,73 @@
 
 BOOL CGrabberRadient::SetTriggerMode( BOOL bExTrigger )
 {	
-	INT nExposureTimer = m_Param.nExposure*1000;
-	INT nExposureTimerDelay = m_Param.nExposureDelay*1000;
-
-	if(bExTrigger == TRUE)	// Trigger
-	{
-		/*
-		MdigControl(m_MilDigitizer, M_CAMERALINK_CC1_SOURCE, M_GRAB_EXPOSURE+M_TIMER1);
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE+M_TIMER1, M_ENABLE);
-		//MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_SOURCE+M_TIMER1, nHWPort);
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME+M_TIMER1,  nExposureTimer);                        //10us
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME_DELAY+M_TIMER1,  nExposureTimerDelay);                 //10us
-		*/
-	}
-	else		// Live
-	{
-		/*
-		MdigControl(m_MilDigitizer, M_CAMERALINK_CC1_SOURCE, M_GRAB_EXPOSURE+M_TIMER1);
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE+M_TIMER1, M_ENABLE);
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_SOURCE+M_TIMER1, M_CONTINUOUS);                      // Periodic 鑴氶緥 鐗㈠晩
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME+M_TIMER1, nExposureTimer);                        //10000ns
-		MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME_DELAY+M_TIMER1,  nExposureTimerDelay);                 //10000ns
-		*/
+	if (m_MilDigitizer == M_NULL) {
+		g_pLog->DisplayMessage(_T("SetTriggerMode failed: digitizer is NULL"));
+		return FALSE;
 	}
 
+	INT nExposureTimer = m_Param.nExposure * 1000;
+	INT nExposureTimerDelay = m_Param.nExposureDelay * 1000;
+	//MdigControl(m_MilDigitizer, M_CAMERALINK_CC1_SOURCE, M_GRAB_EXPOSURE + M_TIMER1);
+	//MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE + M_TIMER1, M_ENABLE);
+	//MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_SOURCE + M_TIMER1, bExTrigger ? M_HARDWARE : M_CONTINUOUS);
+	//MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME + M_TIMER1, nExposureTimer);
+	//MdigControl(m_MilDigitizer, M_GRAB_EXPOSURE_TIME_DELAY + M_TIMER1, nExposureTimerDelay);
+	g_pLog->DisplayMessage(_T("TriggerMode=%s, Exp(ns)=%d, Delay(ns)=%d"), bExTrigger ? _T("External") : _T("Live"), nExposureTimer, nExposureTimerDelay);
+
+	return TRUE;
+}
+
+BOOL CGrabberRadient::DumpBufferAsOneImage(int iScan, LPCTSTR pszPath)
+{
+	if (!m_pFrameBuffer) {
+		g_pLog->DisplayMessage(_T("Dump m_pFrameBuffer is NULL"));
+		return FALSE;
+	}
+
+	const int nFramesAlloc = m_pFrameBuffer->GetFrameCount();
+	const int nFramesGrab = GetEndFrameIdx();
+	const int nFrames = (nFramesGrab > 0 && nFramesGrab <= nFramesAlloc) ? nFramesGrab : nFramesAlloc;
+	if (nFrames <= 0) {
+		return FALSE;
+	}
+
+	const MIL_INT W = m_Param.nFrameWidth;
+	const MIL_INT H = m_Param.nFrameHeight;
+
+	// 淇濇寔鐪熷疄浣嶆繁锛�8/10/12/16bit -> 8/16bit缂撳啿锛�
+	MIL_INT bits = 8;
+	if (m_MilDigitizer) { 
+		MdigInquire(m_MilDigitizer, M_SIZE_BIT, &bits);
+	}
+
+	const int bpp = (int)((bits + 7) / 8);
+	const MIL_INT type = (bpp >= 2) ? (16 + M_UNSIGNED) : (8 + M_UNSIGNED);
+
+	// 鎷兼帴鎴愪竴寮犻暱鍥�
+	MIL_ID img = M_NULL;
+	MbufAlloc2d(m_MilSystem, W, H * nFrames, type, M_IMAGE + M_PROC, &img);
+	if (img == M_NULL) { 
+		return FALSE;
+	}
+
+	for (int f = 0; f < nFrames; ++f) {
+		LPBYTE src = m_pFrameBuffer->GetFrameBuferHeader(iScan, f);
+		if (!src) { 
+			break;
+		}
+
+		MbufPut2d(img, 0, (MIL_INT)f * H, W, H, src);
+	}
+
+	MbufExport((MIL_CONST_TEXT_PTR)(LPCTSTR)pszPath, M_TIFF, img);
+
+	MIL_INT err = 0;
+	if (MappGetError(M_GLOBAL, &err)) {
+		g_pLog->DisplayMessage(_T("DumpBufferAsOneImage Error : %d"), err);
+		return FALSE;
+	}
+
+	MbufFree(img);
 	return TRUE;
 }
\ No newline at end of file

--
Gitblit v1.9.3