2016-05-14 21 views
0

我目前正在尝试使本机库工作的deezer包装器。 它会一直工作,直到它尝试播放曲目:我收到了一个说PLAYLIST_TRACK_NO_RIGHT的回调。用于C++ deezer库的C#包装器:PLAYLIST_TRACK_NO_RIGHT

我试着用在线deezer网站阅读这个曲目,效果很好。我也尝试过在deezer网站上运行的另一首曲目,但仍然无法与封套一起使用,说没有权利播放它。

有谁知道为什么会有这个错误? 我觉得有一些Connect方法。我看到ccappSecret属性消失了,取而代之的是我们有一个已经弹出的ProductId,ProductBuildId和anonymousblob。

那么我们必须写入这个?没有关于这方面的文档(我们唯一可以找到的文档说我们应该将产品ID发送到产品ID中,但是这是什么?我们在哪里可以找到这些信息?)

这里是包装代码:

using System; 
using System.Collections; 
using System.Runtime.InteropServices; 
// make this binding dependent on WPF, but easier to use 
using System.Windows.Threading; 

// http://www.codeproject.com/Articles/339290/PInvoke-pointer-safety-Replacing-IntPtr-with-unsaf 

namespace Deezer 
{ 

    #region Enums 

    public enum CONNECT_EVENT_TYPE 
    { 
     UNKNOWN,       /**< Connect event has not been set yet, not a valid value. */ 
     USER_OFFLINE_AVAILABLE,   /**< User logged in, and credentials from offline store are loaded. */ 

     USER_ACCESS_TOKEN_OK,    /**< (Not available) dz_connect_login_with_email() ok, and access_token is available */ 
     USER_ACCESS_TOKEN_FAILED,   /**< (Not available) dz_connect_login_with_email() failed */ 

     USER_LOGIN_OK,      /**< Login with access_token ok, infos from user available. */ 
     USER_LOGIN_FAIL_NETWORK_ERROR,  /**< Login with access_token failed because of network condition. */ 
     USER_LOGIN_FAIL_BAD_CREDENTIALS, /**< Login with access_token failed because of bad credentials. */ 
     USER_LOGIN_FAIL_USER_INFO,   /**< Login with access_token failed because of other problem. */ 
     USER_LOGIN_FAIL_OFFLINE_MODE,  /**< Login with access_token failed because we are in forced offline mode. */ 

     USER_NEW_OPTIONS,     /**< User options have just changed. */ 

     ADVERTISEMENT_START,    /**< A new advertisement needs to be displayed. */ 
     ADVERTISEMENT_STOP,    /**< An advertisement needs to be stopped. */ 
    }; 

    public enum ERRORS 
    { 
     DZ_ERROR_NO_ERROR = 0x00000000, 
     DZ_ERROR_NO_ERROR_ASYNC = 0x00000001, 
     DZ_ERROR_ERROR_ARG = 0x00000002, 
     DZ_ERROR_ERROR_STATE = 0x00000003, 
     DZ_ERROR_NOT_IMPLEMENTED = 0x00000004, 
     DZ_ERROR_ASYNC_CANCELED = 0x00000005, 

     DZ_ERROR_NOT_ENOUGH_MEMORY, 
     DZ_ERROR_OS_ERROR, 
     DZ_ERROR_UNSUPPORTED, 
     DZ_ERROR_CLASS_NOT_FOUND, 
     DZ_ERROR_JSON_PARSING, 
     DZ_ERROR_XML_PARSING, 
     DZ_ERROR_PARSING, 
     DZ_ERROR_CLASS_INSTANTIATION, 
     DZ_ERROR_RUNNABLE_ALREADY_STARTED, 
     DZ_ERROR_RUNNABLE_NOT_STARTED, 
     DZ_ERROR_CACHE_RESOURCE_OPEN_FAILED, 
     DZ_ERROR_FS_FULL, 
     DZ_ERROR_FILE_EXISTS, 
     DZ_ERROR_IO_ERROR, 

