/// <summary>
        /// Callback for event from device
        /// </summary>
        /// <param name="pEventParameters"></param>
        public void OnEvent(IPortableDeviceValues pEventParameters)
        {
            string pnpDeviceId;
              pEventParameters.GetStringValue(ref PortableDevicePKeys.WPD_EVENT_PARAMETER_PNP_DEVICE_ID, out pnpDeviceId);
              if (this.device.DeviceId != pnpDeviceId)
            return;

              Guid eventGuid;
              pEventParameters.GetGuidValue(ref PortableDevicePKeys.WPD_EVENT_PARAMETER_EVENT_ID, out eventGuid);

              PortableDeviceEventType deviceEventType = new PortableDeviceEventType() {EventGuid = eventGuid};

              if (eventGuid == PortableDeviceGuids.WPD_EVENT_OBJECT_ADDED)
              {
            string objectId;
            pEventParameters.GetStringValue(ref PortableDevicePKeys.WPD_OBJECT_ID, out objectId);
            string objectName;
            pEventParameters.GetStringValue(ref PortableDevicePKeys.WPD_OBJECT_NAME, out objectName);
            PortableDeviceObject deviceObject = new PortableDeviceObject(objectId) {Name = objectName};
            deviceEventType.DeviceObject = deviceObject;
              }

              // the original api isn't finise, i use a siple workaroud, but this need to be fixed using event factory
              //this.device.RaiseEvent(PortableDeviceEventTypeFactory.Instance.CreateEventType(eventGuid));
              this.device.RaiseEvent(deviceEventType);
        }
 /// <summary>
 /// Add a child in collection
 /// </summary>
 /// <param name="child"></param>
 internal void AddChild(PortableDeviceObject child)
 {
     if (this.childs.Contains(child))
     {
         return;
     }
     this.childs.Add(child);
 }
 /// <summary>
 /// Add a child in collection
 /// </summary>
 /// <param name="child"></param>
 internal void AddChild(PortableDeviceObject child)
 {
     if (this.childs.Contains(child))
         return;
     this.childs.Add(child);
 }
        //view-source:http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_26860397.html

        //public void StartLiveView()
        //{
        //  IPortableDeviceValues commandValues = (IPortableDeviceValues)new PortableDeviceTypesLib.PortableDeviceValuesClass();
        //  IPortableDevicePropVariantCollection propVariant =
        //    (IPortableDevicePropVariantCollection)new PortableDeviceTypesLib.PortableDevicePropVariantCollection();
        //  IPortableDeviceValues results;

        //  //commandValues.SetGuidValue(ref PortableDevicePKeys.WPD_PROPERTY_COMMON_COMMAND_CATEGORY, ref command.fmtid);
        //  commandValues.SetGuidValue(PortableDevicePKeys.WPD_PROPERTY_COMMON_COMMAND_CATEGORY,
        //                                   PortableDevicePKeys.WPD_COMMAND_MTP_EXT_EXECUTE_COMMAND_WITHOUT_DATA_PHASE.fmtid);
        //  commandValues.SetUnsignedIntegerValue(PortableDevicePKeys.WPD_PROPERTY_COMMON_COMMAND_ID,
        //                         PortableDevicePKeys.WPD_COMMAND_MTP_EXT_EXECUTE_COMMAND_WITHOUT_DATA_PHASE.pid);

        //  commandValues.SetIPortableDevicePropVariantCollectionValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_OPERATION_PARAMS, propVariant);
        //  commandValues.SetUnsignedIntegerValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_OPERATION_CODE, 0x9201);

        //  // According to documentation, first parameter should be 0 (see http://msdn.microsoft.com/en-us/library/dd375691%28v=VS.85%29.aspx)
        //  this.portableDeviceClass.SendCommand(0, commandValues, out results);
        //  int pvalue = 0;
        //  results.GetSignedIntegerValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_RESPONSE_CODE, out pvalue);

        //}


       // public byte[] GetLiveView()
       // {
       //   // source: http://msdn.microsoft.com/en-us/library/windows/desktop/ff384843(v=vs.85).aspx
       //   // and view-source:http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_26860397.html
       //   // error codes http://msdn.microsoft.com/en-us/library/windows/desktop/dd319335(v=vs.85).aspx
       //   byte[] imgdate = new byte[921600];

       //   IPortableDeviceValues commandValues = (IPortableDeviceValues)new PortableDeviceTypesLib.PortableDeviceValuesClass();
       //   IPortableDeviceValues pParameters = (IPortableDeviceValues)new PortableDeviceTypesLib.PortableDeviceValues();

       //   IPortableDevicePropVariantCollection propVariant =
       //     (IPortableDevicePropVariantCollection)new PortableDeviceTypesLib.PortableDevicePropVariantCollection();
       //   IPortableDeviceValues pResults;

       //   //commandValues.SetGuidValue(ref PortableDevicePKeys.WPD_PROPERTY_COMMON_COMMAND_CATEGORY, ref command.fmtid);
       //   commandValues.SetGuidValue(PortableDevicePKeys.WPD_PROPERTY_COMMON_COMMAND_CATEGORY,
       //                                    PortableDevicePKeys.WPD_COMMAND_MTP_EXT_EXECUTE_COMMAND_WITH_DATA_TO_READ.fmtid);
       //   commandValues.SetUnsignedIntegerValue(PortableDevicePKeys.WPD_PROPERTY_COMMON_COMMAND_ID,
       //                          PortableDevicePKeys.WPD_COMMAND_MTP_EXT_EXECUTE_COMMAND_WITH_DATA_TO_READ.pid);
       //   commandValues.SetBufferValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_TRANSFER_DATA, ref imgdate[0], (uint)imgdate.Length);

         
       //   commandValues.SetIPortableDevicePropVariantCollectionValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_OPERATION_PARAMS, propVariant);
       //   commandValues.SetUnsignedIntegerValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_OPERATION_CODE, 0x9203);

       //   // According to documentation, first parameter should be 0 (see http://msdn.microsoft.com/en-us/library/dd375691%28v=VS.85%29.aspx)
       //   this.portableDeviceClass.SendCommand(0, commandValues, out pResults);
          
       //   try
       //   {
       //     int pValue = 0;
       //     pResults.GetErrorValue(PortableDevicePKeys.WPD_PROPERTY_COMMON_HRESULT, out pValue);
       //     if (pValue!=0)
       //     {
       //       return null;
       //     }
       //   }
       //   catch (Exception ex)
       //   {
       //   }
       //   string pwszContext = string.Empty;
       //   pResults.GetStringValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_TRANSFER_CONTEXT,out pwszContext);
       //   uint cbReportedDataSize = 0;
       //   pResults.GetUnsignedIntegerValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_TRANSFER_TOTAL_DATA_SIZE, out cbReportedDataSize);


       //   uint tmpBufferSize = 0;
       //   uint tmpTransferSize = 0;
       //   string tmpTransferContext = string.Empty;
       //   {
       //     pResults.GetStringValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_TRANSFER_CONTEXT, out tmpTransferContext);
       //     pResults.GetUnsignedIntegerValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_TRANSFER_TOTAL_DATA_SIZE, out tmpBufferSize);
       //     pResults.GetUnsignedIntegerValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_OPTIMAL_TRANSFER_BUFFER_SIZE, out tmpTransferSize);

       //     try
       //     {
       //       int pValue;
       //       pResults.GetErrorValue(PortableDevicePKeys.WPD_PROPERTY_COMMON_HRESULT, out pValue);
       //       if(pValue!=0)
       //       {
       //         return null;
       //       }
       //     }
       //     catch
       //     {
       //     }
       //   }

       //   pParameters.Clear();
       //   pResults.Clear();

       //   byte[] tmpData = new byte[(int)tmpTransferSize];
       //   //CCustomReadContext{81CD75F1-A997-4DA2-BAB1-FF5EC514E355}
       //   pParameters.SetGuidValue(PortableDevicePKeys.WPD_PROPERTY_COMMON_COMMAND_CATEGORY, PortableDevicePKeys.WPD_COMMAND_MTP_EXT_READ_DATA.fmtid);
       //   pParameters.SetUnsignedIntegerValue(ref PortableDevicePKeys.WPD_PROPERTY_COMMON_COMMAND_ID, PortableDevicePKeys.WPD_COMMAND_MTP_EXT_READ_DATA.pid);
       //   pParameters.SetStringValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_TRANSFER_CONTEXT, tmpTransferContext);
       //   pParameters.SetBufferValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_TRANSFER_DATA, ref tmpData[0], (uint)tmpTransferSize);
       //   pParameters.SetUnsignedIntegerValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_TRANSFER_NUM_BYTES_TO_READ, (uint)tmpTransferSize);
       //   pParameters.SetIPortableDevicePropVariantCollectionValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_OPERATION_PARAMS, propVariant);


       //   portableDeviceClass.SendCommand(0, pParameters, out pResults);


       //   uint cbBytesRead = 0;

       //   try
       //   {
       //     int pValue = 0;
       //     pResults.GetErrorValue(PortableDevicePKeys.WPD_PROPERTY_COMMON_HRESULT, out pValue);
       //     if (pValue != 0)
       //       return null;
       //   }
       //   catch(Exception ex)
       //   {
       //   }
       //   // 24,142,174,9
       //   // 18, 8E  
       //   GCHandle pinnedArray = GCHandle.Alloc(imgdate, GCHandleType.Pinned);
       //   IntPtr ptr = pinnedArray.AddrOfPinnedObject();
          
       //   uint dataread =0;
       //   pResults.GetUnsignedIntegerValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_TRANSFER_NUM_BYTES_READ, out dataread);
       //   pResults.GetBufferValue(ref PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_TRANSFER_DATA, ptr, out cbBytesRead);

       //   IntPtr tmpPtr = new IntPtr(Marshal.ReadInt64(ptr));
       //   byte[] res = new byte[(int)cbBytesRead];
       //   for (int i = 0; i < cbBytesRead; i++)
       //   {
       //     res[i] = Marshal.ReadByte(tmpPtr, i);
       //   }

       //   pParameters.Clear();
       //   pResults.Clear();
       //   {
       //     pParameters.SetGuidValue(PortableDevicePKeys.WPD_PROPERTY_COMMON_COMMAND_CATEGORY, PortableDevicePKeys.WPD_COMMAND_MTP_EXT_END_DATA_TRANSFER.fmtid);
       //     pParameters.SetUnsignedIntegerValue(ref PortableDevicePKeys.WPD_PROPERTY_COMMON_COMMAND_ID, PortableDevicePKeys.WPD_COMMAND_MTP_EXT_END_DATA_TRANSFER.pid);
       //     pParameters.SetStringValue(PortableDevicePKeys.WPD_PROPERTY_MTP_EXT_TRANSFER_CONTEXT, tmpTransferContext);
       //   }

       //   portableDeviceClass.SendCommand(0, pParameters, out pResults);

       //   Marshal.FreeHGlobal(tmpPtr);
       //   pinnedArray.Free();
       //   //Marshal.FreeHGlobal(ptr);

       //   try
       //   {
       //     int tmpResult = 0;

       //     pResults.GetErrorValue(ref PortableDevicePKeys.WPD_PROPERTY_COMMON_HRESULT, out tmpResult);
       //     if(tmpResult!=0)
       //     {
              
       //     }
       //   }
       //   catch
       //   {
       //   }
       //   return res;
       //}
      
        /// <summary>
        /// Transfer from device to computer
        /// Source : http://cgeers.com/2011/08/13/wpd-transferring-content/
        /// </summary>
        /// <param name="deviceObject"></param>
        /// <param name="fileName"></param>
        public void SaveFile(PortableDeviceObject deviceObject, string fileName)
        {
          IPortableDeviceContent content;
          portableDeviceClass.Content(out content);
          IPortableDeviceResources resources;
          content.Transfer(out resources);

          PortableDeviceApiLib.IStream wpdStream = null;
          uint optimalTransferSize = 0;

          var property = PortableDevicePKeys.WPD_RESOURCE_DEFAULT;

          
          try
          {
            resources.GetStream(deviceObject.ID, ref property, 0, ref optimalTransferSize,
                    out wpdStream);
          }
          catch (COMException comException)
          {
            // check if the device is busy, this may hapen when a another transfer not finished 
            if ((uint)comException.ErrorCode == PortableDeviceErrorCodes.ERROR_BUSY)
            {
              Thread.Sleep(500);
              SaveFile(deviceObject, fileName);
              return;
            }
            throw comException;
          }

          System.Runtime.InteropServices.ComTypes.IStream sourceStream =
              (System.Runtime.InteropServices.ComTypes.IStream)wpdStream;

          FileStream targetStream = new FileStream(fileName,
              FileMode.Create, FileAccess.Write);

          unsafe
          {
            var buffer = new byte[1024*256];
            int bytesRead;
            do
            {
              sourceStream.Read(buffer, buffer.Length, new IntPtr(&bytesRead));
              targetStream.Write(buffer, 0, bytesRead);
            } while (bytesRead > 0);

            targetStream.Close();
          }
        }
 private void InitializeInstance(PortableDeviceObject obj, string name, string contentType, string format)
 {
     obj.Name = name;
     obj.ContentType = contentType;
     obj.Format = format;
 }
 private PortableDeviceObject CreateGenericObject(string id, string name, string contentType, string format)
 {
     var obj = new PortableDeviceObject(id);
     this.InitializeInstance(obj, name, contentType, format);
     return obj;
 }
 public void Delete(PortableDeviceObject obj, DeleteObjectOptions opts = DeleteObjectOptions.NO_RECURSION)
 {
     Delete(new[] {obj}, opts);
 }
 private IPortableDeviceValues GetRequiredPropertiesForPush(PortableDeviceObject parentObject, string name, string originalFileName, ulong size)
 {
     var values = (IPortableDeviceValues) new PortableDeviceValues();
     values.SetStringValue(PortableDevicePKeys.WPD_OBJECT_PARENT_ID, parentObject.ID);
     values.SetUnsignedLargeIntegerValue(PortableDevicePKeys.WPD_OBJECT_SIZE, size);
     values.SetStringValue(PortableDevicePKeys.WPD_OBJECT_ORIGINAL_FILE_NAME, originalFileName);
     values.SetStringValue(PortableDevicePKeys.WPD_OBJECT_NAME, name);
     return values;
 }
 private void ConvertObjectsIdToPropVariant(PortableDeviceObject obj, out tag_inner_PROPVARIANT propvarValue)
 {
     var pValues = (IPortableDeviceValues) new PortableDeviceValuesClass();
     pValues.SetStringValue(PortableDevicePKeys.WPD_OBJECT_ID, obj.ID);
     pValues.GetValue(ref PortableDevicePKeys.WPD_OBJECT_ID, out propvarValue);
 }
        /// <summary>
        ///     Transfer from device to computer
        ///     Source : http://cgeers.com/2011/08/13/wpd-transferring-content/
        ///     Inspired by nikon-camera-control
        /// </summary>
        /// <param name="deviceObject"></param>
        /// <param name="targetStream"></param>
        public void Pull(PortableDeviceObject deviceObject, Stream targetStream)
        {
            IPortableDeviceContent content;
            portableDeviceClass.Content(out content);
            IPortableDeviceResources resources;
            content.Transfer(out resources);

            IStream wpdStream;
            uint optimalTransferSize = 0;

            _tagpropertykey property = PortableDevicePKeys.WPD_RESOURCE_DEFAULT;

            int numRetries = 3;
            const int retryTimeout = 500;
            const uint STGM_READ = 0;
            do
            {
                try
                {
                    resources.GetStream(deviceObject.ID, ref property, STGM_READ, ref optimalTransferSize, out wpdStream);
                    numRetries = 0;
                }
                catch (COMException comException)
                {
                    if ((uint) comException.ErrorCode == PortableDeviceErrorCodes.ERROR_BUSY)
                    {
                        Thread.Sleep(retryTimeout);
                    }
                    throw;
                }
            } while (numRetries-- > 0);

            var sourceStream = (System.Runtime.InteropServices.ComTypes.IStream) wpdStream;
            unsafe
            {
                var buffer = new byte[1024*256];
                int bytesRead;
                do
                {
                    sourceStream.Read(buffer, buffer.Length, new IntPtr(&bytesRead));
                    if (bytesRead == 0)
                        break;
                    targetStream.Write(buffer, 0, bytesRead);
                } while (bytesRead > 0);

                targetStream.Close();
            }
            Marshal.ReleaseComObject(sourceStream);
            Marshal.ReleaseComObject(wpdStream);
        }
 public bool IsObjectMatching(PortableDeviceObject obj)
 {
     return true;
 }
 private bool MatchesPath(PortableDeviceObject portableDeviceObject, string pathNode)
 {
     // Defined content types that represent filesystem object don't contain extension
     var file = portableDeviceObject as PortableDeviceFileObject;
     if (file != null)
         return Regex.IsMatch(file.FileName, pathNode, RegexOptions.IgnoreCase);
     return Regex.IsMatch(portableDeviceObject.Name, pathNode, RegexOptions.IgnoreCase);
 }
 public bool IsObjectMatching(PortableDeviceObject obj)
 {
     if (paths.Count == 0)
         return false;
     var pathNode = paths.Peek();
     return MatchesPath(obj, pathNode);
 }