2011-12-23 78 views
1
關閉原始一個

我開發了以下類:複製手柄和事後

class Handle 
{ 
public: 
    inline Handle() 
    { 
     handle = INVALID_HANDLE_VALUE; 
    } 
    inline Handle(HANDLE handle) 
    { 
     this->handle = copyHandle(handle); 
    } 
    inline Handle(const Handle& rhs) 
    { 
     this->handle = copyHandle(rhs.handle); 
    } 
    inline bool isValid() 
    { 
     return handle != INVALID_HANDLE_VALUE; 
    } 
    inline HANDLE getNativeHandle() 
    { 
     return copyHandle(this->handle); 
    } 
    inline void close() 
    { 
     if(handle != INVALID_HANDLE_VALUE) 
     { 
      CloseHandle(handle); 
      handle = INVALID_HANDLE_VALUE; 
     } 

    } 
    inline virtual ~Handle() 
    { 
     if(handle != INVALID_HANDLE_VALUE) 
      CloseHandle(handle); 
    } 
protected: 
    HANDLE handle; 
    HANDLE copyHandle(HANDLE copyable); 
}; 

.cpp文件:

HANDLE Handle::copyHandle(HANDLE copyable) 
{ 
    HANDLE ret; 
    HANDLE current = GetCurrentProcess(); 
    if(copyable == INVALID_HANDLE_VALUE) 
     ret = copyable; 

    else if(DuplicateHandle(current, copyable, current, &ret, 0, TRUE , DUPLICATE_SAME_ACCESS) == 0) 
     { 
      if(GetLastError() == ERROR_ACCESS_DENIED) 
       throw SecurityException("The handle duplication was denied!"); 
      else 
       throw InvalidHandleException("The handle could not be duplicated!"); 
     } 

    return ret; 
} 

類似乎很好地工作正常,但複製手柄,然後關閉原始句柄,然後複製新句柄將拋出異常或Windows Errorcode 6,它是「無效句柄值」。

目前,我認爲關閉原來的手柄會導致副本的完全破壞,並使我無法在之後使用它們。

Handle test = CreateMutex(NULL, FALSE, NULL); 
Handle copy = test; 
test.close(); 
std::cout << copy.getNativeHandle() << std::endl; // throws an exception, but uses the same function as above 
return 0; 

是否有重複的手柄,它不依賴於原來存在的可能性?

+0

旁白:'inline'是在成員函數隱含_defined_類體中。你不需要明確地陳述它,大多數程序員不需要。 – 2011-12-23 21:05:39

+0

好的,我改變了這一點,感謝您的幫助! – jgpt 2011-12-23 21:07:41

+1

兩條評論:你沒有定義一個複製賦值操作符,所以可以在不復制包含的句柄的情況下複製你的類,你的意思是複製'getNativeHandle'上的句柄?這意味着您的類的所有客戶端在每次檢索時都需要手動關閉返回的句柄。它不會讓您的班級爲客戶讓生活變得更加輕鬆。 – 2011-12-23 21:10:43

回答

0

您還需要爲Handle定義一個賦值運算符。我懷疑實際崩潰的代碼如下所示:

Handle test = CreateMutex(NULL, FALSE, NULL); 
Handle copy; 
copy= test; // assigned instead of using copy constructor 
test.close(); 
std::cout << copy.getNativeHandle() << std::endl; 
return 0; 

如果沒有賦值運算符,則不會正確複製句柄。

+0

我現在增加了:'Handle&operator =(const Handle&other) { this-> close() ); this-> handle = copyHandle(other.handle); return * this; } – jgpt 2011-12-23 21:40:40

2

試試這個實施:

class Handle 
{ 
public: 
    Handle(HANDLE ahandle = INVALID_HANDLE_VALUE) 
    { 
     handle = ahandle; // <- take ownership of the original, not a copy 
    } 

    Handle(const Handle& src)  
    { 
     handle = src.duplicate(); // <-- take ownership of a copy 
    } 

    ~Handle() 
    { 
     close(); 
    } 

    void close() 
    { 
     if (handle != INVALID_HANDLE_VALUE) 
     { 
      CloseHandle(handle); 
      handle = INVALID_HANDLE_VALUE; 
     } 
    } 