     DZ_ERROR_CATEGORY_CONNECT = 0x00010000, 
     DZ_ERROR_CONNECT_SESSION_LOGIN_FAILED, 
     DZ_ERROR_USER_PROFILE_PERM_DENIED, 
     DZ_ERROR_CACHE_DIRECTORY_PERM_DENIED, 
     DZ_ERROR_CONNECT_SESSION_NOT_ONLINE, 
     DZ_ERROR_CONNECT_SESSION_OFFLINE_MODE, 
     DZ_ERROR_CONNECT_NO_OFFLINE_CACHE, 

     DZ_ERROR_CATEGORY_PLAYER = 0x00020000, 
     DZ_ERROR_PLAYER_PLAYLIST_NONE_SET, 
     DZ_ERROR_PLAYER_PLAYLIST_BAD_INDEX, 
     DZ_ERROR_PLAYER_PLAYLIST_NO_MEDIA,   /**< when trying to access non existing track/radio */ 
     DZ_ERROR_PLAYER_PLAYLIST_NO_RIGHTS,  /**< when trying to access track/radio with no rights */ 
     DZ_ERROR_PLAYER_PLAYLIST_RIGHT_TIMEOUT, /**< when timoeout trying to get rights */ 
     DZ_ERROR_PLAYER_PLAYLIST_RADIO_TOO_MANY_SKIP, 
     DZ_ERROR_PLAYER_PLAYLIST_NO_MORE_TRACK, 
     DZ_ERROR_PLAYER_PAUSE_NOT_STARTED, 
     DZ_ERROR_PLAYER_PAUSE_ALREADY_PAUSED, 
     DZ_ERROR_PLAYER_UNPAUSE_NOT_STARTED, 
     DZ_ERROR_PLAYER_UNPAUSE_NOT_PAUSED, 
     DZ_ERROR_PLAYER_SEEK_NOT_SEEKABLE_NOT_STARTED, 
     DZ_ERROR_PLAYER_SEEK_NOT_SEEKABLE_NO_DURATION, 
     DZ_ERROR_PLAYER_SEEK_NOT_SEEKABLE_NOT_INDEXED, 
     DZ_ERROR_PLAYER_SEEK_NOT_SEEKABLE, 

     DZ_ERROR_CATEGORY_MEDIASTREAMER = 0x00030000, 
     DZ_ERROR_MEDIASTREAMER_BAD_URL_SCHEME, 
     DZ_ERROR_MEDIASTREAMER_BAD_URL_HOST, 
     DZ_ERROR_MEDIASTREAMER_BAD_URL_TRACK, 
     DZ_ERROR_MEDIASTREAMER_NOT_AVAILABLE_OFFLINE, 
     DZ_ERROR_MEDIASTREAMER_NOT_READABLE, 
     DZ_ERROR_MEDIASTREAMER_NO_DURATION, 
     DZ_ERROR_MEDIASTREAMER_NOT_INDEXED, 
     DZ_ERROR_MEDIASTREAMER_SEEK_NOT_SEEKABLE, 
     DZ_ERROR_MEDIASTREAMER_NO_DATA, 
     DZ_ERROR_MEDIASTREAMER_END_OF_STREAM, 
     DZ_ERROR_MEDIASTREAMER_ALREADY_MAPPED, 
     DZ_ERROR_MEDIASTREAMER_NOT_MAPPED, 

     DZ_ERROR_CATEGORY_OFFLINE = 0x00040000, 
     DZ_ERROR_OFFLINE_FS_FULL, 

     DZ_ERROR_PLAYER_BAD_URL, 
    }; 

    public enum PLAYER_COMMANDS 
    { 
     UNKNOWN,   /**< Player command has not been set yet, not a valid value. */ 
     START_TRACKLIST, /**< A new tracklist was loaded and a track played. */ 
     JUMP_IN_TRACKLIST, /**< The user jump into a new song in the current tracklist. */ 
     NEXT,    /**< Next button. */ 
     PREV,    /**< Prev button. */ 
     DISLIKE,   /**< Dislike button. */ 
     NATURAL_END,  /**< Natural end. */ 
     RESUMED_AFTER_ADS, /**< Reload after playing an ads. */ 
    } 

