2012年1月9日 星期一

[C++] Mutex


1. 同一個時間內只能夠有一個執行緒擁有mutex。
2. 同一個時間內只能夠有一個執行緒進入critical section。
3. Mutex速度較慢。因為Critical Section不需要進入OS核心,直接在User Mode 就可以進行動作。
4. Mutex可以跨Process使用。Critical Section則只能夠在同一個Process使用。
5. 等待一個mutex時,你可以指定『結束等待』時間長度,但對於critical section則不行。

用CreateMutex來產生Mutex
HANDLE WINAPI CreateMutex(
  __in_opt  LPSECURITY_ATTRIBUTES lpMutexAttributes,
  __in      BOOL bInitialOwner,
  __in_opt  LPCTSTR lpName
);
// The name can have a "Global\" or "Local\" prefix to explicitly create the object in the global or session namespace. The remainder of the name can contain any character except the backslash character (\).
用ReleaseMutex來釋放Mutex
BOOL WINAPI ReleaseMutex(
  __in  HANDLE hMutex
);
簡單的範例
CMutex::CMutex(std::wstring wstrMutexName)
{
 std::wstring wstrMutex = L"Global\\";
 wstrMutex += wstrMutexName;
 m_mutex = ::CreateMutex(NULL, FALSE, wstrMutex.c_str());
}

CMutex::~CMutex()
{
 ::CloseHandle(m_mutex);
}

HRESULT CMutex::Lock()
{
  HRESULT hr = E_FAIL;
 DWORD dRet = WaitForSingleObject(m_mutex, INFINITE);
 switch (dRet)
 {
  case WAIT_TIMEOUT:  // Time out
   break;
  case WAIT_OBJECT_0:  // Process over
    hr = S_OK;
   break;
  case WAIT_OBJECT_0 + 1: // Don't Know
   break;
 }
 return hr;
}

void CMutex::Unlock()
{
 ::ReleaseMutex(m_mutex);
}
如果想要利用Mutex讓一個Process在同一時間只被執行一次的話,可以用下列的方法檢查

1.Mutex的Create是否有Error
CMutex g_vthumbMutex(strModuleName);
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
 return;
}
2. 用OpenMutex
HANDLE WINAPI OpenMutex(
  __in  DWORD dwDesiredAccess,
  __in  BOOL bInheritHandle,
  __in  LPCTSTR lpName
);
Reference:

[C++] Enumerate file in directory.

