可视化调试:基于共享内存发送数据

大多算法都有自己特定的数据流程,给调试带来麻烦。

如果在几个关键节点,能够把当前数据发送给外部的显示程序实时显示,很多问题都能一目了然。

在进程之间传递数据的最好手段,应该是共享内存了。当然发送者和接收者之间还要约定好消息ID,代表特定的数据格式,接收者得到数据之后才能理解显示。

下面的演示代码我已经用过很长时间,比较稳定了,与大家分享:

 

class CShareMem//通过名字标识的共享内存
{
protected:
 TCHAR m_szShareName[64];
 HANDLE m_hShareMem;  //共享内存句柄
 BYTE * m_pBuffer;   //映射地址
 bool m_bFirst;   //是否第一次分配

public:
 CShareMem():m_hShareMem(0),m_pBuffer(0),m_bFirst(false){
  m_szShareName[0]= 0;
 };
 virtual ~CShareMem(){
  free();
 };

 bool isinited() const{
  return (m_pBuffer!=0);
 };

 //根据指定的名字分配一个共享内存或取得一个共享内存
 //如果是分配的m_bFirst为TRUE,如果是取得的m_bFirst为FALSE
 //不管分配还是取得的,如果成功就返回TRUE
 bool init(LPCTSTR lpShareName, DWORD size=0);

 //必要是重新分配内存
 bool realloc(DWORD mem);
 
 //释放共享内存
 void free();

 //设置共享内存中的数据
 bool setbuf(const void* pBuf, DWORD buflen);

 //发送数据
 bool sendata(const void* pBuf, DWORD buflen,
     DWORD msgid, DWORD wpara, DWORD lpara,
     HWND& hwnd, LPCTSTR szExeTitle);

public:
 //取当前放在共享内存的数据长度
 DWORD getdatasize() const{
  if(m_pBuffer==0)
   return 0;
  DWORD datasize= *(DWORD*)(m_pBuffer+sizeof(DWORD));
  return datasize;
 };
 DWORD getcapacity() const{
  if(m_pBuffer==0)
   return 0;
  DWORD mem= *(DWORD*)(m_pBuffer);
  return mem;
 };

 //取得分配的共享内存地址
 BYTE* getbuf(){
  if(m_pBuffer==0)
   return 0;
  else
   return (m_pBuffer+sizeof(DWORD)*2);
 };


 //是分配还是取得,分配为TRUE,取得为FALSE
 bool isfirst() const{
  return m_bFirst;
 };

 //取得共享内存句柄
 HANDLE gethandle(){
  return m_hShareMem;
 };
};


inline bool CShareMem::init(LPCTSTR lpShareName, DWORD size)
{
 lstrcpy(m_szShareName, lpShareName);
 if(m_hShareMem==0)
 {  
  m_hShareMem = OpenFileMapping(FILE_MAP_WRITE, FALSE, lpShareName);
  if(m_hShareMem)
  {//共享内存已经存在
   m_bFirst = false;
  }
  else if(size>0)
  {//共享内存不存在
   return realloc(size);
  }

  if(m_hShareMem==0)
   return false;
  m_pBuffer= (BYTE*)MapViewOfFile(m_hShareMem, FILE_MAP_WRITE, 0, 0, 0);
  if(m_pBuffer==0)
   return false;

  assert(!m_bFirst);
 }
 return true;
}
inline bool CShareMem::realloc(DWORD size)
{
 free();
 m_bFirst = true;

 //对齐系统内存分页地址
 SYSTEM_INFO info;
 GetSystemInfo(&info);
 DWORD dwAllocUnit= info.dwAllocationGranularity;
 size= (size/dwAllocUnit + 1)*dwAllocUnit;

 m_hShareMem = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, size, m_szShareName);
 if(m_hShareMem==0)
  return false;
   
 DWORD capacity= size;
 m_pBuffer= (BYTE*)MapViewOfFile(m_hShareMem, FILE_MAP_WRITE, 0, 0, 0);

 //第一次成功分配内存后用0初始化该内存
 ZeroMemory(m_pBuffer, min(64,size/64));
 *(DWORD*)m_pBuffer= capacity;
 return true;
}

inline void CShareMem::free()
{
 if(m_pBuffer)
 {
  UnmapViewOfFile(m_pBuffer);
  m_pBuffer= 0;
 }

 if(m_hShareMem)
 {
  CloseHandle(m_hShareMem);
  m_hShareMem= 0;
  m_bFirst= false;
 }
}

//设置共享内存中的数据
inline bool CShareMem::setbuf(const void* pBuf, DWORD buflen)
{
 DWORD capacity= getcapacity();
 if(buflen+sizeof(DWORD)*4>capacity){
  if(!realloc(buflen+sizeof(DWORD)*4))
   return false;
 }

 *(DWORD*)(m_pBuffer+sizeof(DWORD))= buflen; //设置datasize!
 memcpy(m_pBuffer+sizeof(DWORD)*2, pBuf, buflen);
 return true;
}


//通过共享内存发送数据
inline bool CShareMem::sendata( const void* pBuf, DWORD buflen,
        DWORD msgid, DWORD wpara, DWORD lpara,
        HWND& hwnd, LPCTSTR szExeTitle)
{
 assert(isinited());
 if(hwnd){
  if(!IsWindow(hwnd))//maybe closed!
   hwnd= 0;
 }

 if(hwnd==0){
  hwnd= ::FindWindow(0, szExeTitle);
#ifdef _DEBUG
  if(hwnd==0){
 // #ifdef _UNICODE
 //  TRACE(_T("run %S.exe, please!\n"), szExeTitle);
 // #else
   TRACE(_T("run %s.exe, please!\n"), szExeTitle);
 // #endif
  }
#endif
 }

 if(hwnd==0){
 // AfxMessageBox(_T("run StchViewer.exe, please!\n"));
  return false;
 }

 if(!setbuf(pBuf, buflen))
  return false;
  
// ::ShowWindow(hwnd, SW_SHOWNORMAL); 
 ::PostMessage(hwnd, msgid, wpara, lpara);
 return true;
}

/
#define WM_XBUFFER_DATA  WM_USER+110
inline bool SendBmpBufData(const BYTE* pBuf,int width,int height, LPCTSTR appname = _T("Observer"))
{
 bool sucd= false;
 static HWND hwnd= 0;
 static CShareMem sharem;
 DWORD buflen= (DWORD)(width*height);
 if(!sharem.isinited()){
  DWORD H(1024),W(4096);
  sharem.init(_T("sharem_xbuffer"), max(W*H, buflen+1024));
 }

 if(sharem.isinited()){
  ASSERT((width&3)==0); //width若不为4的倍数时,接收到的图像可能错位!
  sucd= sharem.sendata(pBuf,buflen, WM_XBUFFER_DATA, width,height, hwnd, appname );
 }
 return sucd;
}

上面的 SendBmpBufData 就能够把灰度图像数据发给我的 Image Observer,我就能立即看到图像,获知当前程序的处理状态是否正常,如果出错又错在哪里,给算法调试带来了非常大的方便。我还利用这种方法,把多边形曲线轮廓数据发送给相应的数据显示浏览程序,这给算法的跟踪调试带来的好处是显而易见的。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值