    public enum TRACKLIST_AUTOPLAY_MODE 
    { 
     MODE_UNKNOWN, 

     MANUAL, 

     MODE_ONE, 

     MODE_ONE_REPEAT, 

     MODE_NEXT, 

     MODE_NEXT_REPEAT, 

     MODE_RANDOM, 

     MODE_RANDOM_REPEAT, 
    }; 

    public enum PLAYER_EVENT_TYPE 
    { 
     UNKNOWN,        /**< Player event has not been set yet, not a valid value. */ 

     // Data access related event. 
     LIMITATION_FORCED_PAUSE,    /**< Another deezer player session was created elsewhere, the player has entered pause mode. */ 

     // Track selection related event. 
     PLAYLIST_TRACK_NOT_AVAILABLE_OFFLINE,/**< You're offline, the track is not available. */ 
     PLAYLIST_TRACK_NO_RIGHT,    /**< You don't have the right to render this track. */ 
     PLAYLIST_TRACK_RIGHTS_AFTER_AUDIOADS,/**< You have right to play it, but you should render an ads first : 
                - Use dz_player_event_get_advertisement_infos_json(). 
                - Play an ad with dz_player_play_audioads(). 
                - Wait for #DZ_PLAYER_EVENT_RENDER_TRACK_END. 
                - Use dz_player_play() with previous track or DZ_PLAYER_PLAY_CMD_RESUMED_AFTER_ADS (to be done even on radios for now). 
               */ 
     PLAYLIST_SKIP_NO_RIGHT,    /**< You're on a radio, and you had no right to do skip. */ 

     PLAYLIST_TRACK_SELECTED,    /**< A track is selected among the ones available on the server, and will be fetched and read. */ 

     PLAYLIST_NEED_NATURAL_NEXT,   /**< We need a new natural_next action. */ 

     // Data loading related event. 
     MEDIASTREAM_DATA_READY,    /**< Data is ready to be introduced into audio output (first data after a play). */ 
     MEDIASTREAM_DATA_READY_AFTER_SEEK, /**< Data is ready to be introduced into audio output (first data after a seek). */ 

     // Play (audio rendering on output) related event. 
     RENDER_TRACK_START_FAILURE,  /**< Error, track is unable to play. */ 
     RENDER_TRACK_START,    /**< A track has started to play. */ 
     RENDER_TRACK_END,     /**< A track has stopped because the stream has ended. */ 
     RENDER_TRACK_PAUSED,    /**< Currently on paused. */ 
     RENDER_TRACK_SEEKING,    /**< Waiting for new data on seek. */ 
     RENDER_TRACK_UNDERFLOW,   /**< Underflow happened whilst playing a track. */ 
     RENDER_TRACK_RESUMED,    /**< Player resumed play after a underflow or a pause. */ 
     RENDER_TRACK_REMOVED,    /**< Player stopped playing a track. */ 
    }; 

    #endregion 

    #region Delegates 

    // called with userdata Dispatcher on connect events 
    public delegate void ConnectOnEventCb(Connect connect, ConnectEvent connectEvent, DispatcherObject userdata); 
    public delegate void PlayerOnEventCb(Player player, PlayerEvent playerEvent, DispatcherObject userdata); 

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
    unsafe public delegate void libcConnectOnEventCb(CONNECT* libcConnect, CONNECT_EVENT* libcConnectEvent, IntPtr userdata); 
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
    unsafe public delegate bool libcAppCrashDelegate(); 
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
    unsafe public delegate void libcPlayerOnEventCb(PLAYER* libcPlayer, PLAYER_EVENT* libcPlayerEvent, IntPtr userdata); 

    #endregion 

    #region Structures 

unsafe public struct CONNECT_EVENT { }; 

unsafe public struct UTF8STRING { }; 

unsafe public struct CONNECT { }; 

unsafe public struct PLAYER_EVENT { }; 

unsafe public struct PLAYER { }; 

#endregion 

    #region Imports 

#endregion 

    // to be in sync with dz_connect_configuration 
    [StructLayout(LayoutKind.Sequential)] 
    public class ConnectConfig 
    { 
     public string ccAppId; 