bool findFileInDir(wchar_t* rootDir)
{
 wchar_t fname[BUFFSIZE];
 ZeroMemory(fname, BUFFSIZE);

 WIN32_FIND_DATA fd;
 ZeroMemory(&fd, sizeof(WIN32_FIND_DATA));

 HANDLE hSearch;
 wchar_t filePathName[BUFFSIZE];
 wchar_t tmpPath[BUFFSIZE];
 ZeroMemory(filePathName, BUFFSIZE);
 ZeroMemory(tmpPath, BUFFSIZE);

 wcscpy(filePathName, rootDir);
 BOOL bSearchFinished = FALSE;

 if( filePathName[wcslen(filePathName) -1] != L'\\' )
 {
  wcscat(filePathName, L"\\");
 }

 wcscat(filePathName, L"*");

 hSearch = FindFirstFile(filePathName, &fd);

 //Is directory
 if( (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  && wcscmp(fd.cFileName, L".") && wcscmp(fd.cFileName, L"..") )
 {
  wcscpy(tmpPath, rootDir);
  wcscat(tmpPath, fd.cFileName);
  wcscat(tmpPath, L"\\");
  findFileInDir(tmpPath);
 }
 else if( wcscmp(fd.cFileName, L".") && wcscmp(fd.cFileName, L"..") )
 {
  wsprintf(fname, L"%ls%ls", rootDir, fd.cFileName);
  DEBUG_MSG((L"[findFileInDir] filename: %ls", fname));
 }

 while( !bSearchFinished )
 {
  if( FindNextFile(hSearch, &fd) )
  {
   if( (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
    && wcscmp(fd.cFileName, L".") && wcscmp(fd.cFileName, L"..") )
   {
    wcscpy(tmpPath, rootDir);
    wcscat(tmpPath, fd.cFileName);
    wcscat(tmpPath, L"\\");
    findFileInDir(tmpPath);
   }
   else if( wcscmp(fd.cFileName, L".") && wcscmp(fd.cFileName, L"..") )
   {
    wsprintf(fname, L"%ls%ls", rootDir, fd.cFileName);
    DEBUG_MSG((L"[findFileInDir] filename: %ls", fname));
   }
  }
  else
  {
   if( GetLastError() == ERROR_NO_MORE_FILES )          //Normal Finished
   {
    bSearchFinished = TRUE;
   }
   else
    bSearchFinished = TRUE;     //Terminate Search
  }
 }

 FindClose(hSearch);
 return true;
}

[C++] How to get free disk space

int getFreeSpace(wstring wstrWorkingFolder)
{
 int nFreeSpace = 0;

 HINSTANCE hModule = ::LoadLibrary(L"KERNEL32.DLL");
 if(hModule)
 {
  PFNGETDISKFREESPACEEX pDiskFreeSpaceEx = NULL;

  // Determine function to use
  pDiskFreeSpaceEx = reinterpret_cast(::GetProcAddress(hModule, "GetDiskFreeSpaceExA"));
  if(!pDiskFreeSpaceEx)
  {
   DWORD dwSectorsPerCluster = 0;
   DWORD dwBytesPerSector    = 0; 
   DWORD dwFreeClusters      = 0; 
   DWORD dwClusters          = 0; 

   if(::GetDiskFreeSpace(wstrWorkingFolder.c_str(), &dwSectorsPerCluster, &dwBytesPerSector, &dwFreeClusters, &dwClusters) == TRUE)
   {
    nFreeSpace = dwFreeClusters * dwBytesPerSector * dwSectorsPerCluster;
   }
  }
  else
  {
   ULARGE_INTEGER uliFreeBytesAvailableToCaller;
   ULARGE_INTEGER uliTotalNumberOfBytes;
   ULARGE_INTEGER uliTotalNumberOfFreeBytes;

   if(::GetDiskFreeSpaceEx(wstrWorkingFolder.c_str(), &uliFreeBytesAvailableToCaller, &uliTotalNumberOfBytes, &uliTotalNumberOfFreeBytes) == TRUE) 
   {
    nFreeSpace = static_cast<__int64>(uliFreeBytesAvailableToCaller.QuadPart / (1024 * 1024));
   }
  }

  // Release library
  ::FreeLibrary(hModule);
 }
 return nFreeSpace;
}

[C++] Check Process

bool CheckProcess(wstring wstrExeName)
{
 bool bHasProcess = false;
 unsigned long aProcesses[1024], cbNeeded, cProcesses;
 if(EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
 {
  cProcesses = cbNeeded / sizeof(unsigned long);
  for(unsigned int i = 0; i < cProcesses; i++)
  {
   if(aProcesses[i] == 0)
    continue;

   HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, aProcesses[i]);
   wchar_t buffer[50];
   GetModuleBaseNameW(hProcess, 0, buffer, 50);
   CloseHandle(hProcess);
   if(wstrExeName == wstring(buffer))
   {
    bHasProcess = true;
    break;
   }
  }
 }
 return bHasProcess;
}

[C++] Kill Process

bool KillProcess(wstring wstrExename)
{
 bool bOK = false;
 WCHAR wszCmd[2048];
 int nSize = 160;
 PROCESS_INFORMATION pi;
 STARTUPINFOW si;
 ZeroMemory(&si, sizeof(STARTUPINFOW));
 ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
 si.cb = sizeof(STARTUPINFOW);
 si.dwFlags = STARTF_USESHOWWINDOW;
 si.wShowWindow = SW_HIDE;

 swprintf(wszCmd, L"taskkill /F /IM %s", wstrExename.c_str());
 if (CreateProcessW(NULL, wszCmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE|IDLE_PRIORITY_CLASS, NULL, NULL, &si, &pi))
 {
  int nKillWaitTime = 30000;
  int nRet = WaitForSingleObject(pi.hProcess, nKillWaitTime);
  switch (nRet)
  {
  case WAIT_TIMEOUT:  // Time out
   break;
  case WAIT_OBJECT_0:  // Process over
   break;
  case WAIT_OBJECT_0 + 1: // Don't Know
   break;
  }
  CloseHandle(pi.hProcess);
  pi.hProcess = NULL;
  CloseHandle(pi.hThread);
  pi.hThread = NULL;
  bOK = true;
 }
 return bOK;
}

[C++] Create Process

bool CreateProcess(wstring wstrProcessName, wstring wstrParas, )
{
  WCHAR wszCmd [2048] = {0};
  swprintf(wszCmd, L"%ls %ls", wstrProcessName.c_str(), wstrParas.c_str());

  int nProcessPriority = BELOW_NORMAL_PRIORITY_CLASS;
  STARTUPINFOW si;
  PROCESS_INFORMATION pi;
  ZeroMemory(&si, sizeof(STARTUPINFOW));
  ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
  si.cb = sizeof(STARTUPINFOW);
  si.dwFlags = STARTF_USESHOWWINDOW;
  si.wShowWindow = SW_HIDE;

  if (CreateProcessW(NULL, wszCmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE|nProcessPriority, NULL, NULL, &si, &pi))
  {
    return true;
  }
  return false;
}

[C++] wstring to string

Here is an example for wstring to string transform.
HRESULT DSU_WcsToStr(wstring wstrSrc, string* strDst, UINT nCodepage)
{
 _DSU_ChkPtrRtn(strDst);

 int iStrLen = wstrSrc.length();
 int nCount = WideCharToMultiByte(nCodepage, 0, wstrSrc.c_str(), iStrLen, NULL, 0, NULL, FALSE);

 char* pCHAR = new char[nCount + 1]; 
 nCount = WideCharToMultiByte(nCodepage, 0, wstrSrc.c_str(), iStrLen, pCHAR, nCount + 1, NULL, FALSE);

 pCHAR[nCount] = NULL;
 *strDst = pCHAR ;
 delete [] pCHAR ; 

 return S_OK ;
}

[C++] string to wstring

Here is an example for string to wstring transform.
HRESULT DSU_StrToWcs( string strSrc, wstring* wstrDst, UINT nCodepage = CP_UTF8) ;

HRESULT DSU_StrToWcs(string strSrc, wstring* wstrDst, UINT nCodepage)
{
 if ( wstrDst == NULL ) 
  return E_POINTER;

 int iStrLen = strSrc.length() ;

 int nCount = MultiByteToWideChar(nCodepage, 0, strSrc.c_str(), iStrLen, NULL, 0) ;
 WCHAR* pWCHAR = (WCHAR*)alloca(sizeof(WCHAR) * (nCount + 1)) ;

 nCount = MultiByteToWideChar(nCodepage, 0, strSrc.c_str(), iStrLen, pWCHAR, nCount+1) ;
 pWCHAR[nCount] = NULL ;

 *wstrDst = pWCHAR ;

 return S_OK ;
}