foobar2000 SDK  2015-08-03
file_win32_wrapper.cpp
Go to the documentation of this file.
1 #include "stdafx.h"
2 
3 #ifdef _WIN32
4 namespace file_win32_helpers {
6  union {
7  t_uint64 val64;
8  t_uint32 val32[2];
9  } u;
10 
11  u.val64 = 0;
12  SetLastError(NO_ERROR);
13  u.val32[0] = GetFileSize(p_handle,reinterpret_cast<DWORD*>(&u.val32[1]));
14  if (GetLastError()!=NO_ERROR) exception_io_from_win32(GetLastError());
15  return u.val64;
16  }
17  void seek(HANDLE p_handle,t_sfilesize p_position,file::t_seek_mode p_mode) {
18  union {
19  t_int64 temp64;
20  struct {
21  DWORD temp_lo;
22  LONG temp_hi;
23  };
24  };
25 
26  temp64 = p_position;
27  SetLastError(ERROR_SUCCESS);
28  temp_lo = SetFilePointer(p_handle,temp_lo,&temp_hi,(DWORD)p_mode);
29  if (GetLastError() != ERROR_SUCCESS) exception_io_from_win32(GetLastError());
30  }
31 
32  void fillOverlapped(OVERLAPPED & ol, HANDLE myEvent, t_filesize s) {
33  ol.hEvent = myEvent;
34  ol.Offset = (DWORD)( s & 0xFFFFFFFF );
35  ol.OffsetHigh = (DWORD)(s >> 32);
36  }
37 
38  void writeOverlappedPass(HANDLE handle, HANDLE myEvent, t_filesize position, const void * in,DWORD inBytes, abort_callback & abort) {
39  abort.check();
40  if (inBytes == 0) return;
41  OVERLAPPED ol = {};
42  fillOverlapped(ol, myEvent, position);
43  ResetEvent(myEvent);
44  DWORD bytesWritten;
45  SetLastError(NO_ERROR);
46  if (WriteFile( handle, in, inBytes, &bytesWritten, &ol)) {
47  // succeeded already?
48  if (bytesWritten != inBytes) throw exception_io();
49  return;
50  }
51 
52  {
53  const DWORD code = GetLastError();
54  if (code != ERROR_IO_PENDING) exception_io_from_win32(code);
55  }
56  const HANDLE handles[] = {myEvent, abort.get_abort_event()};
57  SetLastError(NO_ERROR);
58  DWORD state = WaitForMultipleObjects(_countof(handles), handles, FALSE, INFINITE);
59  if (state == WAIT_OBJECT_0) {
60  try {
61  WIN32_IO_OP( GetOverlappedResult(handle,&ol,&bytesWritten,TRUE) );
62  } catch(...) {
63  CancelIo(handle);
64  throw;
65  }
66  if (bytesWritten != inBytes) throw exception_io();
67  return;
68  }
69  CancelIo(handle);
70  throw exception_aborted();
71  }
72 
73  void writeOverlapped(HANDLE handle, HANDLE myEvent, t_filesize & position, const void * in, size_t inBytes, abort_callback & abort) {
74  const enum {writeMAX = 16*1024*1024};
75  size_t done = 0;
76  while(done < inBytes) {
77  size_t delta = inBytes - done;
78  if (delta > writeMAX) delta = writeMAX;
79  writeOverlappedPass(handle, myEvent, position, (const BYTE*)in + done, (DWORD) delta, abort);
80  done += delta;
81  position += delta;
82  }
83  }
84  void writeStreamOverlapped(HANDLE handle, HANDLE myEvent, const void * in, size_t inBytes, abort_callback & abort) {
85  const enum {writeMAX = 16*1024*1024};
86  size_t done = 0;
87  while(done < inBytes) {
88  size_t delta = inBytes - done;
89  if (delta > writeMAX) delta = writeMAX;
90  writeOverlappedPass(handle, myEvent, 0, (const BYTE*)in + done, (DWORD) delta, abort);
91  done += delta;
92  }
93  }
94 
95  DWORD readOverlappedPass(HANDLE handle, HANDLE myEvent, t_filesize position, void * out, DWORD outBytes, abort_callback & abort) {
96  abort.check();
97  if (outBytes == 0) return 0;
98  OVERLAPPED ol = {};
99  fillOverlapped(ol, myEvent, position);
100  ResetEvent(myEvent);
101  DWORD bytesDone;
102  SetLastError(NO_ERROR);
103  if (ReadFile( handle, out, outBytes, &bytesDone, &ol)) {
104  // succeeded already?
105  return bytesDone;
106  }
107 
108  {
109  const DWORD code = GetLastError();
110  switch(code) {
111  case ERROR_HANDLE_EOF:
112  case ERROR_BROKEN_PIPE:
113  return 0;
114  case ERROR_IO_PENDING:
115  break; // continue
116  default:
118  };
119  }
120 
121  const HANDLE handles[] = {myEvent, abort.get_abort_event()};
122  SetLastError(NO_ERROR);
123  DWORD state = WaitForMultipleObjects(_countof(handles), handles, FALSE, INFINITE);
124  if (state == WAIT_OBJECT_0) {
125  SetLastError(NO_ERROR);
126  if (!GetOverlappedResult(handle,&ol,&bytesDone,TRUE)) {
127  const DWORD code = GetLastError();
128  if (code == ERROR_HANDLE_EOF || code == ERROR_BROKEN_PIPE) bytesDone = 0;
129  else {
130  CancelIo(handle);
132  }
133  }
134  return bytesDone;
135  }
136  CancelIo(handle);
137  throw exception_aborted();
138  }
139  size_t readOverlapped(HANDLE handle, HANDLE myEvent, t_filesize & position, void * out, size_t outBytes, abort_callback & abort) {
140  const enum {readMAX = 16*1024*1024};
141  size_t done = 0;
142  while(done < outBytes) {
143  size_t delta = outBytes - done;
144  if (delta > readMAX) delta = readMAX;
145  delta = readOverlappedPass(handle, myEvent, position, (BYTE*) out + done, (DWORD) delta, abort);
146  if (delta == 0) break;
147  done += delta;
148  position += delta;
149  }
150  return done;
151  }
152 
153  size_t readStreamOverlapped(HANDLE handle, HANDLE myEvent, void * out, size_t outBytes, abort_callback & abort) {
154  const enum {readMAX = 16*1024*1024};
155  size_t done = 0;
156  while(done < outBytes) {
157  size_t delta = outBytes - done;
158  if (delta > readMAX) delta = readMAX;
159  delta = readOverlappedPass(handle, myEvent, 0, (BYTE*) out + done, (DWORD) delta, abort);
160  if (delta == 0) break;
161  done += delta;
162  }
163  return done;
164  }
165 
166  typedef BOOL (WINAPI * pCancelSynchronousIo_t)(HANDLE hThread);
167 
168 
170  LPCTSTR lpFileName;
172  DWORD dwShareMode;
173  LPSECURITY_ATTRIBUTES lpSecurityAttributes;
178  DWORD dwErrorCode;
179  };
180 
181  static unsigned CALLBACK createFileProc(void * data) {
182  createFileData_t * cfd = (createFileData_t*)data;
183  SetLastError(0);
185  cfd->dwErrorCode = GetLastError();
186  return 0;
187  }
188 
190  abort.check();
191 
192  return CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
193 
194  // CancelSynchronousIo() doesn't fucking work. Useless.
195 #if 0
196  pCancelSynchronousIo_t pCancelSynchronousIo = (pCancelSynchronousIo_t) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "CancelSynchronousIo");
197  if (pCancelSynchronousIo == NULL) {
198 #ifdef _DEBUG
199  uDebugLog() << "Async CreateFile unavailable - using regular";
200 #endif
201  return CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
202  } else {
203 #ifdef _DEBUG
204  uDebugLog() << "Starting async CreateFile...";
205  pfc::hires_timer t; t.start();
206 #endif
208  HANDLE hThread = (HANDLE) _beginthreadex(NULL, 0, createFileProc, &data, 0, NULL);
209  HANDLE waitHandles[2] = {hThread, abort.get_abort_event()};
210  switch(WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE)) {
211  case WAIT_OBJECT_0: // succeeded
212  break;
213  case WAIT_OBJECT_0 + 1: // abort
214 #ifdef _DEBUG
215  uDebugLog() << "Aborting async CreateFile...";
216 #endif
217  pCancelSynchronousIo(hThread);
218  WaitForSingleObject(hThread, INFINITE);
219  break;
220  default:
221  uBugCheck();
222  }
223  CloseHandle(hThread);
224  SetLastError(data.dwErrorCode);
225 #ifdef _DEBUG
226  uDebugLog() << "Async CreateFile completed in " << pfc::format_time_ex(t.query(), 6) << ", status: " << (uint32_t) data.dwErrorCode;
227 #endif
228  if (abort.is_aborting()) {
229  if (data.hResult != INVALID_HANDLE_VALUE) CloseHandle(data.hResult);
230  throw exception_aborted();
231  }
232  return data.hResult;
233  }
234 #endif
235  }
236 
237 }
238 
239 #endif // _WIN32
240 
t_filesize get_size(HANDLE p_handle)
DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAll, DWORD dwMilliseconds)
Definition: pp-winapi.h:20
t_int64 t_sfilesize
Type used for file size related variables when a signed value is needed.
Definition: filesystem.h:10
static unsigned CALLBACK createFileProc(void *data)
void seek(HANDLE p_handle, t_sfilesize p_position, file::t_seek_mode p_mode)
uint64_t t_uint64
Definition: int_types.h:3
PFC_NORETURN void exception_io_from_win32(DWORD p_code)
Definition: filesystem.cpp:773
typedef BOOL(WINAPI *pPowerSetRequest_t)(__in HANDLE PowerRequest
void fillOverlapped(OVERLAPPED &ol, HANDLE myEvent, t_filesize s)
double query() const
Definition: timers.h:61
void writeOverlapped(HANDLE handle, HANDLE myEvent, t_filesize &position, const void *in, size_t inBytes, abort_callback &abort)
typedef HANDLE(WINAPI *pPowerCreateRequest_t)(__in void *Context)
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
Definition: pp-winapi.h:16
DWORD readOverlappedPass(HANDLE handle, HANDLE myEvent, t_filesize position, void *out, DWORD outBytes, abort_callback &abort)
t_uint64 t_filesize
Type used for file size related variables.
Definition: filesystem.h:8
size_t readStreamOverlapped(HANDLE handle, HANDLE myEvent, void *out, size_t outBytes, abort_callback &abort)
void start()
Definition: timers.h:58
size_t readOverlapped(HANDLE handle, HANDLE myEvent, t_filesize &position, void *out, size_t outBytes, abort_callback &abort)
HANDLE createFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile, abort_callback &abort)
BOOL(WINAPI * pCancelSynchronousIo_t)(HANDLE hThread)
PFC_NORETURN void SHARED_EXPORT uBugCheck()
void writeOverlappedPass(HANDLE handle, HANDLE myEvent, t_filesize position, const void *in, DWORD inBytes, abort_callback &abort)
uint32_t t_uint32
Definition: int_types.h:5
void writeStreamOverlapped(HANDLE handle, HANDLE myEvent, const void *in, size_t inBytes, abort_callback &abort)
int64_t t_int64
Definition: int_types.h:2