     public string product_id; 
     public string product_build_id; 
     public string anonymousblob; 


     //public string ccAppSecret; 

     public string ccUserProfilePath; 

     public DispatcherObject ccConnectUserdata; 
     public ConnectOnEventCb ccConnectEventCb; 
    } 

    public class ConnectEvent 
    { 
     internal CONNECT_EVENT_TYPE eventType; 

     /* two design strategies: 
    * - we could keep a reference to CONNECT_EVENT* with dz_object_retain and call method on the fly 
    * - we extract all info in constructor and have pure managed object 
    * 
    * here we keep the second option, because we have to have a managed object anyway, and it's 
    * a lot fewer unsafe method to expose, even though it's making a lot of calls in the constructor.. 
    */ 
     public unsafe static ConnectEvent newFromLibcEvent(CONNECT_EVENT* libcConnectEventHndl) 
    { 
     CONNECT_EVENT_TYPE eventType; 
     unsafe 
     { 
      eventType = dz_connect_event_get_type(libcConnectEventHndl); 
     } 
     switch (eventType) 
     { 
      case CONNECT_EVENT_TYPE.USER_ACCESS_TOKEN_OK: 
       string accessToken; 
       unsafe 
       { 
        IntPtr libcAccessTokenString = dz_connect_event_get_access_token(libcConnectEventHndl); 
        accessToken = Marshal.PtrToStringAnsi(libcAccessTokenString); 
       } 
       return new NewAccessTokenConnectEvent(accessToken); 
      default: 
       return new ConnectEvent(eventType); 
     } 
    } 

     public ConnectEvent(CONNECT_EVENT_TYPE eventType) 
    { 
     this.eventType = eventType; 
    } 

     public CONNECT_EVENT_TYPE GetEventType() 
    { 
     return eventType; 
    } 

     [DllImport("libdeezer.x64.dll", CallingConvention = CallingConvention.Cdecl)] 
     static extern unsafe CONNECT_EVENT_TYPE dz_connect_event_get_type(CONNECT_EVENT* dzConnectEvent); 

     [DllImport("libdeezer.x64.dll", CallingConvention = CallingConvention.Cdecl)] 
     static extern unsafe IntPtr dz_connect_event_get_access_token(CONNECT_EVENT* dzConnectEvent); 
    } 

    public class NewAccessTokenConnectEvent : ConnectEvent 
    { 
     string accessToken; 

     public NewAccessTokenConnectEvent(string accessToken) 
     : base(CONNECT_EVENT_TYPE.USER_ACCESS_TOKEN_OK) 
    { 
     this.accessToken = accessToken; 
    } 

     public string GetAccessToken() 
    { 
     return accessToken; 
    } 
    } 

    unsafe public class Connect 
    { 
     // hash 
     static Hashtable refKeeper = new Hashtable(); 

     internal unsafe CONNECT* libcConnectHndl; 
     internal ConnectConfig connectConfig; 

     public unsafe Connect(ConnectConfig cc) 
     { 
      NativeMethods.LoadClass(); 
      //ConsoleHelper.AllocConsole(); 
      // attach a console to parent process (launch from cmd.exe) 
      //ConsoleHelper.AttachConsole(-1); 

      CONNECT_CONFIG libcCc = new CONNECT_CONFIG(); 

      connectConfig = cc; 

      IntPtr intptr = new IntPtr(this.GetHashCode()); 

      refKeeper[intptr] = this; 

      libcCc.ccAppId = cc.ccAppId; 
      libcCc.ccAnonymousBlob = cc.anonymousblob; 
      //libcCc.ccAppSecret = cc.ccAppSecret; 
      libcCc.ccProductBuildId = cc.product_build_id; 
      libcCc.ccProductId = cc.product_id; 
      libcCc.ccUserProfilePath = UTF8Marshaler.GetInstance(null).MarshalManagedToNative(cc.ccUserProfilePath); 
      libcCc.ccConnectEventCb = delegate (CONNECT* libcConnect, CONNECT_EVENT* libcConnectEvent, IntPtr userdata) 
      { 
       Connect connect = (Connect)refKeeper[userdata]; 
       ConnectEvent connectEvent = ConnectEvent.newFromLibcEvent(libcConnectEvent); 
       DispatcherObject dispather = connect.connectConfig.ccConnectUserdata; 

       dispather.Dispatcher.Invoke(connect.connectConfig.ccConnectEventCb, connect, connectEvent, connect.connectConfig.ccConnectUserdata); 
      }; 

      libcConnectHndl = dz_connect_new(libcCc); 

      UTF8Marshaler.GetInstance(null).CleanUpNativeData(libcCc.ccUserProfilePath); 
     } 

