I looked for a way to email you some stuff, but ...
You don't [yet] support .net 4.5 async functions. I have added it with very little effort, thought maybe it would help.
/// <summary>Current status of the work</summary>
uint QueryStatus();
/// <summary>Wait a period of time. Result is true only if completed successfully.</summary>
bool Wait(TimeSpan TimeOut);
/// Provides extensions (note - only works in NET35 and higher
public static partial class Extensions
{
public static TimeSpan
TimeOut_Default = new TimeSpan(0, 5, 0);
/// Provides an awaitable process while running async operations
/// Since this is an extension, this is the object being extended
/// Maximum time to wait (default uses the static field "TimeOut_Default")
/// If operation succeded before the timeout occured, true. Otherwise false.
async static public System.Threading.Tasks.Task WaitAsync(this IVssAsyncResult Async, TimeSpan TimeOut)
{
if (Async==null || Async.IsCompleted)
return true;
System.Diagnostics.StackTrace // this part isn't necessary ... helps me follow the true stack
preException = new System.Diagnostics.StackTrace(1, true);
if (TimeOut.Milliseconds <= 0)
TimeOut = TimeOut_Default;
try
{
System.Threading.Tasks.Task
tsk = new System.Threading.Tasks.Task(() => { return Async.Wait(TimeOut); });
if (tsk.Status == System.Threading.Tasks.TaskStatus.Created)
tsk.Start();
await tsk;
if (tsk.Exception != null)
throw tsk.Exception;
return tsk.Result;
}
catch (Exception ex)
{ // this part isn't necessary ... helps me follow the true stack
Exception
iEx = new Exception("Fail waiting on Asyncronous operation");
zDougie.ExceptionExtensions.SetStack(ex, preException.ToString());
zDougie.ExceptionExtensions.InnerException(ex, iEx);
zDougie.ExceptionExtensions.Rethrow(ex);
return false; // will never happen - here just to keep compiler happy
}
}
}
namespace Alphaleonis {
namespace Win32 {
namespace Vss
{
VssAsyncResult::VssAsyncResult(::IVssAsync *vssAsync, AsyncCallback^ userCallback, Object^ asyncState)
: m_isComplete(0), m_asyncCallback(userCallback), m_asyncState(asyncState), m_asyncWaitHandle(nullptr), m_vssAsync(vssAsync), m_exception(nullptr)
{
if (!ThreadPool::QueueUserWorkItem(gcnew WaitCallback(this, &VssAsyncResult::WaitForAsyncCompletion)))
{
throw gcnew Exception(L"ThreadPool::QueueUserWorkItem failed.");
}
}
void VssAsyncResult::WaitForAsyncCompletion(Object^ state)
{
HRESULT hrResult;
#if ZDOUGIE
if (IsCompleted || m_vssAsync == 0)
return;
#endif
hrResult = m_vssAsync->Wait();
int prevState = Interlocked::Exchange(m_isComplete, -1);
if (prevState != 0)
throw gcnew InvalidOperationException("WaitForAsyncCompletion can only be called once.");
if (SUCCEEDED(hrResult))
{
#if ZDOUGIE
bool
t1 = m_vssAsync != 0,
t2 = m_vssAsync == nullptr,
t3 = m_vssAsync == NULL;
if (m_vssAsync != 0)
{
HRESULT hr = m_vssAsync->QueryStatus(&hrResult, NULL);
if (FAILED(hr))
hrResult = hr;
}
#else
HRESULT hr = m_vssAsync->QueryStatus(&hrResult, NULL);
if (FAILED(hr))
hrResult = hr;
#endif
}
if (FAILED(hrResult))
m_exception = GetExceptionForHr(hrResult);
else if (hrResult == VSS_S_ASYNC_CANCELLED)
m_exception = gcnew OperationCanceledException();
if (m_asyncWaitHandle != nullptr)
m_asyncWaitHandle->Set();
if (m_asyncCallback != nullptr)
m_asyncCallback(this);
}
void VssAsyncResult::EndInvoke()
{
// This method assumes that only 1 thread calls EndInvoke
// for this object
if (!IsCompleted)
{
AsyncWaitHandle->WaitOne();
AsyncWaitHandle->Close();
m_asyncWaitHandle = nullptr;
}
if (m_exception != nullptr)
throw m_exception;
}
Object^ VssAsyncResult::AsyncState::get()
{
return m_asyncState;
}
bool VssAsyncResult::CompletedSynchronously::get()
{
return false;
}
WaitHandle^ VssAsyncResult::AsyncWaitHandle::get()
{
if (m_asyncWaitHandle == nullptr)
{
bool done = IsCompleted;
ManualResetEvent^ ev = gcnew ManualResetEvent(done);
if (Interlocked::CompareExchange<ManualResetEvent^>(m_asyncWaitHandle, ev, nullptr) != nullptr)
{
ev->Close();
}
else
{
if (!done && IsCompleted)
{
m_asyncWaitHandle->Set();
}
}
}
return m_asyncWaitHandle;
}
bool VssAsyncResult::IsCompleted::get()
{
return Thread::VolatileRead(m_isComplete) != 0;
}
VssAsyncResult^ VssAsyncResult::Create(::IVssAsync *vssAsync, AsyncCallback^ userCallback, Object^ asyncState)
{
try
{
return gcnew VssAsyncResult(vssAsync, userCallback, asyncState);
}
catch (...)
{
vssAsync->Release();
throw;
}
}
VssAsyncResult::~VssAsyncResult()
{
this->!VssAsyncResult();
}
VssAsyncResult::!VssAsyncResult()
{
if (m_vssAsync != 0)
{
m_vssAsync->Release();
m_vssAsync = 0;
}
}
void VssAsyncResult::Cancel()
{
#if ZDOUGIE
if (m_vssAsync != 0)
{
CheckCom(m_vssAsync->Cancel());
}
#endif // ZDOUGIE
}
#if ZDOUGIE && NET45
UINT VssAsyncResult::QueryStatus()
{
if (m_vssAsync != 0)
{
HRESULT
hr = 0;
Int32
resv = 0;
CheckCom(m_vssAsync->QueryStatus(&hr, &resv));
return hr;
}
return (zDougie::NativeMethods::NtStatus)S_OK;
}
bool VssAsyncResult::Wait(TimeSpan TimeOut)
{
if (m_vssAsync != 0)
{
UInt32
ms = (UInt32)TimeOut.TotalMilliseconds;
if (ms <= 0)
ms = 1000 * 5 * 60;
UINT
result = m_vssAsync->Wait(ms);
if ((UINT)result == VSS_E_UNEXPECTED || (UINT)result == E_ACCESSDENIED)
zDougie::NativeMethods::ThrowOnFailure(result, "Waiting for Async Operation");
return (UINT)result == S_OK;
}
return true;
}
#endif // ZDOUGIE && NET45
}
}}