OSDN Git Service

Add classes encapsulatinglegacy USB API
authorvchtchetkine <vchtchetkine@google.com>
Tue, 28 Jul 2009 19:45:33 +0000 (12:45 -0700)
committervchtchetkine <vchtchetkine@google.com>
Tue, 28 Jul 2009 20:09:51 +0000 (13:09 -0700)
Added implementation for endpoints and overlapped I/O support for legacy API support.

host/windows/usb/api/SOURCES
host/windows/usb/api/adb_helper_routines.cpp
host/windows/usb/api/adb_helper_routines.h
host/windows/usb/api/adb_legacy_endpoint_object.cpp [new file with mode: 0755]
host/windows/usb/api/adb_legacy_endpoint_object.h [new file with mode: 0755]
host/windows/usb/api/adb_legacy_interface.cpp
host/windows/usb/api/adb_legacy_interface.h
host/windows/usb/api/adb_legacy_io_completion.cpp [new file with mode: 0755]
host/windows/usb/api/adb_legacy_io_completion.h [new file with mode: 0755]
host/windows/usb/api/adb_winusb_interface.cpp

index 4b9d360..f6e6614 100755 (executable)
@@ -88,6 +88,7 @@ PRECOMPILED_SOURCEFILE = stdafx.cpp
 SOURCES = adb_api.cpp                     \\r
           adb_endpoint_object.cpp         \\r
           adb_winusb_endpoint_object.cpp  \\r
+          adb_legacy_endpoint_object.cpp  \\r
           adb_helper_routines.cpp         \\r
           adb_interface.cpp               \\r
           adb_winusb_interface.cpp        \\r
@@ -95,6 +96,7 @@ SOURCES = adb_api.cpp                     \
           adb_interface_enum.cpp          \\r
           adb_io_completion.cpp           \\r
           adb_winusb_io_completion.cpp    \\r
+          adb_legacy_io_completion.cpp    \\r
           adb_object_handle.cpp           \\r
           AdbWinApi.cpp                   \\r
                      AdbWinApi.rc\r
index 9e37380..e45ff91 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
- * Copyright (C) 2006 The Android Open Source Project\r
+ * Copyright (C) 2009 The Android Open Source Project\r
  *\r
  * Licensed under the Apache License, Version 2.0 (the "License");\r
  * you may not use this file except in compliance with the License.\r
 #include "adb_helper_routines.h"\r
 #include "adb_interface_enum.h"\r
 \r