     public int Start() 
     { 
      int ret; 
      ret = dz_connect_activate(libcConnectHndl, new IntPtr(this.GetHashCode())); 
      return ret; 
     } 

     public string DeviceId() 
    { 
     IntPtr libcDeviceId = dz_connect_get_device_id(libcConnectHndl); 

     if (libcDeviceId == null) 
     { 
      return null; 
     } 

     return Marshal.PtrToStringAnsi(libcDeviceId); 
    } 

     public int SetAccessToken(string accessToken) 
    { 
     int ret; 
     ret = dz_connect_set_access_token(libcConnectHndl, IntPtr.Zero, IntPtr.Zero, accessToken); 
     return ret; 
    } 

     public int SetSmartCache(string path, int quotaKb) 
    { 
     int ret; 
     ret = dz_connect_cache_path_set(libcConnectHndl, IntPtr.Zero, IntPtr.Zero, path); 
     ret = dz_connect_smartcache_quota_set(libcConnectHndl, IntPtr.Zero, IntPtr.Zero, quotaKb); 
     return ret; 
    } 

     [DllImport("libdeezer.x64.dll", CallingConvention = CallingConvention.Cdecl)] 
     static extern unsafe CONNECT* dz_connect_new(
      [In, MarshalAs(UnmanagedType.LPStruct)] 
      CONNECT_CONFIG lpcc); 

     [DllImport("libdeezer.x64.dll", CallingConvention = CallingConvention.Cdecl)] 
     static extern unsafe IntPtr dz_connect_get_device_id(
      CONNECT* dzConnect); 

     [DllImport("libdeezer.x64.dll", CallingConvention = CallingConvention.Cdecl)] 
     static extern unsafe int dz_connect_activate(
      CONNECT* dzConnect, IntPtr userdata); 

     [DllImport("libdeezer.x64.dll", CallingConvention = CallingConvention.Cdecl)] 
     static extern unsafe int dz_connect_set_access_token(
      CONNECT* dzConnect, IntPtr cb, IntPtr userdata, string access_token); 

     [DllImport("libdeezer.x64.dll", CallingConvention = CallingConvention.Cdecl)] 
     static extern unsafe int dz_connect_cache_path_set(
      CONNECT* dzConnect, IntPtr cb, IntPtr userdata, 
      [MarshalAs(UnmanagedType.CustomMarshaler, 
       MarshalTypeRef=typeof(UTF8Marshaler))] 
       string local_path); 

     [DllImport("libdeezer.x64.dll", CallingConvention = CallingConvention.Cdecl)] 
     static extern unsafe int dz_connect_smartcache_quota_set(
      CONNECT* dzConnect, IntPtr cb, IntPtr userdata, 
       int quota_kB); 
    } 

    public class PlayerEvent 
    { 
     internal PLAYER_EVENT_TYPE eventType; 

     /* two design strategies: 
    * - we could keep a reference to PLAYER_EVENT* with dz_object_retain and call method on the fly 
    * - we extract all info in constructor and have pure managed object 
    * 
    * here we keep the second option, because we have to have a managed object anyway, and it's 
    * a lot fewer unsafe method to expose, even though it's making a lot of calls in the constructor.. 
    */ 
     public unsafe static PlayerEvent newFromLibcEvent(PLAYER_EVENT* libcPlayerEventHndl) 
    { 
     PLAYER_EVENT_TYPE eventType; 
     unsafe 
     { 
      eventType = dz_player_event_get_type(libcPlayerEventHndl); 
     } 
     switch (eventType) 
     { 
      default: 
       return new PlayerEvent(eventType); 
     } 
    } 

