简体   繁体   中英

Using an intermediary function to direct a callback to a member function

I believe this question resembles this question . However I am not sure how to adjust that to my case. Here is what I am doing.

I currently have something like this

void IOCompletionCallback(_In_ DWORD dwErrorCode, _In_ DWORD dwNumberOfBytesTransfered, _Inout_ LPOVERLAPPED lpOverlapped)
{
   ......    
}

void foo::Work()
{
     if (!BindIoCompletionCallback(hnd, IOCompletionCallback, 0))
     {
          printf("Error (error code: %u)\n", GetLastError());
     }
}

In the above code I am using the windows API BindIoCompletionCallback which takes in the function IOCompletionCallback . What I would like to do is to actually make IOCompletionCallback a method of foo instead of a free function so I could do this

if (!BindIoCompletionCallback(hnd, std::bind( &foo::IOCompletionCallback,this), 0))
{
}

but I read that is impossible because signature of the method takes in a specific type. From the link I posted that it states that you can use an intermediary method. I am not sure how Ill be able to pass the instance address to that intermediary method. Any suggestions on that approach would be appreciated.

Use the lpoverlapped you create and pass in to the io operation to store the calllback. Well, data before/after ithe OVERLAPPED.. This function should just cast the overlapped to the larger state, find the callback you stored there, and invoke that callback.

The callback can be a std function with all of its wonderful utility.

template<class D>
struct MyOverlapped:OVERLAPPED{
  std::function<void(DWORD, DWORD, D*)> callback;
  MyOverlapped():OVERLAPPED{0}{}
  virtual ~MyOverlapped() {}
};

Something sort of like this. You'd use it like:

template<class D>
void MyIOCompletionCallback(_In_ DWORD dwErrorCode, _In_ DWORD dwNumberOfBytesTransfered, _Inout_ LPOVERLAPPED lpOverlapped)
{
  if (!lpOverlapped) return;
  auto* pOverlapped = static_cast<D*>(lpOverlapped);
  pOverlapped->callback( dwErrorCode, dwNumberOfBytesTransferred, pOverlapped );
  delete pOverlapped; // as MyOverlapped
}

struct ReadFileOverlapped: MyOverlapped<ReadFileOverlapped> {
  explicit ReadFileOverlapped(std::size_t count = 0) {
    data.resize(count);
  }
  DWORD size() const { return static_cast<DWORD>(data.size()); }
  std::vector<std::byte> data;
};
auto overlapped = std::make_unique<ReadFileOverlapped>(1024);
overlapped->callback = [=](_In_ DWORD dwErrorCode, _In_ DWORD dwNumberOfBytesTransfered, ReadFileOverlapped* pOverlapped ) {
  std::cout << "Error " << dwErrorCode << "\n";
  std::cout << "Bytes " << dwNumberOfBytesTransfered << "\n";
  // get at data in pOverlapped->data.data() through pOverlapped->data.data()+dwNumberOfBytesTransfered or somesuch
};
if (ReadFile( hnd,
  overlapped->data.data(),
  overlapped->size(),
  nullptr,
  overlapped.get()
)) {
  if (BindIoCompletionCallback(hnd, MyIOCompletionCallback<ReadFileOverlapped>, 0))
  {
    overlapped.release();
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM