sofsr
sofsr

Reputation:

Locking files using C++ on Windows

I have a program writing/reading from a file, and I want to lock the file for other instances of my application. How can I do it (in c++ visual studio 2003)? I tried using the _locking() but then also I myself cannot reach the file when trying to read/write (in the same instance). I know there's an option of LockFile() but have no idea how to set it properly. Please help me.

Upvotes: 6

Views: 26290

Answers (3)

phyatt
phyatt

Reputation: 19102

After searching online for a while, I didn't find any good examples.

Here are two calls to CreateFile with the intent of locking the file for the life of a process... I use this along side the CLimitSingleInstance that uses CreateMutex for a global named mutex.

The first call to CreateFile attempts to open it, the second one creates it if necessary. I have a little bit more thorough implementation. I implemented it in Qt, hence the qCritical() instead of std::cout and the QDir::tempPath() instead of getting that some other way.

class SingleInstance
{
protected:
    DWORD  m_dwLastError;
    HANDLE m_hFile;
public:
    SingleInstance(const char *strMutexName) {  }

    bool attemptToLockTempFile()
    {
      QString lockFile = QDir::tempPath() + "/My.exe.lock";
      m_hFile = CreateFileA(lockFile.toLocal8Bit().data(), GENERIC_READ, 0, 
                                NULL, OPEN_EXISTING, 0, NULL);
      DWORD dwLastError = GetLastError();
      if(m_hFile != NULL && m_hFile != INVALID_HANDLE_VALUE)
      {
          return true;
      }
      else
      {
          if(dwLastError == ERROR_FILE_NOT_FOUND )
          {
              m_hFile = CreateFileA(lockFile.toLocal8Bit().data(), GENERIC_READ, 
                                        0, NULL, CREATE_NEW, 0, NULL);
              dwLastError = GetLastError();

              if(m_hFile != NULL && m_hFile != INVALID_HANDLE_VALUE)
              {
                  return true;
              }
              else if(dwLastError == ERROR_SHARING_VIOLATION)
              {
                  qCritical() << "Sharing Violation on My.exe.lock";
              }
              else
              {
                  qCritical() << "Error reading" << "My.exe.lock" << "-" << dwLastError;
              }
          }
          else if(dwLastError == ERROR_SHARING_VIOLATION)
          {
              qCritical() << "Sharing Violation on My.exe.lock";
          }
          else
          {
              qCritical() << "Unable to obtain file lock -" << dwLastError;
          }
          return false;
      }
    }

    ~SingleInstance()
    {
        if ( m_hFile != NULL && m_hFile != INVALID_HANDLE_VALUE)
        {
            ::CloseHandle(m_hFile); //Do as late as possible.
            m_hFile = NULL;
        }
    }
}

Here is what you would have at the top of your main function:

SingleInstance g_SingleInstanceObj(globalId_QA);

// Makes sure that the program doesn't run if there is another 
// instance already running
if (g_SingleInstanceObj.IsAnotherInstanceRunning())
{
    return 0;
}

Upvotes: 1

Brian R. Bondy
Brian R. Bondy

Reputation: 347196

You can simply use the Win32 API CreateFile and then specify no sharing rights. This will ensure that no other processes can access the file.

The dwShareMode DWORD specifies the type of sharing you would like, for example GENERIC_READ. If you specify 0 then that means no sharing rights should be granted.

Example:

HANDLE hFile = CreateFile(_T("c:\\file.txt"), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

If you want to only lock a certain part of the file you can use LockFile or LockFileEx.

Example:

 //Lock the first 1024 bytes
 BOOL bLocked = LockFile(hFile, 0, 0, 1024, 0);

For locking on other platforms please see my post here.

Upvotes: 16

Shane C. Mason
Shane C. Mason

Reputation: 7615

You want LockFileEx() (exclusive file locking). Have a look at this discussion from Secure Programming Cookbook for C and C++.

Upvotes: 1

Related Questions