     public PlayerEvent(PLAYER_EVENT_TYPE eventType) 
     { 
      this.eventType = eventType; 
     } 

     public PLAYER_EVENT_TYPE GetEventType() 
    { 
     return eventType; 
    } 

     [DllImport("libdeezer.x64.dll", CallingConvention = CallingConvention.Cdecl)] 
     static extern unsafe PLAYER_EVENT_TYPE dz_player_event_get_type(PLAYER_EVENT* dzPlayerEvent); 
    } 

    unsafe public class Player 
    { 
     // hash 
     static Hashtable refKeeper = new Hashtable(); 

     internal unsafe PLAYER* libcPlayerHndl; 
     internal Connect connect; 
     internal libcPlayerOnEventCb eventcb; 


     public unsafe Player(Connect connect, object observer) 
    { 
     IntPtr intptr = new IntPtr(this.GetHashCode()); 

     refKeeper[intptr] = this; 

     libcPlayerHndl = dz_player_new(connect.libcConnectHndl); 

     this.connect = connect; 
    } 

     public int Start(PlayerOnEventCb eventcb) 
     { 
      int ret; 
      ret = dz_player_activate(libcPlayerHndl, new IntPtr(this.GetHashCode())); 

      this.eventcb = delegate (PLAYER* libcPlayer, PLAYER_EVENT* libcPlayerEvent, IntPtr userdata) 
      { 
       Player player = (Player)refKeeper[userdata]; 
       PlayerEvent playerEvent = PlayerEvent.newFromLibcEvent(libcPlayerEvent); 
       DispatcherObject dispather = player.connect.connectConfig.ccConnectUserdata; 

       dispather.Dispatcher.Invoke(eventcb, player, playerEvent, connect.connectConfig.ccConnectUserdata); 
      }; 

      ret = dz_player_set_event_cb(libcPlayerHndl, this.eventcb); 
      return ret; 
     } 

     public int LoadStream(string url) 
     { 
      int ret; 
      ret = dz_player_load(libcPlayerHndl, IntPtr.Zero, IntPtr.Zero, url); 
      return ret; 
     } 

     public int Play(int idx, PLAYER_COMMANDS cmd) 
     { 
      int ret; 
      ret = dz_player_play(libcPlayerHndl, IntPtr.Zero, IntPtr.Zero, cmd, TRACKLIST_AUTOPLAY_MODE.MANUAL, idx); 
      //ret = dz_player_play(libcPlayerHndl, IntPtr.Zero, IntPtr.Zero, cmd, TRACKLIST_AUTOPLAY_MODE.MODE_ONE, idx); 
      return ret; 
     } 

     [DllImport("libdeezer.x64.dll", CallingConvention = CallingConvention.Cdecl)] 
     static extern unsafe PLAYER* dz_player_new(CONNECT* lpcc); 
     //static extern unsafe PLAYER* dz_player_new(CONNECT* lpcc, IntPtr userdata); 

     [DllImport("libdeezer.x64.dll", CallingConvention = CallingConvention.Cdecl)] 
     static extern unsafe int dz_player_set_event_cb(PLAYER* lpcc, libcPlayerOnEventCb cb); 

     [DllImport("libdeezer.x64.dll", CallingConvention = CallingConvention.Cdecl)] 
     static extern unsafe int dz_player_activate(PLAYER* dzPlayer, IntPtr userdata); 
     //static extern unsafe int dz_player_activate(PLAYER* dzPlayer, IntPtr userdata); 

     [DllImport("libdeezer.x64.dll", CallingConvention = CallingConvention.Cdecl)] 
     static extern unsafe int dz_player_load(PLAYER* dzPlayer, IntPtr cb, IntPtr userdata, string url); 