+bool GetSDKComplientParam(AdbOpenAccessType access_type,\r
+                          AdbOpenSharingMode sharing_mode,\r
+                          ULONG* desired_access,\r
+                          ULONG* desired_sharing) {\r
+  if (NULL != desired_access) {\r
+    switch (access_type) {\r
+      case AdbOpenAccessTypeReadWrite:\r
+        *desired_access = GENERIC_READ | GENERIC_WRITE;\r
+        break;\r
+\r
+      case AdbOpenAccessTypeRead:\r
+        *desired_access = GENERIC_READ;\r
+        break;\r
+\r
+      case AdbOpenAccessTypeWrite:\r
+        *desired_access = GENERIC_WRITE;\r
+        break;\r
+\r
+      case AdbOpenAccessTypeQueryInfo:\r
+        *desired_access = FILE_READ_ATTRIBUTES | FILE_READ_EA;\r
+        break;\r
+\r
+      default:\r
+        SetLastError(ERROR_INVALID_ACCESS);\r
+        return false;\r
+    }\r
+  }\r
+\r
+  if (NULL != desired_sharing) {\r
+    switch (sharing_mode) {\r
+      case AdbOpenSharingModeReadWrite:\r
+        *desired_sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;\r
+        break;\r
+\r
+      case AdbOpenSharingModeRead:\r
+        *desired_sharing = FILE_SHARE_READ;\r
+        break;\r
+\r
+      case AdbOpenSharingModeWrite:\r
+        *desired_sharing = FILE_SHARE_WRITE;\r
+        break;\r
+\r
+      case AdbOpenSharingModeExclusive:\r
+        *desired_sharing = 0;\r
+        break;\r
+\r
+      default:\r
+        SetLastError(ERROR_INVALID_PARAMETER);\r
+        return false;\r
+    }\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
 bool EnumerateDeviceInterfaces(HDEVINFO hardware_dev_info,\r
                                GUID class_id,\r
                                bool exclude_removed,\r
index 907e638..b6885e4 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
- * Copyright (C) 2006 The Android Open Source Project\r
+ * Copyright (C) 2009 The Android Open Source Project\r
  *\r
  * Licensed under the Apache License, Version 2.0 (the "License");\r
  * you may not use this file except in compliance with the License.\r
 \r
 #include "adb_api_private_defines.h"\r
 \r
+/** \brief Converts access type and share mode from our enum into\r
+  SDK - complient values.\r
+\r
+  @param[in] access_type Enumerated access type\r
+  @param[in] sharing_mode Enumerated share mode\r
+  @param[out] desired_access Will receive SDK - complient desired access\r
+         flags. This parameter can be NULL.\r
+  @param[out] desired_sharing Will receive SDK - complient share mode.\r
+         This parameter can be NULL.\r
+  @return True on success, false on failure, in which case GetLastError()\r
+          provides extended information about the error that occurred.\r
+*/\r
+bool GetSDKComplientParam(AdbOpenAccessType access_type,\r
+                          AdbOpenSharingMode sharing_mode,\r
+                          ULONG* desired_access,\r
+                          ULONG* desired_sharing);\r
+\r
 /** \brief Given the hardware device information enumerates interfaces for\r
   this device.\r
 \r
diff --git a/host/windows/usb/api/adb_legacy_endpoint_object.cpp b/host/windows/usb/api/adb_legacy_endpoint_object.cpp
new file mode 100755 (executable)
index 0000000..2baa53b
--- /dev/null
@@ -0,0 +1,237 @@
+/*\r
+ * Copyright (C) 2009 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/** \file\r
+  This file consists of implementation of class AdbLegacyEndpointObject that\r
+  encapsulates a handle opened to an endpoint on our device controlled by\r
+  a custom (legacy) USB driver.\r
+*/\r
+\r
+#include "stdafx.h"\r
+#include "adb_api_legacy.h"\r
+#include "adb_legacy_endpoint_object.h"\r
+#include "adb_legacy_io_completion.h"\r
+#include "adb_helper_routines.h"\r
+\r
+AdbLegacyEndpointObject::AdbLegacyEndpointObject(\r
+    AdbLegacyInterfaceObject* parent_interf,\r
+    UCHAR endpoint_id,\r
+    UCHAR endpoint_index)\r
+    : AdbEndpointObject(parent_interf, endpoint_id, endpoint_index),\r
+      usb_handle_(INVALID_HANDLE_VALUE) {\r
+}\r
+\r
+AdbLegacyEndpointObject::~AdbLegacyEndpointObject() {\r
+  if (INVALID_HANDLE_VALUE != usb_handle_) {\r
+    ::CloseHandle(usb_handle_);\r
+  }\r
+}\r
+\r
+ADBAPIHANDLE AdbLegacyEndpointObject::CommonAsyncReadWrite(\r
+    bool is_read,\r
+    void* buffer,\r
+    ULONG bytes_to_transfer,\r
+    ULONG* bytes_transferred,\r
+    HANDLE event_handle,\r
+    ULONG time_out) {\r
+  if (NULL != bytes_transferred) {\r
+    *bytes_transferred = 0;\r
+  }\r
+\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+\r
+  bool is_ioctl_write = is_read ? false : (0 != time_out);\r
+\r
+  // Create completion i/o object\r
+  AdbLegacyIOCompletion* adb_io_completion = NULL;\r
+\r
+  try {\r
+    adb_io_completion = new AdbLegacyIOCompletion(this,\r
+                                                  bytes_to_transfer,\r
+                                                  event_handle,\r
+                                                  is_ioctl_write);\r
+  } catch (... ) {\r
+    // We don't expect exceptions other than OOM thrown here.\r
+    SetLastError(ERROR_OUTOFMEMORY);\r
+    return NULL;\r
+  }\r
+\r
+  // Create a handle for it\r
+  ADBAPIHANDLE ret = adb_io_completion->CreateHandle();\r
+  ULONG transferred = 0;\r
+  if (NULL != ret) {\r
+    BOOL res = TRUE;\r
+    if (0 == time_out) {\r
+      // Go the read / write file way\r
+      res = is_read ? ReadFile(usb_handle(),\r
+                               buffer,\r
+                               bytes_to_transfer,\r
+                               &transferred,\r
+                               adb_io_completion->overlapped()) :\r
+                      WriteFile(usb_handle(),\r
+                                buffer,\r
+                                bytes_to_transfer,\r
+                                &transferred,\r
+                                adb_io_completion->overlapped());\r
+    } else {\r
+      // Go IOCTL way\r
+      AdbBulkTransfer transfer_param;\r
+      transfer_param.time_out = time_out;\r
+      transfer_param.transfer_size = is_read ? 0 : bytes_to_transfer;\r
+      transfer_param.SetWriteBuffer(is_read ? NULL : buffer);\r
+\r
+      res = DeviceIoControl(usb_handle(),\r
+        is_read ? ADB_IOCTL_BULK_READ : ADB_IOCTL_BULK_WRITE,\r
+        &transfer_param, sizeof(transfer_param),\r
+        is_read ? buffer : adb_io_completion->transferred_bytes_ptr(),\r
+        is_read ? bytes_to_transfer : sizeof(ULONG),\r
+        &transferred,\r
+        adb_io_completion->overlapped());\r
+    }\r
+\r
+    if (NULL != bytes_transferred) {\r
+      *bytes_transferred = transferred;\r
+    }\r
+\r
+    ULONG error = GetLastError();\r
+    if (!res && (ERROR_IO_PENDING != error)) {\r
+      // I/O failed immediatelly. We need to close i/o completion object\r
+      // before we return NULL to the caller.\r
+      adb_io_completion->CloseHandle();\r
+      ret = NULL;\r
+      SetLastError(error);\r
+    }\r
+  }\r
+\r
+  // Offseting 'new'\r
+  adb_io_completion->Release();\r
+\r
+  return ret;\r
+}\r
+\r
+bool AdbLegacyEndpointObject::CommonSyncReadWrite(bool is_read,\r
+                                                  void* buffer,\r
+                                                  ULONG bytes_to_transfer,\r
+                                                  ULONG* bytes_transferred,\r
+                                                  ULONG time_out) {\r
+  if (NULL != bytes_transferred) {\r
+    *bytes_transferred = 0;\r
+  }\r
+\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+\r
+  bool is_ioctl_write = is_read ? false : (0 != time_out);\r
+\r
+  // This is synchronous I/O. Since we always open I/O items for\r
+  // overlapped I/O we're obligated to always provide OVERLAPPED\r
+  // structure to read / write routines. Prepare it now.\r
+  OVERLAPPED overlapped;\r
+  ZeroMemory(&overlapped, sizeof(overlapped));\r
+\r
+  BOOL ret = TRUE;\r
+  ULONG ioctl_write_transferred = 0;\r
+  if (0 == time_out) {\r
+    // Go the read / write file way\r
+    ret = is_read ?\r
+      ReadFile(usb_handle(), buffer, bytes_to_transfer, bytes_transferred, &overlapped) :\r
+      WriteFile(usb_handle(), buffer, bytes_to_transfer, bytes_transferred, &overlapped);\r
+  } else {\r
+    // Go IOCTL way\r
+    AdbBulkTransfer transfer_param;\r
+    transfer_param.time_out = time_out;\r
+    transfer_param.transfer_size = is_read ? 0 : bytes_to_transfer;\r
+    transfer_param.SetWriteBuffer(is_read ? NULL : buffer);\r
+\r
+    ULONG tmp;\r
+    ret = DeviceIoControl(usb_handle(),\r
+      is_read ? ADB_IOCTL_BULK_READ : ADB_IOCTL_BULK_WRITE,\r
+      &transfer_param, sizeof(transfer_param),\r
+      is_read ? buffer : &ioctl_write_transferred,\r
+      is_read ? bytes_to_transfer : sizeof(ULONG),\r
+      &tmp,\r
+      &overlapped);\r
+  }\r
+\r
+  // Lets see the result\r
+  if (!ret && (ERROR_IO_PENDING != GetLastError())) {\r
+    // I/O failed.\r
+    return false;\r
+  }\r
+\r
+  // Lets wait till I/O completes\r
+  ULONG transferred = 0;\r
+  ret = GetOverlappedResult(usb_handle(), &overlapped, &transferred, TRUE);\r
+  if (ret && (NULL != bytes_transferred)) {\r
+    *bytes_transferred = is_ioctl_write ? ioctl_write_transferred :\r
+                                          transferred;\r
+  }\r
+\r
+  return ret ? true : false;\r
+}\r
+\r
+ADBAPIHANDLE AdbLegacyEndpointObject::CreateHandle(\r
+    const wchar_t* item_path,\r
+    AdbOpenAccessType access_type,\r
+    AdbOpenSharingMode share_mode) {\r
+  // Convert access / share parameters into CreateFile - compatible\r
+  ULONG desired_access;\r
+  ULONG desired_sharing;\r
+\r
+  if (!GetSDKComplientParam(access_type, share_mode,\r
+                            &desired_access, &desired_sharing)) {\r
+    return NULL;\r
+  }\r
+\r
+  // Open USB handle\r
+  usb_handle_ = CreateFile(item_path,\r
+                           desired_access,\r
+                           share_mode,\r
+                           NULL,\r
+                           OPEN_EXISTING,\r
+                           FILE_FLAG_OVERLAPPED,  // Always overlapped!\r
+                           NULL);\r
+  if (INVALID_HANDLE_VALUE == usb_handle_) {\r
+    return NULL;\r
+  }\r
+\r
+  // Create ADB handle\r
+  ADBAPIHANDLE ret = AdbObjectHandle::CreateHandle();\r
+\r
+  if (NULL == ret) {\r
+    // If creation of ADB handle failed we have to close USB handle too.\r
+    ULONG error = GetLastError();\r
+    ::CloseHandle(usb_handle());\r
+    usb_handle_ = INVALID_HANDLE_VALUE;\r
+    SetLastError(error);\r
+  }\r
+\r
+  return ret;\r
+}\r
+\r
+bool AdbLegacyEndpointObject::CloseHandle() {\r
+  if (INVALID_HANDLE_VALUE != usb_handle_) {\r
+    ::CloseHandle(usb_handle_);\r
+    usb_handle_ = INVALID_HANDLE_VALUE;\r
+  }\r
+\r
+  return AdbEndpointObject::CloseHandle();\r
+}\r
diff --git a/host/windows/usb/api/adb_legacy_endpoint_object.h b/host/windows/usb/api/adb_legacy_endpoint_object.h
new file mode 100755 (executable)
index 0000000..a8613d2
--- /dev/null
@@ -0,0 +1,142 @@
+/*\r
+ * Copyright (C) 2009 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef ANDROID_USB_API_ADB_LEGACY_ENDPOINT_OBJECT_H__\r
+#define ANDROID_USB_API_ADB_LEGACY_ENDPOINT_OBJECT_H__\r
+/** \file\r
+  This file consists of declaration of class AdbLegacyEndpointObject that\r
+  encapsulates a handle opened to an endpoint on our device controlled by\r
+  a custom (legacy) USB driver.\r
+*/\r
+\r
+#include "adb_endpoint_object.h"\r
+#include "adb_legacy_interface.h"\r
+\r
+/** Encapsulates a handle opened to an endpoint on our device controlled by\r
+  a custom (legacy) USB driver.\r
+*/\r
+class AdbLegacyEndpointObject : public AdbEndpointObject {\r
+ public:\r
+  /** \brief Constructs the object\r
+\r
+    @param[in] interface Parent legacy USB interface for this object.\r
+    @param[in] endpoint_id Endpoint ID (endpoint address) on the device.\r
+    @param[in] endpoint_index Zero-based endpoint index in the interface's\r
+          array of endpoints.\r
+  */\r
+  AdbLegacyEndpointObject(AdbLegacyInterfaceObject* parent_interf,\r
+                          UCHAR endpoint_id,\r
+                          UCHAR endpoint_index);\r
+\r
+ protected:\r
+  /** \brief Destructs the object.\r
+\r
+    We hide destructor in order to prevent ourseves from accidentaly allocating\r
+    instances on the stack. If such attemp occur, compiler will error.\r
+  */\r
+  virtual ~AdbLegacyEndpointObject();\r
+\r
+  //\r
+  // Abstract overrides\r
+  //\r
+\r
+ protected:\r
+  /** \brief Common code for async read / write\r
+\r
+    @param[in] is_read Read or write selector.\r
+    @param[in,out] buffer Pointer to the buffer for read / write.\r
+    @param[in] bytes_to_transfer Number of bytes to be read / written.\r
+    @param[out] bytes_transferred Number of bytes read / written. Can be NULL.\r
+    @param[in] event_handle Event handle that should be signaled when async I/O\r
+           completes. Can be NULL. If it's not NULL this handle will be used to\r
+           initialize OVERLAPPED structure for this I/O.\r
+    @param[in] time_out A timeout (in milliseconds) required for this I/O to\r
+           complete. Zero value in this parameter means that there is no\r
+           timeout set for this I/O.\r
+    @return A handle to IO completion object or NULL on failure. If NULL is\r
+            returned GetLastError() provides extended error information.\r
+  */\r
+  virtual ADBAPIHANDLE CommonAsyncReadWrite(bool is_read,\r
+                                            void* buffer,\r
+                                            ULONG bytes_to_transfer,\r
+                                            ULONG* bytes_transferred,\r
+                                            HANDLE event_handle,\r
+                                            ULONG time_out);\r
+\r
+  /** \brief Common code for sync read / write\r
+\r
+    @param[in] is_read Read or write selector.\r
+    @param[in,out] buffer Pointer to the buffer for read / write.\r
+    @param[in] bytes_to_transfer Number of bytes to be read / written.\r
+    @param[out] bytes_transferred Number of bytes read / written. Can be NULL.\r
+    @param[in] time_out A timeout (in milliseconds) required for this I/O to\r
+           complete. Zero value in this parameter means that there is no\r
+           timeout set for this I/O.\r
+    @return true on success, false on failure. If false is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  virtual bool CommonSyncReadWrite(bool is_read,\r
+                                   void* buffer,\r
+                                   ULONG bytes_to_transfer,\r
+                                   ULONG* bytes_transferred,\r
+                                   ULONG time_out);\r
+\r
+  //\r
+  // Operations\r
+  //\r
+\r
+ public:\r
+  /** \brief Opens endpoint and creates a handle to this object\r
+\r
+    @param item_path[in] Path to the endpoint on our USB device.\r
+    @param access_type[in] Desired access type. In the current implementation\r
+          this parameter has no effect on the way item is opened. It's\r
+          always read / write access.\r
+    @param sharing_mode[in] Desired share mode. In the current implementation\r
+          this parameter has no effect on the way item is opened. It's\r
+          always shared for read / write.\r
+    @return A handle to this object on success or NULL on an error.\r
+            If NULL is returned GetLastError() provides extended error\r
+            information. ERROR_GEN_FAILURE is set if an attempt was\r
+            made to create already opened object.\r
+  */\r
+  virtual ADBAPIHANDLE CreateHandle(const wchar_t* item_path,\r
+                                    AdbOpenAccessType access_type,\r
+                                    AdbOpenSharingMode share_mode);\r
+\r
+\r
+  /** \brief This method is called when handle to this object gets closed.\r
+\r
+    We override this method in order to close handle to the endpoint opened\r
+    in CreateHandle method of this class.\r
+    @return true on success or false if object is already closed. If\r
+            false is returned GetLastError() provides extended error\r
+            information.\r
+  */\r
+  virtual bool CloseHandle();\r
+\r
+ public:\r
+  /// Gets handle to the endpoint opened on our USB device.\r
+  HANDLE usb_handle() const {\r
+    return usb_handle_;\r
+  }\r
+\r
+ protected:\r
+  /// Handle to the endpoint opened on our USB device.\r
+  HANDLE              usb_handle_;\r
+};\r
+\r
+#endif  // ANDROID_USB_API_ADB_LEGACY_ENDPOINT_OBJECT_H__\r
index 95c750e..9eab9bd 100755 (executable)
 /** \file\r
   This file consists of implementation of class AdbLegacyInterfaceObject\r
   that encapsulates an interface on our USB device that is accessible\r
-  via WinUsb API.\r
 */\r
 \r
 #include "stdafx.h"\r
+#include "adb_api_legacy.h"\r
 #include "adb_legacy_interface.h"\r
-#include "adb_endpoint_object.h"\r
+#include "adb_legacy_endpoint_object.h"\r
 \r
 AdbLegacyInterfaceObject::AdbLegacyInterfaceObject(const wchar_t* interf_name)\r
-  : AdbInterfaceObject(interf_name) {\r
+    : AdbInterfaceObject(interf_name),\r
+      def_read_endpoint_(0xFF),\r
+      read_endpoint_id_(0xFF),\r
+      def_write_endpoint_(0xFF),\r
+      write_endpoint_id_(0xFF) {\r
 }\r
 \r
 AdbLegacyInterfaceObject::~AdbLegacyInterfaceObject() {\r
 }\r
 \r
 ADBAPIHANDLE AdbLegacyInterfaceObject::CreateHandle() {\r
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);\r
-  return NULL;\r
-}\r
+  // Open USB device for this intefface\r
+  HANDLE usb_device_handle = CreateFile(interface_name().c_str(),\r
+                                        GENERIC_READ | GENERIC_WRITE,\r
+                                        FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+                                        NULL,\r
+                                        OPEN_EXISTING,\r
+                                        0,\r
+                                        NULL);\r
+  if (INVALID_HANDLE_VALUE == usb_device_handle) {\r
+    return NULL;\r
+  }\r
+\r
+  // Now, we ensured that our usb device / interface is up and running.\r
+  // Lets collect device, interface and pipe information\r
+  bool ok = true;\r
+  if (!CacheUsbDeviceDescriptor(usb_device_handle) ||\r
+      !CacheUsbConfigurationDescriptor(usb_device_handle) ||\r
+      !CacheUsbInterfaceDescriptor(usb_device_handle)) {\r
+    ok = false;\r
+  }\r
+\r
+  // Preserve error accross handle close\r
+  ULONG error = ok ? NO_ERROR : GetLastError();\r
+\r
+  ::CloseHandle(usb_device_handle);\r
+\r
+  if (NO_ERROR != error) {\r
+    SetLastError(error);\r
+  }\r
+\r
+  if (!ok) {\r
+    return false;\r
+  }\r
 \r
-bool AdbLegacyInterfaceObject::CloseHandle() {\r
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);\r
-  return false;\r
+  // Save indexes and IDs for bulk read / write endpoints. We will use them to\r
+  // convert ADB_QUERY_BULK_WRITE_ENDPOINT_INDEX and\r
+  // ADB_QUERY_BULK_READ_ENDPOINT_INDEX into actual endpoint indexes and IDs.\r
+  for (UCHAR endpoint = 0; endpoint < usb_interface_descriptor_.bNumEndpoints;\r
+       endpoint++) {\r
+    // Get endpoint information\r
+    AdbEndpointInformation pipe_info;\r
+    if (!GetEndpointInformation(endpoint, &pipe_info)) {\r
+      return false;\r
+    }\r
+\r
+    if (AdbEndpointTypeBulk == pipe_info.endpoint_type) {\r
+      // This is a bulk endpoint. Cache its index and ID.\r
+      if (0 != (pipe_info.endpoint_address & USB_ENDPOINT_DIRECTION_MASK)) {\r
+        // Use this endpoint as default bulk read endpoint\r
+        ATLASSERT(0xFF == def_read_endpoint_);\r
+        def_read_endpoint_ = endpoint;\r
+        read_endpoint_id_ = pipe_info.endpoint_address;\r
+      } else {\r
+        // Use this endpoint as default bulk write endpoint\r
+        ATLASSERT(0xFF == def_write_endpoint_);\r
+        def_write_endpoint_ = endpoint;\r
+        write_endpoint_id_ = pipe_info.endpoint_address;\r
+      }\r
+    }\r
+  }\r
+\r
+  return AdbObjectHandle::CreateHandle();\r
 }\r
 \r
 bool AdbLegacyInterfaceObject::GetSerialNumber(void* buffer,\r
                                                unsigned long* buffer_char_size,\r
                                                bool ansi) {\r
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);\r
-  return false;\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+\r
+  // Open USB device for this intefface\r
+  HANDLE usb_device_handle = CreateFile(interface_name().c_str(),\r
+                                        GENERIC_READ,\r
+                                        FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+                                        NULL,\r
+                                        OPEN_EXISTING,\r
+                                        0,\r
+                                        NULL);\r
+  if (INVALID_HANDLE_VALUE == usb_device_handle) {\r
+    return NULL;\r
+  }\r
+\r
+  WCHAR serial_number[512];\r
+\r
+  // Send IOCTL\r
+  DWORD ret_bytes = 0;\r
+  BOOL ret = DeviceIoControl(usb_device_handle,\r
+                             ADB_IOCTL_GET_SERIAL_NUMBER,\r
+                             NULL, 0,\r
+                             serial_number, sizeof(serial_number),\r
+                             &ret_bytes,\r
+                             NULL);\r
+\r
+  // Preserve error accross CloseHandle\r
+  ULONG error = ret ? NO_ERROR : GetLastError();\r
+\r
+  ::CloseHandle(usb_device_handle);\r
+\r
+  if (NO_ERROR != error) {\r
+    SetLastError(error);\r
+    return false;\r
+  }\r
+\r
+  unsigned long str_len =\r
+    static_cast<unsigned long>(wcslen(serial_number) + 1);\r
+\r
+  if ((NULL == buffer) || (*buffer_char_size < str_len)) {\r
+    *buffer_char_size = str_len;\r
+    SetLastError(ERROR_INSUFFICIENT_BUFFER);\r
+    return false;\r
+  }\r
+\r
+  if (!ansi) {\r
+    // If user asked for wide char name just return it\r
+    wcscpy(reinterpret_cast<wchar_t*>(buffer), serial_number);\r
+    return true;\r
+  }\r
+\r
+  // We need to convert name from wide char to ansi string\r
+  int res = WideCharToMultiByte(CP_ACP,\r
+                                0,\r
+                                serial_number,\r
+                                static_cast<int>(str_len),\r
+                                reinterpret_cast<PSTR>(buffer),\r
+                                static_cast<int>(*buffer_char_size),\r
+                                NULL,\r
+                                NULL);\r
+  return (res != 0);\r
 }\r
 \r
 bool AdbLegacyInterfaceObject::GetEndpointInformation(\r
     UCHAR endpoint_index,\r
     AdbEndpointInformation* info) {\r
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);\r
-  return false;\r
+  // Open USB device for this intefface\r
+  HANDLE usb_device_handle = CreateFile(interface_name().c_str(),\r
+                                        GENERIC_READ,\r
+                                        FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+                                        NULL,\r
+                                        OPEN_EXISTING,\r
+                                        0,\r
+                                        NULL);\r
+  if (INVALID_HANDLE_VALUE == usb_device_handle) {\r
+    return NULL;\r
+  }\r
+\r
+  // Init ICTL param\r
+  AdbQueryEndpointInformation param;\r
+  param.endpoint_index = endpoint_index;\r
+\r
+  // Send IOCTL\r
+  DWORD ret_bytes = 0;\r
+  BOOL ret = DeviceIoControl(usb_device_handle,\r
+                             ADB_IOCTL_GET_ENDPOINT_INFORMATION,\r
+                             &param, sizeof(param),\r
+                             info, sizeof(AdbEndpointInformation),\r
+                             &ret_bytes,\r
+                             NULL);\r
+  ATLASSERT(!ret || (sizeof(AdbEndpointInformation) == ret_bytes));\r
+\r
+  // Preserve error accross CloseHandle\r
+  ULONG error = ret ? NO_ERROR : GetLastError();\r
+\r
+  ::CloseHandle(usb_device_handle);\r
+\r
+  if (NO_ERROR != error) {\r
+    SetLastError(error);\r
+  }\r
+\r
+  return ret ? true : false;\r
 }\r
 \r
 ADBAPIHANDLE AdbLegacyInterfaceObject::OpenEndpoint(\r
     UCHAR endpoint_index,\r
     AdbOpenAccessType access_type,\r
     AdbOpenSharingMode sharing_mode) {\r
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);\r
-  return NULL;\r
+  // Convert index into name and ID.\r
+  std::wstring endpoint_name;\r
+  UCHAR endpoint_id;\r
+\r
+  try {\r
+    if ((ADB_QUERY_BULK_READ_ENDPOINT_INDEX == endpoint_index) ||\r
+        (def_read_endpoint_ == endpoint_index)) {\r
+      endpoint_name = DEVICE_BULK_READ_PIPE_NAME;\r
+      endpoint_id = read_endpoint_id_;\r
+      endpoint_index = def_read_endpoint_;\r
+    } else if ((ADB_QUERY_BULK_WRITE_ENDPOINT_INDEX == endpoint_index) ||\r
+               (def_write_endpoint_ == endpoint_index)) {\r
+      endpoint_name = DEVICE_BULK_WRITE_PIPE_NAME;\r
+      endpoint_id = write_endpoint_id_;\r
+      endpoint_index = def_write_endpoint_;\r
+    } else {\r
+      SetLastError(ERROR_INVALID_PARAMETER);\r
+      return false;\r
+    }\r
+  } catch (...) {\r
+    // We don't expect exceptions other than OOM thrown here.\r
+    SetLastError(ERROR_OUTOFMEMORY);\r
+    return NULL;\r
+  }\r
+\r
+  return OpenEndpoint(endpoint_name.c_str(), endpoint_id, endpoint_index,\r
+                      access_type, sharing_mode);\r
+}\r
+\r
+ADBAPIHANDLE AdbLegacyInterfaceObject::OpenEndpoint(\r
+    const wchar_t* endpoint_name,\r
+    UCHAR endpoint_id,\r
+    UCHAR endpoint_index,\r
+    AdbOpenAccessType access_type,\r
+    AdbOpenSharingMode sharing_mode) {\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+\r
+  AdbLegacyEndpointObject* adb_endpoint = NULL;\r
+\r
+  try {\r
+    adb_endpoint =\r
+        new AdbLegacyEndpointObject(this, endpoint_id, endpoint_index);\r
+  } catch (...) {\r
+    // We don't expect exceptions other than OOM thrown here.\r
+    SetLastError(ERROR_OUTOFMEMORY);\r
+    return NULL;\r
+  }\r
+\r
+  // Build full path to the object\r
+  std::wstring endpoint_path = interface_name();\r
+  endpoint_path += L"\\";\r
+  endpoint_path += endpoint_name;\r
+\r
+  ADBAPIHANDLE ret = adb_endpoint->CreateHandle(endpoint_path.c_str(),\r
+                                                access_type,\r
+                                                sharing_mode);\r
+\r
+  adb_endpoint->Release();\r
+\r
+  return ret;\r
+}\r
+\r
+bool AdbLegacyInterfaceObject::CacheUsbDeviceDescriptor(\r
+    HANDLE usb_device_handle) {\r
+  DWORD ret_bytes = 0;\r
+  BOOL ret = DeviceIoControl(usb_device_handle,\r
+                             ADB_IOCTL_GET_USB_DEVICE_DESCRIPTOR,\r
+                             NULL, 0,\r
+                             &usb_device_descriptor_,\r
+                             sizeof(usb_device_descriptor_),\r
+                             &ret_bytes,\r
+                             NULL);\r
+  ATLASSERT(!ret || (sizeof(USB_DEVICE_DESCRIPTOR) == ret_bytes));\r
+\r
+  return ret ? true : false;\r
+}\r
+\r
+bool AdbLegacyInterfaceObject::CacheUsbConfigurationDescriptor(\r
+    HANDLE usb_device_handle) {\r
+  DWORD ret_bytes = 0;\r
+  BOOL ret = DeviceIoControl(usb_device_handle,\r
+                             ADB_IOCTL_GET_USB_CONFIGURATION_DESCRIPTOR,\r
+                             NULL, 0,\r
+                             &usb_config_descriptor_,\r
+                             sizeof(usb_config_descriptor_),\r
+                             &ret_bytes,\r
+                             NULL);\r
+  ATLASSERT(!ret || (sizeof(USB_CONFIGURATION_DESCRIPTOR) == ret_bytes));\r
+\r
+  return ret ? true : false;\r
+}\r
+\r
+bool AdbLegacyInterfaceObject::CacheUsbInterfaceDescriptor(\r
+    HANDLE usb_device_handle) {\r
+  DWORD ret_bytes = 0;\r
+  BOOL ret = DeviceIoControl(usb_device_handle,\r
+                             ADB_IOCTL_GET_USB_INTERFACE_DESCRIPTOR,\r
+                             NULL, 0,\r
+                             &usb_interface_descriptor_,\r
+                             sizeof(usb_interface_descriptor_),\r
+                             &ret_bytes,\r
+                             NULL);\r
+  ATLASSERT(!ret || (sizeof(USB_INTERFACE_DESCRIPTOR) == ret_bytes));\r
+\r
+  return ret ? true : false;\r
 }\r