    HANDLE getNativeHandle() const 
    { 
     return handle; 
    } 

    bool isValid() const 
    { 
     return (handle != INVALID_HANDLE_VALUE); 
    } 

    HANDLE duplicate() 
    { 
     if (handle == INVALID_HANDLE_VALUE) 
      return handle; 

     HANDLE ret, current = GetCurrentProcess(); 
     if (!DuplicateHandle(current, handle, current, &ret, 0, TRUE, DUPLICATE_SAME_ACCESS)) 
     { 
      if (GetLastError() == ERROR_ACCESS_DENIED) 
       throw SecurityException("The handle duplication was denied!"); 
      else 
       throw InvalidHandleException("The handle could not be duplicated!"); 
     } 

     return ret; 
    } 

    Handle& operator=(HANDLE &rhs) 
    { 
     close(); 
     handle = rhs; // <-- take ownership of the original, not a copy 
     return *this; 
    } 

    Handle& operator=(const Handle &rhs) 
    { 
     close(); 
     handle = rhs.duplicate(); // <-- take ownership of a copy 
     return *this; 
    } 

protected: 
    HANDLE handle; 
}; 

在一個側面說明,一些API函數使用NULL代替INVALID_HANDLE_VALUE,有的不使用CloseHandle()。你應該考慮考慮這些差異。我建議更新Handle類使用C++模板,這樣你就可以專注於每個實例的基礎上的行爲,如:

struct InvalidHandleTrait 
{ 
    static const HANDLE InvalidValue = INVALID_HANDLE_VALUE; 
}; 

struct NullHandleTrait 
{ 
    static const HANDLE InvalidValue = NULL; 
}; 

struct CloseHandleTrait 
{ 
    static bool close(HANDLE handle) 
    { 
     return CloseHandle(handle); 
    } 
}; 

template< typename HandleTrait = InvalidHandleTrait, typename CloseTrait = CloseHandleTrait > 
class Handle 
{ 
public: 
    Handle(HANDLE ahandle = HandleTrait::InvalidValue) 
    { 
     handle = ahandle; // <- take ownership of the original, not a copy 
    } 

    Handle(const Handle& src)  
    { 
     handle = src.duplicate(); // <-- take ownership of a copy 
    } 

    ~Handle() 
    { 
     close(); 
    } 

    void close() 
    { 
     if (handle != HandleTrait::InvalidValue) 
     { 
      CloseTrait::close(handle); 
      handle = HandleTrait::InvalidValue; 
     } 
    } 

    HANDLE getNativeHandle() const 
    { 
     return handle; 
    } 

    bool isValid() const 
    { 
     return (handle != HandleTrait::InvalidValue); 
    } 

    HANDLE duplicate() 
    { 
     if (handle == HandleTrait::InvalidValue) 
      return handle; 

     HANDLE ret, current = GetCurrentProcess(); 
     if (!DuplicateHandle(current, handle, current, &ret, 0, TRUE, DUPLICATE_SAME_ACCESS)) 
     { 
      if (GetLastError() == ERROR_ACCESS_DENIED) 
       throw SecurityException("The handle duplication was denied!"); 
      else 
       throw InvalidHandleException("The handle could not be duplicated!"); 
     } 

     return ret; 
    } 

    Handle& operator=(HANDLE &rhs) 
    { 
     close(); 
     handle = rhs; // <-- take ownership of the original, not a copy 
     return *this; 
    } 

    Handle& operator=(const Handle &rhs) 
    { 
     close(); 
     handle = rhs.duplicate(); // <-- take ownership of a copy 
     return *this; 
    } 

protected: 
    HANDLE handle; 
}; 
+0

有沒有辦法區分GetCurrentProcess中的Handle和標準的無效句柄? – jgpt 2011-12-23 22:40:22

+0

你的意思是'DuplicateHandle()'而不是'GetCurrentProcess()'? 'GetCurrentProcess()'返回一個僞句柄。 AFAIK,沒有辦法查詢句柄,以知道它是否重複。無論哪種方式,這兩種類型的句柄都不會被設置爲「INVALID_HANDLE_VALUE」。 – 2011-12-24 16:24:35