     [DllImport("libdeezer.x64.dll", CallingConvention = CallingConvention.Cdecl)] 
     static extern unsafe int dz_player_play(PLAYER* dzPlayer, IntPtr cb, IntPtr userdata, PLAYER_COMMANDS cmd, TRACKLIST_AUTOPLAY_MODE mode, int idx); 
     //static extern unsafe int dz_player_play(PLAYER* dzPlayer, IntPtr cb, IntPtr userdata, int idx, TRACKLIST_AUTOPLAY_MODE mode); 
    } 



    [StructLayout(LayoutKind.Sequential)] 
    public class CONNECT_CONFIG 
    { 
     public string ccAppId; 

     public string ccProductId; 
     public string ccProductBuildId; 

     public IntPtr ccUserProfilePath; 

     public libcConnectOnEventCb ccConnectEventCb; 

     public string ccAnonymousBlob; 

     public libcAppCrashDelegate ccAppCrashDelegate; 

    } 




    // trick from http://stackoverflow.com/questions/1573724/cpu-architecture-independent-p-invoke-can-the-dllname-or-path-be-dynamic 
// but actually SetDllDirectory works better (for pthread.dll) 
    public static class NativeMethods 
    { 
     // call this to load this class 
     public static void LoadClass() 
    { 
    } 

     [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     static extern bool SetDllDirectory(string lpPathName); 

     [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] 
     static extern IntPtr LoadLibrary(string lpFileName); 

     static NativeMethods() 
    { 
     string arch; 
     string basePath = System.IO.Path.GetDirectoryName(typeof(NativeMethods).Assembly.Location); 


     if (IntPtr.Size == 4) 
      arch = "i386"; 
     else 
      arch = "x86_64"; 

     System.Diagnostics.Debug.WriteLine("using arch: " + arch); 

     SetDllDirectory(System.IO.Path.Combine(basePath, arch)); 
#if false // can be used to debug library loading 
     IntPtr hExe = LoadLibrary("libdeezer.x64.dll"); 

     if (hExe == IntPtr.Zero) 
     { 
      Win32Exception ex = new Win32Exception(Marshal.GetLastWin32Error()); 
      System.Console.WriteLine("exception:" + ex); 
      throw ex; 
     } 
#endif 
    } 

    } 

    // http://stackoverflow.com/questions/10415807/output-console-writeline-from-wpf-windows-applications-to-actual-console 
    public class ConsoleHelper 
    { 
     /// <summary> 
    /// Allocates a new console for current process. 
    /// </summary> 
     [DllImport("kernel32.dll")] 
     public static extern Boolean AllocConsole(); 

     [DllImport("Kernel32.dll")] 
     public static extern bool AttachConsole(int processId); 

     /// <summary> 
    /// Frees the console. 
    /// </summary> 
     [DllImport("kernel32.dll")] 
     public static extern Boolean FreeConsole(); 
    } 

    // http://www.codeproject.com/Articles/138614/Advanced-Topics-in-PInvoke-String-Marshaling 
    public class UTF8Marshaler : ICustomMarshaler 
    { 
     static UTF8Marshaler static_instance; 

     // maybe we could play with WideCharToMultiByte too and avoid Marshal.Copy 
    // http://stackoverflow.com/questions/537573/how-to-get-intptr-from-byte-in-c-sharp 
     /* 
     Byte[] byNewData = null; 

     iNewDataLen = NativeMethods.WideCharToMultiByte(NativeMethods.CP_UTF8, 0, cc.ccUserProfilePath, -1, null, 0, IntPtr.Zero, IntPtr.Zero); 
     Console.WriteLine("iNewDataLen:" + iNewDataLen + " len:" + cc.ccUserProfilePath.Length + " ulen:" + iNewDataLen); 
     byNewData = new Byte[iNewDataLen]; 
     iNewDataLen = NativeMethods.WideCharToMultiByte(NativeMethods.CP_UTF8, 0, cc.ccUserProfilePath, cc.ccUserProfilePath.Length, byNewData, iNewDataLen, IntPtr.Zero, IntPtr.Zero); 

     libcCc.ccUserProfilePath = Marshal.UnsafeAddrOfPinnedArrayElement(byNewData, 0); 
    */ 
     public IntPtr MarshalManagedToNative(object managedObj) 
    { 
     if (managedObj == null) 
      return IntPtr.Zero; 
     if (!(managedObj is string)) 
      throw new MarshalDirectiveException(
        "UTF8Marshaler must be used on a string."); 

     // not null terminated 
     byte[] strbuf = System.Text.Encoding.UTF8.GetBytes((string)managedObj); 
     IntPtr buffer = Marshal.AllocHGlobal(strbuf.Length + 1); 
     Marshal.Copy(strbuf, 0, buffer, strbuf.Length); 

     // write the terminating null 
     Marshal.WriteByte(buffer + strbuf.Length, 0); 
     return buffer; 
    } 
     public unsafe object MarshalNativeToManaged(IntPtr pNativeData) 
    { 
     byte* walk = (byte*)pNativeData; 