index 6d4b0e8..8dd0b22 100755 (executable)
@@ -60,15 +60,6 @@ class AdbLegacyInterfaceObject : public AdbInterfaceObject {
   */\r
   virtual ADBAPIHANDLE CreateHandle();\r
 \r
-  /** \brief This method is called when handle to this object gets closed.\r
-\r
-    In this call object is deleted from the AdbObjectHandleMap.\r
-    @return true on success or false if object is already closed. If\r
-            false is returned GetLastError() provides extended error\r
-            information.\r
-  */\r
-  virtual bool CloseHandle();\r
-\r
   //\r
   // Abstract overrides\r
   //\r
@@ -124,6 +115,76 @@ class AdbLegacyInterfaceObject : public AdbInterfaceObject {
   virtual ADBAPIHANDLE OpenEndpoint(UCHAR endpoint_index,\r
                                     AdbOpenAccessType access_type,\r
                                     AdbOpenSharingMode sharing_mode);\r
+\r
+  //\r
+  // Internal operations\r
+  //\r
+\r
+ protected:\r
+  /** \brief Opens an endpoint on this interface.\r
+\r
+    @param[in] endpoint_name Endpoint file name.\r
+    @param[in] endpoint_id Endpoint (pipe) address on the device.\r
+    @param[in] endpoint_index Zero-based endpoint index.\r
+    @param[in] access_type Desired access type. In the current implementation\r
+           this parameter has no effect on the way endpoint is opened. It's\r
+           always read / write access.\r
+    @param[in] sharing_mode Desired share mode. In the current implementation\r
+           this parameter has no effect on the way endpoint is opened. It's\r
+           always shared for read / write.\r
+    @return Handle to the opened endpoint object or NULL on failure.\r
+            If NULL is returned GetLastError() provides extended information\r
+            about the error that occurred.\r
+  */\r
+  ADBAPIHANDLE OpenEndpoint(const wchar_t* endpoint_name,\r
+                            UCHAR endpoint_id,\r
+                            UCHAR endpoint_index,\r
+                            AdbOpenAccessType access_type,\r
+                            AdbOpenSharingMode sharing_mode);\r
+\r
+  /** \brief Caches device descriptor for the USB device associated with\r
+    this interface.\r
+\r
+    This method is called from CreateHandle method to cache some interface\r
+    information.\r
+    @param[in] usb_device_handle Handle to USB device.\r
+    @return 'true' on success, 'false' on failure. If 'false' is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  bool CacheUsbDeviceDescriptor(HANDLE usb_device_handle);\r
+\r
+  /** \brief Caches descriptor for the selected USB device configuration.\r
+\r
+    This method is called from CreateHandle method to cache some interface\r
+    information.\r
+    @param[in] usb_device_handle Handle to USB device.\r
+    @return 'true' on success, 'false' on failure. If 'false' is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  bool CacheUsbConfigurationDescriptor(HANDLE usb_device_handle);\r
+\r
+  /** \brief Caches descriptor for this interface.\r
+\r
+    This method is called from CreateHandle method to cache some interface\r
+    information.\r
+    @param[in] usb_device_handle Handle to USB device.\r
+    @return 'true' on success, 'false' on failure. If 'false' is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  bool CacheUsbInterfaceDescriptor(HANDLE usb_device_handle);\r
+\r
+ protected:\r
+  /// Index for the default bulk read endpoint\r
+  UCHAR                         def_read_endpoint_;\r
+\r
+  /// ID for the default bulk read endpoint\r
+  UCHAR                         read_endpoint_id_;\r
+\r
+  /// Index for the default bulk write endpoint\r
+  UCHAR                         def_write_endpoint_;\r
+\r
+  /// ID for the default bulk write endpoint\r
+  UCHAR                         write_endpoint_id_;\r
 };\r
 \r
 #endif  // ANDROID_USB_API_ADB_LEGACY_INTERFACE_H__\r
diff --git a/host/windows/usb/api/adb_legacy_io_completion.cpp b/host/windows/usb/api/adb_legacy_io_completion.cpp
new file mode 100755 (executable)
index 0000000..e3d1498
--- /dev/null
@@ -0,0 +1,90 @@
+/*\r
+ * Copyright (C) 2009 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/** \file\r
+  This file consists of implementation of class AdbLegacyIOCompletion that\r
+  encapsulates a wrapper around OVERLAPPED Win32 structure returned from\r
+  asynchronous I/O requests issued via legacy USB API.\r
+*/\r
+\r
+#include "stdafx.h"\r
+#include "adb_legacy_io_completion.h"\r
+\r
+AdbLegacyIOCompletion::AdbLegacyIOCompletion(\r
+    AdbLegacyEndpointObject* parent_io_obj,\r
+    ULONG expected_trans_size,\r
+    HANDLE event_hndl,\r
+    bool is_write_ctl)\r
+    : AdbIOCompletion(parent_io_obj, expected_trans_size, event_hndl),\r
+      transferred_bytes_(0),\r
+      is_write_ioctl_(is_write_ctl) {\r
+}\r
+\r
+AdbLegacyIOCompletion::~AdbLegacyIOCompletion() {\r
+}\r
+\r
+bool AdbLegacyIOCompletion::GetOvelappedIoResult(LPOVERLAPPED ovl_data,\r
+                                                 ULONG* bytes_transferred,\r
+                                                 bool wait) {\r
+  if (NULL != bytes_transferred) {\r
+    *bytes_transferred = 0;\r
+  }\r
+\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+\r
+  ULONG transfer;\r
+  bool ret = GetOverlappedResult(parent_legacy_io_object()->usb_handle(),\r
+                                 overlapped(),\r
+                                 &transfer,\r
+                                 wait) ? true :\r
+                                         false;\r
+\r
+  // TODO: This is bizzare but I've seen it happening\r
+  // that GetOverlappedResult with wait set to true returns "prematurely",\r
+  // with wrong transferred bytes value and GetLastError reporting\r
+  // ERROR_IO_PENDING. So, lets give it an up to a 20 ms loop!\r
+  ULONG error = GetLastError();\r
+\r
+  if (wait && ret && (0 == transfer) && (0 != expected_transfer_size_) &&\r
+      ((ERROR_IO_INCOMPLETE == error) || (ERROR_IO_PENDING == error))) {\r
+    for (int trying = 0; trying < 10; trying++) {\r
+      Sleep(2);\r
+      ret = GetOverlappedResult(parent_legacy_io_object()->usb_handle(),\r
+                                overlapped(),\r
+                                &transfer,\r
+                                wait) ? true :\r
+                                        false;\r
+      error = GetLastError();\r
+      if (!ret || (0 != transfer) ||\r
+          ((ERROR_IO_INCOMPLETE != error) && (ERROR_IO_PENDING != error))) {\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (NULL != ovl_data) {\r
+    CopyMemory(ovl_data, overlapped(), sizeof(OVERLAPPED));\r
+  }\r
+\r
+  if (NULL != bytes_transferred) {\r
+    *bytes_transferred = is_write_ioctl() ? transferred_bytes_ : transfer;\r
+  }\r
+\r
+  return ret;\r
+}\r
diff --git a/host/windows/usb/api/adb_legacy_io_completion.h b/host/windows/usb/api/adb_legacy_io_completion.h
new file mode 100755 (executable)
index 0000000..743219e
--- /dev/null
@@ -0,0 +1,115 @@
+/*\r
+ * Copyright (C) 2009 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef ANDROID_USB_API_ADB_LEGACY_IO_COMPLETION_H__\r
+#define ANDROID_USB_API_ADB_LEGACY_IO_COMPLETION_H__\r
+/** \file\r
+  This file consists of declaration of class AdbLegacyIOCompletion that\r
+  encapsulates a wrapper around OVERLAPPED Win32 structure returned from\r
+  asynchronous I/O requests issued via legacy USB API.\r
+*/\r
+\r
+#include "adb_io_completion.h"\r
+#include "adb_legacy_endpoint_object.h"\r
+\r
+/** \brief Encapsulates a wrapper around OVERLAPPED Win32 structure returned\r
+  from asynchronous I/O requests issued via legacy USB API.\r
+\r
+  A handle to this object is returned to the caller of each successful\r
+  asynchronous I/O request. Just like all other handles this handle\r
+  must be closed after it's no longer needed.\r
+*/\r
+class AdbLegacyIOCompletion : public AdbIOCompletion {\r
+ public:\r
+  /** \brief Constructs the object.\r
+\r
+    @param[in] parent_io_obj Parent legacy endpoint that created this\r
+           instance.\r
+    @param[in] expected_trans_size Number of bytes expected to be transferred\r
+          with the I/O.\r
+    @param[in] event_hndl Event handle that should be signaled when I/O\r
+           completes. Can be NULL. If it's not NULL this handle will be\r
+           used to initialize OVERLAPPED structure for this object.\r
+    @param[in] is_write_ctl Flag indicating whether or not this completion\r
+           object is created for ADB_IOCTL_BULK_WRITE I/O.\r
+  */\r
+  AdbLegacyIOCompletion(AdbLegacyEndpointObject* parent_io_obj,\r
+                        ULONG expected_trans_size,\r
+                        HANDLE event_hndl,\r
+                        bool is_write_ctl);\r
+\r
+ protected:\r
+  /** \brief Destructs the object.\r
+\r
+    We hide destructor in order to prevent ourseves from accidentaly allocating\r
+    instances on the stack. If such attemp occur, compiler will error.\r
+  */\r
+  virtual ~AdbLegacyIOCompletion();\r
+\r
+  //\r
+  // Abstract overrides\r
+  //\r
+\r
+ public:\r
+  /** \brief Gets overlapped I/O result\r
+\r
+    This method uses GetOverlappedResult to get results of the overlapped I/O\r
+    operation.\r
+    @param[out] ovl_data Buffer for the copy of this object's OVERLAPPED\r
+           structure. Can be NULL.\r
+    @param[out] bytes_transferred Pointer to a variable that receives the\r
+           number of bytes that were actually transferred by a read or write\r
+           operation. See SDK doc on GetOvelappedResult for more information.\r
+           Unlike regular GetOvelappedResult call this parameter can be NULL.\r
+    @param[in] wait If this parameter is true, the method does not return\r
+           until the operation has been completed. If this parameter is false\r
+           and the operation is still pending, the method returns false and\r
+           the GetLastError function returns ERROR_IO_INCOMPLETE.\r
+    @return true if I/O has been completed or false on failure or if request\r
+           is not yet completed. If false is returned GetLastError() provides\r
+           extended error information. If GetLastError returns\r
+           ERROR_IO_INCOMPLETE it means that I/O is not yet completed.\r
+  */\r
+  virtual bool GetOvelappedIoResult(LPOVERLAPPED ovl_data,\r
+                                    ULONG* bytes_transferred,\r
+                                    bool wait);\r
+\r
+ public:\r
+  /// Gets parent legacy endpoint.\r
+  AdbLegacyEndpointObject* parent_legacy_io_object() const {\r
+    return reinterpret_cast<AdbLegacyEndpointObject*>(parent_io_object());\r
+  }\r
+\r
+  /// Gets write IOCTL flag.\r
+  bool is_write_ioctl() const {\r
+    return is_write_ioctl_;\r
+  }\r
+\r
+  /// Gets address for ADB_IOCTL_BULK_WRITE output buffer.\r
+  ULONG* transferred_bytes_ptr() {\r
+    ATLASSERT(is_write_ioctl());\r
+    return &transferred_bytes_;\r
+  }\r
+\r
+ protected:\r
+  /// Recepient for number of transferred bytes in write IOCTL.\r
+  ULONG         transferred_bytes_;\r
+\r
+  /// Write IOCTL flag.\r
+  bool          is_write_ioctl_;\r
+};\r
+\r
+#endif  // ANDROID_USB_API_ADB_LEGACY_IO_COMPLETION_H__\r
index 00e575d..d09c1cb 100755 (executable)
@@ -305,7 +305,7 @@ ADBAPIHANDLE AdbWinUsbInterfaceObject::OpenEndpoint(
 }\r
 \r
 ADBAPIHANDLE AdbWinUsbInterfaceObject::OpenEndpoint(UCHAR endpoint_id,\r
-                                              UCHAR endpoint_index) {\r
+                                                    UCHAR endpoint_index) {\r
   if (!IsOpened()) {\r
     SetLastError(ERROR_INVALID_HANDLE);\r
     return false;\r