     // find the end of the string 
     while (*walk != 0) 
     { 
      walk++; 
     } 
     int length = (int)(walk - (byte*)pNativeData); 

     // should not be null terminated 
     byte[] strbuf = new byte[length]; 
     // skip the trailing null 
     Marshal.Copy((IntPtr)pNativeData, strbuf, 0, length); 
     string data = System.Text.Encoding.UTF8.GetString(strbuf); 
     return data; 
    } 

     public void CleanUpNativeData(IntPtr pNativeData) 
    { 
     Marshal.FreeHGlobal(pNativeData); 
    } 

     public void CleanUpManagedData(object managedObj) 
    { 
    } 

     public int GetNativeDataSize() 
    { 
     return -1; 
    } 

     public static ICustomMarshaler GetInstance(string cookie) 
    { 
     if (static_instance == null) 
     { 
      return static_instance = new UTF8Marshaler(); 
     } 
     return static_instance; 
    } 

     [DllImport("kernel32.dll")] 
     public static extern int WideCharToMultiByte(uint CodePage, uint dwFlags, 
      [MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr, int cchWideChar, 
      [MarshalAs(UnmanagedType.LPArray)] Byte[] lpMultiByteStr, int cbMultiByte, IntPtr lpDefaultChar, 
      IntPtr lpUsedDefaultChar); 

     public const uint CP_UTF8 = 65001; 
    } 
} 
+0

最后一个参数使用诸如Fiddler嗅探器和网站的结果与应用比较。通常这个问题是http标题。我会在两次尝试之间删除IE历史记录(Cookie),因为Cookie可能会影响结果。 – jdweng

回答

0

也许您的access_token无效了吗? 您能否检查您创建的“access_token”在致电https://connect.deezer.com/oauth/auth.php?app_id=YOUR_APP_ID&redirect_uri=YOUR_REDIRECT_URI&perms=basic_access,email,offline_access时是否启用offline_access。它应该给予更持久的权利。 (CF:http://developers.deezer.com/api/oauthhttp://developers.deezer.com/api/permissions

+0

不会改变任何东西:(关于从ConnectConfig中消失的事实appSecretId属性和ConnectConfig中的新属性(如productid和product build id)的情况呢?我仍然不知道如何使用它们。 – Steeve

+0

dispatcher用于包装器你从我们的邮件对话开始发给我)所以如果我不给它一个调度器,我会有一个空引用异常。你有没有一个包装器样本,我可以使用这个调度器吗? – Steeve

+0

你可以吗?请发布一些问题的痕迹?谢谢。 – CyrilP

2

我有同样的问题

尝试第一次运行dz_connect_offline_mode与假

+0

它不起作用,仍然是同样的问题。 – Steeve

+0

在你以前的示例代码(http://stackoverflow.com/questions/37120771/c-sharp-deezer-native-api-adapting-to-c-sharp)我看到你设置令牌后调用dz_connect_activate。我认为正确的顺序是首先调用激活,然后设置令牌。 – IvanR

+0

感谢您的回答,但它仍然是同样的问题。这里是我的测试项目的链接:https://onedrive.live.com/redir?resid=9156C1D87978D3B6!1165&authkey=!AE9OBJ-SrEUZNoE&ithint=file%2czip – Steeve