├── .gitattributes
├── .gitignore
├── Wechat.sln
├── Wechat
├── API
│ ├── RPC
│ │ ├── BaseRequest.cs
│ │ ├── BaseResponse.cs
│ │ ├── BatchGetContact
│ │ │ ├── BatchGetContactRequest.cs
│ │ │ └── BatchGetContactResponse.cs
│ │ ├── GetContact
│ │ │ └── GetContactResponse.cs
│ │ ├── SendMsg
│ │ │ ├── SendMsgRequest.cs
│ │ │ └── SendMsgResponse.cs
│ │ ├── SendMsgImg
│ │ │ ├── SendMsgImgRequest.cs
│ │ │ └── SendMsgImgResponse.cs
│ │ ├── Statusnotify
│ │ │ ├── StatusnotifyRequest.cs
│ │ │ └── StatusnotifyResponse.cs
│ │ ├── Sync
│ │ │ ├── SyncRequest.cs
│ │ │ └── SyncResponse.cs
│ │ ├── SyncCheck
│ │ │ └── SyncCheckResponse.cs
│ │ ├── Uploadmedia
│ │ │ ├── UploadmediaRequest.cs
│ │ │ └── UploadmediaResponse.cs
│ │ ├── init
│ │ │ ├── InitRequest.cs
│ │ │ └── initResponse.cs
│ │ └── oplog
│ │ │ ├── OplogRequest.cs
│ │ │ └── OplogResponse.cs
│ ├── Result
│ │ ├── LoginRedirectResult.cs
│ │ └── LoginResult.cs
│ ├── WechatAPIService.cs
│ └── Wx
│ │ ├── AddMsg.cs
│ │ ├── AppInfo.cs
│ │ ├── BatchUser.cs
│ │ ├── ImgMsg.cs
│ │ ├── Msg.cs
│ │ ├── RecommendInfo.cs
│ │ ├── SyncKey.cs
│ │ └── User.cs
├── Properties
│ └── AssemblyInfo.cs
├── Wechat.csproj
├── Wechat
│ ├── Contact.cs
│ ├── Events.cs
│ ├── Group.cs
│ ├── Message.cs
│ └── WeChatClient.cs
├── packages.config
└── tools
│ └── UniversalTool.cs
└── WechatTest
├── App.config
├── LoginForm.Designer.cs
├── LoginForm.cs
├── LoginForm.resx
├── Program.cs
├── Properties
├── AssemblyInfo.cs
├── Resources.Designer.cs
├── Resources.resx
├── Settings.Designer.cs
└── Settings.settings
├── Simsimi.cs
├── WechatTest.csproj
└── packages.config
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | [Xx]64/
19 | [Xx]86/
20 | [Bb]uild/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 |
85 | # Visual Studio profiler
86 | *.psess
87 | *.vsp
88 | *.vspx
89 | *.sap
90 |
91 | # TFS 2012 Local Workspace
92 | $tf/
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 | *.DotSettings.user
101 |
102 | # JustCode is a .NET coding add-in
103 | .JustCode
104 |
105 | # TeamCity is a build add-in
106 | _TeamCity*
107 |
108 | # DotCover is a Code Coverage Tool
109 | *.dotCover
110 |
111 | # NCrunch
112 | _NCrunch_*
113 | .*crunch*.local.xml
114 | nCrunchTemp_*
115 |
116 | # MightyMoose
117 | *.mm.*
118 | AutoTest.Net/
119 |
120 | # Web workbench (sass)
121 | .sass-cache/
122 |
123 | # Installshield output folder
124 | [Ee]xpress/
125 |
126 | # DocProject is a documentation generator add-in
127 | DocProject/buildhelp/
128 | DocProject/Help/*.HxT
129 | DocProject/Help/*.HxC
130 | DocProject/Help/*.hhc
131 | DocProject/Help/*.hhk
132 | DocProject/Help/*.hhp
133 | DocProject/Help/Html2
134 | DocProject/Help/html
135 |
136 | # Click-Once directory
137 | publish/
138 |
139 | # Publish Web Output
140 | *.[Pp]ublish.xml
141 | *.azurePubxml
142 |
143 | # TODO: Un-comment the next line if you do not want to checkin
144 | # your web deploy settings because they may include unencrypted
145 | # passwords
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # NuGet Packages
150 | *.nupkg
151 | # The packages folder can be ignored because of Package Restore
152 | **/packages/*
153 | # except build/, which is used as an MSBuild target.
154 | !**/packages/build/
155 | # Uncomment if necessary however generally it will be regenerated when needed
156 | #!**/packages/repositories.config
157 | # NuGet v3's project.json files produces more ignoreable files
158 | *.nuget.props
159 | *.nuget.targets
160 |
161 | # Microsoft Azure Build Output
162 | csx/
163 | *.build.csdef
164 |
165 | # Microsoft Azure Emulator
166 | ecf/
167 | rcf/
168 |
169 | # Microsoft Azure ApplicationInsights config file
170 | ApplicationInsights.config
171 |
172 | # Windows Store app package directory
173 | AppPackages/
174 | BundleArtifacts/
175 |
176 | # Visual Studio cache files
177 | # files ending in .cache can be ignored
178 | *.[Cc]ache
179 | # but keep track of directories ending in .cache
180 | !*.[Cc]ache/
181 |
182 | # Others
183 | ClientBin/
184 | [Ss]tyle[Cc]op.*
185 | ~$*
186 | *~
187 | *.dbmdl
188 | *.dbproj.schemaview
189 | *.pfx
190 | *.publishsettings
191 | node_modules/
192 | orleans.codegen.cs
193 |
194 | # RIA/Silverlight projects
195 | Generated_Code/
196 |
197 | # Backup & report files from converting an old project file
198 | # to a newer Visual Studio version. Backup files are not needed,
199 | # because we have git ;-)
200 | _UpgradeReport_Files/
201 | Backup*/
202 | UpgradeLog*.XML
203 | UpgradeLog*.htm
204 |
205 | # SQL Server files
206 | *.mdf
207 | *.ldf
208 |
209 | # Business Intelligence projects
210 | *.rdl.data
211 | *.bim.layout
212 | *.bim_*.settings
213 |
214 | # Microsoft Fakes
215 | FakesAssemblies/
216 |
217 | # GhostDoc plugin setting file
218 | *.GhostDoc.xml
219 |
220 | # Node.js Tools for Visual Studio
221 | .ntvs_analysis.dat
222 |
223 | # Visual Studio 6 build log
224 | *.plg
225 |
226 | # Visual Studio 6 workspace options file
227 | *.opt
228 |
229 | # Visual Studio LightSwitch build output
230 | **/*.HTMLClient/GeneratedArtifacts
231 | **/*.DesktopClient/GeneratedArtifacts
232 | **/*.DesktopClient/ModelManifest.xml
233 | **/*.Server/GeneratedArtifacts
234 | **/*.Server/ModelManifest.xml
235 | _Pvt_Extensions
236 |
237 | # LightSwitch generated files
238 | GeneratedArtifacts/
239 | ModelManifest.xml
240 |
241 | # Paket dependency manager
242 | .paket/paket.exe
243 |
244 | # FAKE - F# Make
245 | .fake/
--------------------------------------------------------------------------------
/Wechat.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26228.9
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wechat", "Wechat\Wechat.csproj", "{A48C55F5-02AB-49EA-B77A-F6A9CC81B1E4}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WechatTest", "WechatTest\WechatTest.csproj", "{7241DDB9-6CAF-4D68-8E06-FFAFBC1ACEFE}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {A48C55F5-02AB-49EA-B77A-F6A9CC81B1E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {A48C55F5-02AB-49EA-B77A-F6A9CC81B1E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {A48C55F5-02AB-49EA-B77A-F6A9CC81B1E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {A48C55F5-02AB-49EA-B77A-F6A9CC81B1E4}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {7241DDB9-6CAF-4D68-8E06-FFAFBC1ACEFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {7241DDB9-6CAF-4D68-8E06-FFAFBC1ACEFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {7241DDB9-6CAF-4D68-8E06-FFAFBC1ACEFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {7241DDB9-6CAF-4D68-8E06-FFAFBC1ACEFE}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/BaseRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class BaseRequest
10 | {
11 | public string Uin;
12 | public string Sid;
13 | public string Skey;
14 | public string DeviceID;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/BaseResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class BaseResponse
10 | {
11 | public int ret;
12 | public string ErrMsg;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/BatchGetContact/BatchGetContactRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 |
10 | public class BatchGetContactRequest
11 | {
12 | public BaseRequest BaseRequest;
13 | public int Count;
14 | public BatchUser[] List;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/BatchGetContact/BatchGetContactResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class BatchGetContactResponse
10 | {
11 | public BaseResponse BaseResponse;
12 | public int Count;
13 | public User[] ContactList;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/GetContact/GetContactResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class GetContactResponse
10 | {
11 | public BaseResponse BaseResponse;
12 | public int MemberCount;
13 | public User[] MemberList;
14 | public int Seq;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/SendMsg/SendMsgRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class SendMsgRequest
10 | {
11 | public BaseRequest BaseRequest;
12 | public Msg Msg;
13 | public long rr;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/SendMsg/SendMsgResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class SendMsgResponse
10 | {
11 | public BaseResponse BaseResponse;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/SendMsgImg/SendMsgImgRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class SendMsgImgRequest
10 | {
11 | public BaseRequest BaseRequest;
12 | public ImgMsg Msg;
13 | public int Scene;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/SendMsgImg/SendMsgImgResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class SendMsgImgResponse
10 | {
11 | public BaseResponse BaseResponse;
12 | public string MsgID;
13 | public long LocalID;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/Statusnotify/StatusnotifyRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class StatusnotifyRequest
10 | {
11 | public BaseRequest BaseRequest;
12 | public long ClientMsgId;
13 | public string FromUserName;
14 | public string ToUserName;
15 | public int Code;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/Statusnotify/StatusnotifyResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class StatusnotifyResponse
10 | {
11 | public BaseResponse BaseResponse;
12 | public long MsgID;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/Sync/SyncRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class SyncRequest
10 | {
11 | public BaseRequest BaseRequest;
12 | public SyncKey SyncKey;
13 | public long rr;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/Sync/SyncResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class SyncResponse
10 | {
11 | public BaseResponse BaseResponse;
12 | public int AddMsgCount;
13 | public AddMsg[] AddMsgList;
14 | public int ContinueFlag;
15 | public int DelContactCount;
16 | public User[] DelContactList;
17 | public int ModChatRoomMemberCount;
18 | //public ChatRoomMember[] ModChatRoomMemberList;
19 | public int ModContactCount;
20 | public User[] ModContactList;
21 | public string Skey;
22 | public SyncKey SyncKey;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/SyncCheck/SyncCheckResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class SyncCheckResponse
10 | {
11 | public string retcode;
12 | public string selector;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/Uploadmedia/UploadmediaRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class UploadmediaRequest
10 | {
11 | public int UploadType;
12 | public BaseRequest BaseRequest;
13 | public long ClientMediaId;
14 | public int TotalLen;
15 | public int StartPos;
16 | public int DataLen;
17 | public int MediaType;
18 | public string FromUserName;
19 | public string ToUserName;
20 | public string FileMd5;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/Uploadmedia/UploadmediaResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class UploadmediaResponse
10 | {
11 | public BaseResponse BaseResponse;
12 | public string MediaId;
13 | public int CDNThumbImgHeight;
14 | public int CDNThumbImgWidth;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/init/InitRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class InitRequest
10 | {
11 | public BaseRequest BaseRequest;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/init/initResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class InitResponse
10 | {
11 | public BaseResponse BaseResponse;
12 | public int Count;
13 | public User[] ContactList;
14 | public SyncKey SyncKey;
15 | public User User;
16 | public string ChatSet;
17 | public string SKey;
18 | public long ClientVersion;
19 | public long SystemTime;
20 | public int GrayScale;
21 | public int InviteStartCount;
22 | public int MPSubscribeMsgCount;
23 | //public MPSubscribeMsg[] MPSubscribeMsgList;
24 | public int ClickReportInterval;
25 |
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/oplog/OplogRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class OplogRequest
10 | {
11 | public BaseRequest BaseRequest;
12 | public int CmdId;
13 | public int OP;
14 | public string UserName;
15 | public string RemarkName;// 设置备注名,CmdId == 2时可用
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Wechat/API/RPC/oplog/OplogResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API.RPC
8 | {
9 | public class OplogResponse
10 | {
11 | public BaseResponse BaseResponse;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Wechat/API/Result/LoginRedirectResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API
8 | {
9 | public class LoginRedirectResult
10 | {
11 | public string skey;
12 | public string wxsid;
13 | public string wxuin;
14 | public string pass_ticket;
15 | public string isgrayscale;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Wechat/API/Result/LoginResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | namespace Wechat.API
7 | {
8 | public class LoginResult
9 | {
10 | ///
11 | /// 201: 已扫描但是未确认登录
12 | /// 200: 已确认登录
13 | ///
14 | public int code;
15 | ///
16 | /// 以base64编码的用户头像图片
17 | /// code=201 时可用
18 | ///
19 | public string UserAvatar;
20 | ///
21 | /// 登录重定向Url
22 | /// code=200 时可用
23 | ///
24 | public string redirect_uri;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Wechat/API/WechatAPIService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using Wechat.API.RPC;
5 | using System.Drawing;
6 | using System.IO;
7 | using Newtonsoft.Json;
8 | using Newtonsoft.Json.Linq;
9 | using System.Collections.Specialized;
10 | using System.Net.Http;
11 | using Wechat.tools;
12 | using System.Net;
13 | using System.Collections;
14 |
15 | namespace Wechat.API
16 | {
17 | public class WechatAPIService
18 | {
19 | HttpClientHandler mHandler;
20 | HttpClient mHttpClient;
21 | public WechatAPIService() {
22 | InitHttpClient();
23 | }
24 |
25 | private void InitHttpClient()
26 | {
27 | mHandler = new HttpClientHandler();
28 | mHandler.UseCookies = true;
29 | mHandler.AutomaticDecompression = DecompressionMethods.GZip;
30 | mHandler.AllowAutoRedirect = true;
31 | mHttpClient = new HttpClient(mHandler);
32 | mHttpClient.DefaultRequestHeaders.ExpectContinue = false;
33 | SetHttpHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
34 | SetHttpHeader("Accept-Language", "zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4,ja;q=0.2");
35 | SetHttpHeader("Accept-Encoding", "gzip, deflate, sdch, br");
36 | }
37 |
38 |
39 | ///
40 | /// 获得二维码登录SessionID,使用此ID可以获得登录二维码
41 | ///
42 | /// Session
43 | public string GetNewQRLoginSessionID()
44 | {
45 | //respone like this => window.QRLogin.code = 200; window.QRLogin.uuid = "Qa_GBH_IqA==";
46 | string url = "https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb";
47 |
48 | SetHttpHeader("Accept", "*/*");
49 | mHttpClient.DefaultRequestHeaders.Referrer = new Uri("https://wx.qq.com/");
50 |
51 | string str = GetString(url);
52 | if (str == null) return null;
53 | var pairs = str.Split(new string[] { "\"" }, StringSplitOptions.None);
54 | if (pairs.Length >= 2) {
55 | string sessionID = pairs[1];
56 | return sessionID;
57 | }
58 | return null;
59 | }
60 |
61 | ///
62 | /// 获得登录二维码URL
63 | ///
64 | ///
65 | ///
66 | public string GetQRCodeUrl(string QRLoginSessionID) {
67 | string url = "https://login.weixin.qq.com/qrcode/" + QRLoginSessionID;
68 | return url;
69 | }
70 |
71 | ///
72 | /// 获得登录二维码图片
73 | ///
74 | ///
75 | ///
76 | public Image GetQRCodeImage(string QRLoginSessionID)
77 | {
78 | string url = GetQRCodeUrl(QRLoginSessionID);
79 | SetHttpHeader("Accept", "image/webp,image/*,*/*;q=0.8");
80 | mHttpClient.DefaultRequestHeaders.Referrer = new Uri("https://wx.qq.com/");
81 | try
82 | {
83 | HttpResponseMessage response = mHttpClient.GetAsync(new Uri(url)).Result;
84 | var bytes = response.Content.ReadAsByteArrayAsync().Result;
85 | if (bytes != null && bytes.Length > 0) {
86 | return Image.FromStream(new MemoryStream(bytes));
87 | }
88 | return null;
89 | }
90 | catch {
91 | InitHttpClient();
92 | return null;
93 | }
94 |
95 | }
96 |
97 | ///
98 | /// 登录检查
99 | ///
100 | ///
101 | ///
102 | public LoginResult Login(string QRLoginSessionID,long t)
103 | {
104 | string url = string.Format("https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={0}&tip={1}&r={2}&_={3}",
105 | QRLoginSessionID,"0",t/1579,t);
106 |
107 | SetHttpHeader("Accept", "*/*");
108 | mHttpClient.DefaultRequestHeaders.Referrer = new Uri("https://wx.qq.com/");
109 |
110 |
111 | string login_result = GetString(url);
112 | if (login_result == null) return null;
113 |
114 | LoginResult result = new LoginResult();
115 | result.code = 408;
116 | if (login_result.Contains("window.code=201")) //已扫描 未登录
117 | {
118 | string base64_image = login_result.Split(new string[] { "\'" }, StringSplitOptions.None)[1].Split(',')[1];
119 | result.code = 201;
120 | result.UserAvatar = base64_image;
121 | } else if (login_result.Contains("window.code=200")) //已扫描 已登录
122 | {
123 | string login_redirect_url = login_result.Split(new string[] { "\"" }, StringSplitOptions.None)[1];
124 | result.code = 200;
125 | result.redirect_uri = login_redirect_url;
126 | }
127 |
128 | return result;
129 | }
130 |
131 | public LoginRedirectResult LoginRedirect(string redirect_uri)
132 | {
133 | SetHttpHeader("Accept", "application/json, text/plain, */*");
134 | SetHttpHeader("Connection", "keep-alive");
135 | mHttpClient.DefaultRequestHeaders.Referrer = new Uri("https://wx.qq.com/");
136 |
137 | string url = redirect_uri + "&fun=new&version=v2&lang=zh_CN";
138 | string rep = GetString(url);
139 | if (rep == null) return null;
140 |
141 | LoginRedirectResult result = new LoginRedirectResult();
142 | result.pass_ticket = rep.Split(new string[] { "pass_ticket" }, StringSplitOptions.None)[1].TrimStart('>').TrimEnd('<', '/');
143 | result.skey = rep.Split(new string[] { "skey" }, StringSplitOptions.None)[1].TrimStart('>').TrimEnd('<', '/');
144 | result.wxsid = rep.Split(new string[] { "wxsid" }, StringSplitOptions.None)[1].TrimStart('>').TrimEnd('<', '/');
145 | result.wxuin = rep.Split(new string[] { "wxuin" }, StringSplitOptions.None)[1].TrimStart('>').TrimEnd('<', '/');
146 | result.isgrayscale = rep.Split(new string[] { "isgrayscale" }, StringSplitOptions.None)[1].TrimStart('>').TrimEnd('<', '/');
147 | return result;
148 | }
149 |
150 | ///
151 | /// 初始化
152 | ///
153 | ///
154 | ///
155 | ///
156 | ///
157 | ///
158 | ///
159 | public InitResponse Init(string pass_ticket,BaseRequest baseReq)
160 | {
161 | SetHttpHeader("Accept", "application/json, text/plain, */*");
162 | SetHttpHeader("Connection", "keep-alive");
163 | SetHttpHeader("Accept-Encoding", "gzip, deflate, br");
164 | mHttpClient.DefaultRequestHeaders.Referrer = new Uri("https://wx.qq.com/");
165 |
166 | string url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r={0}&pass_ticket={1}";
167 | url = string.Format(url, getR(), pass_ticket);
168 | InitRequest initReq = new InitRequest();
169 | initReq.BaseRequest = baseReq;
170 | string requestJson = JsonConvert.SerializeObject(initReq);
171 | string repJsonStr = PostString(url, requestJson);
172 | if (repJsonStr == null) return null;
173 | var rep = JsonConvert.DeserializeObject(repJsonStr);
174 | return rep;
175 | }
176 |
177 | ///
178 | /// 获得联系人列表
179 | ///
180 | ///
181 | ///
182 | ///
183 |
184 | public GetContactResponse GetContact(string pass_ticket,string skey)
185 | {
186 | SetHttpHeader("Accept", "application/json, text/plain, */*");
187 | SetHttpHeader("Connection", "keep-alive");
188 | SetHttpHeader("Accept-Encoding", "gzip, deflate, br");
189 | string url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?pass_ticket={0}&r={1}&seq=0&skey={2}";
190 | url = string.Format(url, pass_ticket, getR(), skey);
191 | string json = GetString(url);
192 | var rep = JsonConvert.DeserializeObject(json);
193 | if (rep == null) return null;
194 | return rep;
195 | }
196 |
197 | ///
198 | /// 批量获取联系人详细信息
199 | ///
200 | ///
201 | ///
202 | ///
203 | ///
204 | ///
205 | ///
206 | ///
207 | public BatchGetContactResponse BatchGetContact(string[] requestContacts,string pass_ticket,BaseRequest baseReq)
208 | {
209 | SetHttpHeader("Accept", "application/json, text/plain, */*");
210 | SetHttpHeader("Connection", "keep-alive");
211 | SetHttpHeader("Accept-Encoding", "gzip, deflate, br");
212 | string url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r={0}&lang=zh_CN&pass_ticket={1}";
213 | url = string.Format(url, getR(), pass_ticket);
214 |
215 | BatchGetContactRequest req = new BatchGetContactRequest();
216 | req.BaseRequest = baseReq;
217 | req.Count = requestContacts.Length;
218 |
219 | List requestUsers = new List();
220 | for (int i = 0; i < req.Count; i++) {
221 | var tmp = new BatchUser();
222 | tmp.UserName = requestContacts[i];
223 | requestUsers.Add(tmp);
224 | }
225 |
226 | req.List = requestUsers.ToArray();
227 | string requestJson = JsonConvert.SerializeObject(req);
228 | string repJsonStr = PostString(url, requestJson);
229 | var rep = JsonConvert.DeserializeObject(repJsonStr);
230 | if (rep == null) return null;
231 | return rep;
232 | }
233 |
234 |
235 | public SyncCheckResponse SyncCheck(SyncItem[] syncItems,BaseRequest baseReq,long syncCheckTimes)
236 | {
237 | SetHttpHeader("Accept", "*/*");
238 | SetHttpHeader("Connection", "keep-alive");
239 | SetHttpHeader("Accept-Encoding", "gzip, deflate, br");
240 |
241 | string synckey = "";
242 | for (int i = 0; i < syncItems.Length; i++) {
243 | if (i != 0) {
244 | synckey += "|";
245 | }
246 | synckey += syncItems[i].Key + "_" + syncItems[i].Val;
247 | }
248 | string url = "https://webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck?skey={0}&sid={1}&uin={2}&deviceid={3}&synckey={4}&_={5}&r={6}";
249 | url = string.Format(url,UrlEncode(baseReq.Skey), UrlEncode(baseReq.Sid), baseReq.Uin, baseReq.DeviceID,synckey,syncCheckTimes,Util.GetTimeStamp());
250 | string repStr =GetString(url);
251 | if (repStr == null) return null;
252 | SyncCheckResponse rep = new SyncCheckResponse();
253 | if (repStr.StartsWith("window.synccheck="))
254 | {
255 | repStr = repStr.Substring("window.synccheck=".Length);
256 | rep = JsonConvert.DeserializeObject(repStr);
257 | }
258 |
259 | return rep;
260 | }
261 |
262 | static long getR() {
263 | return Util.GetTimeStamp();
264 | }
265 |
266 | public SyncResponse Sync(SyncKey syncKey,string pass_ticket,BaseRequest baseReq)
267 | {
268 | SetHttpHeader("Accept", "application/json, text/plain, */*");
269 | SetHttpHeader("Connection", "keep-alive");
270 | SetHttpHeader("Accept-Encoding", "gzip, deflate, br");
271 | SetHttpHeader("Origin", "https://wx.qq.com");
272 |
273 | string url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid={0}&skey={1}&lang=zh_CN&pass_ticket={2}";
274 | url = string.Format(url,baseReq.Sid,baseReq.Skey,pass_ticket);
275 | SyncRequest req = new SyncRequest();
276 | req.BaseRequest = baseReq;
277 | req.SyncKey = syncKey;
278 | req.rr = ~getR();
279 | string requestJson = JsonConvert.SerializeObject(req);
280 | string repJsonStr = PostString(url, requestJson);
281 | if (repJsonStr == null) return null;
282 | var rep = JsonConvert.DeserializeObject(repJsonStr);
283 |
284 |
285 |
286 |
287 | return rep;
288 | }
289 |
290 | public StatusnotifyResponse Statusnotify(string formUser,string toUser,string pass_ticket,BaseRequest baseReq)
291 | {
292 | SetHttpHeader("Accept", "application/json, text/plain, */*");
293 | SetHttpHeader("Connection", "keep-alive");
294 | SetHttpHeader("Accept-Encoding", "gzip, deflate, br");
295 | SetHttpHeader("Origin", "https://wx.qq.com");
296 |
297 | string url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify?lang=zh_CN&pass_ticket=" + pass_ticket;
298 | StatusnotifyRequest req = new StatusnotifyRequest();
299 | req.BaseRequest = baseReq;
300 | req.ClientMsgId = getR();
301 | req.FromUserName = formUser;
302 | req.ToUserName = toUser;
303 | req.Code = 3;
304 | string requestJson = JsonConvert.SerializeObject(req);
305 | string repJsonStr = PostString(url, requestJson);
306 | if (repJsonStr == null) return null;
307 | var rep = JsonConvert.DeserializeObject(repJsonStr);
308 | return rep;
309 | }
310 |
311 | public SendMsgResponse SendMsg(Msg msg, string pass_ticket,BaseRequest baseReq)
312 | {
313 | string url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?sid={0}&r={1}&lang=zh_CN&pass_ticket={2}";
314 | url = string.Format(url, baseReq.Sid, getR(), pass_ticket);
315 | SendMsgRequest req = new SendMsgRequest();
316 | req.BaseRequest = baseReq;
317 | req.Msg = msg;
318 | req.rr = DateTime.Now.Millisecond;
319 | string requestJson = JsonConvert.SerializeObject(req);
320 | string repJsonStr = PostString(url, requestJson);
321 | if (repJsonStr == null) return null;
322 | var rep = JsonConvert.DeserializeObject(repJsonStr);
323 | return rep;
324 | }
325 |
326 |
327 | public UploadmediaResponse Uploadmedia(string fromUserName,string toUserName,string id,string mime_type, int uploadType,int mediaType,byte[] buffer,string fileName,string pass_ticket,BaseRequest baseReq) {
328 | UploadmediaRequest req = new UploadmediaRequest();
329 | req.BaseRequest = baseReq;
330 | req.ClientMediaId = getR();
331 | req.DataLen = buffer.Length;
332 | req.StartPos = 0;
333 | req.TotalLen = buffer.Length;
334 | req.MediaType = mediaType;
335 | req.FromUserName = fromUserName;
336 | req.ToUserName = toUserName;
337 | req.UploadType = uploadType;
338 | req.FileMd5 = Util.getMD5(buffer);
339 |
340 | string url = "https://file.wx.qq.com/cgi-bin/mmwebwx-bin/webwxuploadmedia?f=json";
341 | string requestJson = JsonConvert.SerializeObject(req);
342 | string mt = "doc";
343 | if (mime_type.StartsWith("image/")) {
344 | mt = "pic";
345 | }
346 | var dataTicketCookie = GetCookie("webwx_data_ticket");
347 |
348 | var dataContent = new MultipartFormDataContent();
349 | dataContent.Add(new StringContent(id), "id");
350 | dataContent.Add(new StringContent(fileName), "name");
351 | dataContent.Add(new StringContent(mime_type), "type");
352 | dataContent.Add(new StringContent("Thu Mar 17 2016 14:35:28 GMT+0800 (中国标准时间)"), "lastModifiedDate");
353 | dataContent.Add(new StringContent(buffer.Length.ToString()), "size");
354 | dataContent.Add(new StringContent(mt), "mediatype");
355 | dataContent.Add(new StringContent(requestJson), "uploadmediarequest");
356 | dataContent.Add(new StringContent(dataTicketCookie.Value), "webwx_data_ticket");
357 | dataContent.Add(new StringContent(pass_ticket), "pass_ticket");
358 | dataContent.Add(new ByteArrayContent(buffer), "filename", fileName + "\r\n Content - Type: " + mime_type);
359 |
360 | try
361 | {
362 | var response = mHttpClient.PostAsync(url, dataContent).Result;
363 | string repJsonStr = response.Content.ReadAsStringAsync().Result;
364 | var rep = JsonConvert.DeserializeObject(repJsonStr);
365 | return rep;
366 | }
367 | catch {
368 | InitHttpClient();
369 | return null;
370 | }
371 |
372 | }
373 |
374 |
375 | public SendMsgImgResponse SendMsgImg(ImgMsg msg, string pass_ticket,BaseRequest baseReq)
376 | {
377 | string url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsgimg?fun=async&f=json&pass_ticket={0}";
378 | url = string.Format(url,pass_ticket);
379 | SendMsgImgRequest req = new SendMsgImgRequest();
380 | req.BaseRequest = baseReq;
381 | req.Msg = msg;
382 | req.Scene = 0;
383 | string requestJson = JsonConvert.SerializeObject(req);
384 | string repJsonStr = PostString(url, requestJson);
385 | if (repJsonStr == null) return null;
386 | var rep = JsonConvert.DeserializeObject(repJsonStr);
387 |
388 | return rep;
389 | }
390 |
391 |
392 |
393 | public OplogResponse Oplog(string userName,int cmdID,int op,string RemarkName, string pass_ticket,BaseRequest baseReq)
394 | {
395 | string url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxoplog?pass_ticket={0}";
396 | url = string.Format(url, pass_ticket);
397 | OplogRequest req = new OplogRequest();
398 | req.BaseRequest = baseReq;
399 | req.UserName = userName;
400 | req.CmdId = cmdID;
401 | req.OP = op;
402 | req.RemarkName = RemarkName;
403 | string requestJson = JsonConvert.SerializeObject(req);
404 | string repJsonStr = PostString(url, requestJson);
405 | if (repJsonStr == null) return null;
406 | var rep = JsonConvert.DeserializeObject(repJsonStr);
407 | return rep;
408 | }
409 |
410 | public void Logout(string skey,string sid,string uin)
411 | {
412 |
413 | string url = string.Format("https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxlogout?redirect=1&type=0&skey={0}", System.Web.HttpUtility.UrlEncode(skey));
414 | string requestStr = string.Format("sid={0}&uin={1}",sid,uin);
415 | SetHttpHeader("Cache-Control", "max-age=0");
416 | SetHttpHeader("Upgrade-Insecure-Requests", "1");
417 | SetHttpHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
418 | SetHttpHeader("Referer", "https://wx.qq.com/");
419 | PostString(url, requestStr);
420 |
421 | url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxlogout?redirect=1&type=1&skey=" + System.Web.HttpUtility.UrlEncode(skey);
422 | PostString(url, requestStr);
423 |
424 | mHttpClient.DefaultRequestHeaders.Remove("Cache-Control");
425 | mHttpClient.DefaultRequestHeaders.Remove("Upgrade-Insecure-Requests");
426 | }
427 |
428 |
429 |
430 | private string GetString(string url)
431 | {
432 | // try
433 | // {
434 | HttpResponseMessage response = mHttpClient.GetAsync(new Uri(url)).Result;
435 | string ret = response.Content.ReadAsStringAsync().Result;
436 | response.Dispose();
437 | return ret;
438 | // }
439 | //catch {
440 | // InitHttpClient();
441 | // return null;
442 | //}
443 |
444 | }
445 |
446 | private string PostString(string url, string content)
447 | {
448 | //try
449 | //{
450 | HttpResponseMessage response = mHttpClient.PostAsync(new Uri(url), new StringContent(content)).Result;
451 | string ret = response.Content.ReadAsStringAsync().Result;
452 | response.Dispose();
453 | return ret;
454 | //}
455 | //catch
456 | // {
457 | // InitHttpClient();
458 | // return null;
459 | // }
460 |
461 | }
462 |
463 | ///
464 | /// 获取指定cookie
465 | ///
466 | ///
467 | ///
468 | public Cookie GetCookie(string name)
469 | {
470 | List cookies = GetAllCookies(mHandler.CookieContainer);
471 | foreach (Cookie c in cookies)
472 | {
473 | if (c.Name == name)
474 | {
475 | return c;
476 | }
477 | }
478 | return null;
479 | }
480 |
481 | private static List GetAllCookies(CookieContainer cc)
482 | {
483 | List lstCookies = new List();
484 |
485 | Hashtable table = (Hashtable)cc.GetType().InvokeMember("m_domainTable",
486 | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField |
487 | System.Reflection.BindingFlags.Instance, null, cc, new object[] { });
488 |
489 | foreach (object pathList in table.Values)
490 | {
491 | SortedList lstCookieCol = (SortedList)pathList.GetType().InvokeMember("m_list",
492 | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField
493 | | System.Reflection.BindingFlags.Instance, null, pathList, new object[] { });
494 | foreach (CookieCollection colCookies in lstCookieCol.Values)
495 | foreach (Cookie c in colCookies) lstCookies.Add(c);
496 | }
497 | return lstCookies;
498 | }
499 |
500 |
501 | private void SetHttpHeader(string name,string value)
502 | {
503 | if (mHttpClient.DefaultRequestHeaders.Contains(name)) {
504 | mHttpClient.DefaultRequestHeaders.Remove(name);
505 | }
506 |
507 | mHttpClient.DefaultRequestHeaders.Add(name, value);
508 | }
509 | string UrlEncode(string url)
510 | {
511 | return System.Web.HttpUtility.UrlEncode(url);
512 | }
513 |
514 | }
515 |
516 |
517 | }
518 |
--------------------------------------------------------------------------------
/Wechat/API/Wx/AddMsg.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API
8 | {
9 | public class AddMsg
10 | {
11 | public AppInfo AppInfo;
12 | public int AppMsgType;
13 | public string Content;
14 | public long CreateTime;
15 | public string FileName;
16 | public string FileSize;
17 | public int ForwardFlag;
18 | public string FromUserName;
19 | public int HasProductId;
20 | public int ImgHeight;
21 | public int ImgWidth;
22 | public int ImgStatus;
23 | public string MediaId;
24 | public string MsgId;
25 | public int MsgType;
26 | public string NewMsgId;
27 | public int PlayLength;
28 | public RecommendInfo RecommendInfo;
29 | public int Status;
30 | public int StatusNotifyCode;
31 | public string StatusNotifyUserName;
32 | public int SubMsgType;
33 | public string Ticket;
34 | public string ToUserName;
35 | public string Url;
36 | public int VoiceLength;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Wechat/API/Wx/AppInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API
8 | {
9 | public class AppInfo
10 | {
11 | public string AppID;
12 | public int Type;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Wechat/API/Wx/BatchUser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API
8 | {
9 | public class BatchUser
10 | {
11 | public string UserName;
12 | public int ChatRoomId;
13 | public string EncryChatRoomId;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Wechat/API/Wx/ImgMsg.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API
8 | {
9 | public class ImgMsg
10 | {
11 | public long ClientMsgId;
12 | public long LocalID;
13 | public string FromUserName;
14 | public string ToUserName;
15 | public int Type;//3
16 | public string MediaId;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Wechat/API/Wx/Msg.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API
8 | {
9 | public class Msg
10 | {
11 | public long ClientMsgId;
12 | public long LocalID;
13 | public string Content;
14 | public string FromUserName;
15 | public string ToUserName;
16 | public int Type;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Wechat/API/Wx/RecommendInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API
8 | {
9 | public class RecommendInfo
10 | {
11 | public string Alias;
12 | public int AttrStatus;
13 | public string City;
14 | public string Content;
15 | public string NickName;
16 | public int OpCode;
17 | public string Province;
18 | public int QQNum;
19 | public int Scene;
20 | public int Sex;
21 | public string Signature;
22 | public string Ticket;
23 | public string UserName;
24 | public int VerifyFlag;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Wechat/API/Wx/SyncKey.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API
8 | {
9 | public class SyncItem {
10 | public int Key;
11 | public int Val;
12 | }
13 | public class SyncKey
14 | {
15 | public int Count;
16 | public SyncItem[] List;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Wechat/API/Wx/User.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat.API
8 | {
9 | public class User
10 | {
11 | public long Uin;
12 | public string UserName;
13 | public string NickName;
14 | public string HeadImgUrl;
15 | public int ContactFlag;
16 | public int MemberCount;
17 | public User[] MemberList;
18 | public string RemarkName;
19 | public int Sex;
20 | public string Signature;
21 | public int VerifyFlag;
22 | public int OwnerUin;
23 | public string PYInitial;
24 | public string PYQuanPin;
25 | public string RemarkPYInitial;
26 | public string RemarkPYQuanPin;
27 | public int StarFriend;
28 | public int AppAccountFlag;
29 | public int Statues;
30 | public long AttrStatus;
31 | public string Province;
32 | public string City;
33 | public string Alias;
34 | public int SnsFlag;
35 | public int UniFriend;
36 | public string DisplayName;
37 | public int ChatRoomId;
38 | public string KeyWord;
39 | public string EncryChatRoomId;
40 |
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Wechat/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("Wechat")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Wechat")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | //将 ComVisible 设置为 false 将使此程序集中的类型
18 | //对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
19 | //请将此类型的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("a48c55f5-02ab-49ea-b77a-f6a9cc81b1e4")]
24 |
25 | // 程序集的版本信息由下列四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
33 | // 方法是按如下所示使用“*”: :
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Wechat/Wechat.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {A48C55F5-02AB-49EA-B77A-F6A9CC81B1E4}
8 | Library
9 | Properties
10 | Wechat
11 | Wechat
12 | v4.5.2
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 | ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
35 | True
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
100 |
--------------------------------------------------------------------------------
/Wechat/Wechat/Contact.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat
8 | {
9 | public class Contact
10 | {
11 | public virtual string NickName { get; set; }
12 | public string ID { get; set; }
13 | public string RemarkName { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Wechat/Wechat/Events.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Wechat
9 | {
10 |
11 | public class WeChatClientEvent : EventArgs { }
12 |
13 |
14 | public class GetQRCodeImageEvent : WeChatClientEvent
15 | {
16 | public Image QRImage;
17 | }
18 |
19 | public class UserScanQRCodeEvent : WeChatClientEvent
20 | {
21 | public Image UserAvatarImage;
22 | }
23 |
24 | public class LoginSucessEvent : WeChatClientEvent
25 | {
26 |
27 | }
28 |
29 | public class InitedEvent : WeChatClientEvent
30 | {
31 |
32 | }
33 |
34 | public class AddMessageEvent:WeChatClientEvent
35 | {
36 | public Message Msg;
37 | }
38 |
39 | public class StatusChangedEvent:WeChatClientEvent
40 | {
41 | public ClientStatusType FromStatus;
42 | public ClientStatusType ToStatus;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Wechat/Wechat/Group.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat
8 | {
9 | public class Group : Contact
10 | {
11 |
12 | public override string NickName
13 | {
14 | get {
15 | if (string.IsNullOrWhiteSpace(base.NickName)) {
16 | if (Members != null && Members.Length > 0) {
17 | int max = Members.Length > 4 ? 4 : Members.Length;
18 | string newName = "";
19 | for (int i = 0; i < max; i++) {
20 | newName = newName + Members[i].NickName;
21 | if (i != max - 1) newName += ",";
22 | }
23 | base.NickName = newName;
24 | }
25 | }
26 | return base.NickName;
27 | }
28 |
29 | set
30 | {
31 | base.NickName = value;
32 | }
33 | }
34 |
35 | public Contact[] Members { get; set; }
36 |
37 | public Contact GetMember(string ID)
38 | {
39 | if (Members == null) return null;
40 | for (int i = 0; i < Members.Length; i++)
41 | {
42 | if (Members[i].ID == ID) return Members[i];
43 | }
44 | return null;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Wechat/Wechat/Message.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Wechat
8 | {
9 | public class Message
10 | {
11 | public string FromContactID;
12 | public string ToContactD;
13 | }
14 |
15 |
16 | public class TextMessage : Message
17 | {
18 | public string Content;
19 | }
20 |
21 | public class DefaultMessage: Message
22 | {
23 | public int MsgType;
24 | public string Content;
25 | }
26 |
27 | public class MessageFactory
28 | {
29 | public static Message CreateMessage(Wechat.API.AddMsg msg)
30 | {
31 | //MsgType
32 | //1 文本消息
33 | //3 图片消息
34 | //34 语音消息
35 | //37 VERIFYMSG
36 | //40 POSSIBLEFRIEND_MSG
37 | //42 共享名片
38 | //43 视频通话消息
39 | //47 动画表情
40 | //48 位置消息
41 | //49 分享链接
42 | //50 VOIPMSG
43 | //51 微信初始化消息
44 | //52 VOIPNOTIFY
45 | //53 VOIPINVITE
46 | //62 小视频
47 | //9999 SYSNOTICE
48 | //10000 系统消息
49 | //10002 撤回消息
50 |
51 | Message ret = null;
52 |
53 | if (msg.MsgType == 1) {
54 | ret = new TextMessage() {
55 | Content = msg.Content
56 | };
57 |
58 | }
59 |
60 | if (ret == null)
61 | {
62 | ret = new DefaultMessage()
63 | {
64 | MsgType = msg.MsgType,
65 | Content = msg.Content
66 | };
67 | }
68 | ret.FromContactID = msg.FromUserName;
69 | ret.ToContactD = msg.ToUserName;
70 | return ret;
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Wechat/Wechat/WeChatClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 | using System.Drawing.Imaging;
4 | using System.IO;
5 | using Wechat.API;
6 | using Wechat.API.RPC;
7 | using System.Collections.Generic;
8 | using Wechat.tools;
9 |
10 | namespace Wechat
11 | {
12 |
13 | public enum ClientStatusType
14 | {
15 | GetUUID,
16 | GetQRCode,
17 | Login,
18 | QRCodeScaned,
19 | WeixinInit,
20 | SyncCheck,
21 | WeixinSync,
22 | None,
23 | }
24 |
25 |
26 | public class WeChatClient
27 | {
28 |
29 |
30 |
31 | public Action OnEvent;
32 |
33 |
34 | public Contact Self { get; private set; }
35 |
36 | public bool IsLogin { get; private set; }
37 |
38 | public ClientStatusType CurrentStatus
39 | {
40 | get
41 | {
42 | return mStatus;
43 | }
44 | private set
45 | {
46 | if (mStatus != value)
47 | {
48 | var changedEvent = new StatusChangedEvent()
49 | {
50 | FromStatus = mStatus,
51 | ToStatus = value
52 | };
53 | mStatus = value;
54 | OnEvent?.Invoke(this, changedEvent);
55 | }
56 | }
57 | }
58 |
59 |
60 |
61 | private List mContacts;
62 |
63 | public Contact[] Contacts
64 | {
65 | get{
66 | return mContacts.ToArray();
67 | }
68 | private set {
69 | mContacts = new List();
70 | mContacts.AddRange(value);
71 | }
72 | }
73 |
74 | private List mGroups;
75 | public Group[] Groups
76 | {
77 | get {
78 | return mGroups.ToArray();
79 | }
80 | private set
81 | {
82 | mGroups = new List();
83 | mGroups.AddRange(value);
84 | }
85 | }
86 |
87 | public Group GetGroup(string ID)
88 | {
89 | if (mGroups == null) return null;
90 | return mGroups.FindLast((group) => {
91 | return group.ID == ID;
92 | });
93 | }
94 |
95 | public Contact GetContact(string ID)
96 | {
97 | if (ID == Self.ID) return Self;
98 | if (mContacts == null) return null;
99 | return mContacts.FindLast((contact) =>
100 | {
101 | return contact.ID == ID;
102 | });
103 | }
104 |
105 | /*
106 | * Web Weixin Pipeline
107 | +--------------+ +---------------+ +---------------+
108 | | | | | | |
109 | | Get UUID | | Get Contact | | Status Notify |
110 | | | | | | |
111 | +-------+------+ +-------^-------+ +-------^-------+
112 | | | |
113 | | +-------+ +--------+
114 | | | |
115 | +-------v------+ +-----+--+------+ +--------------+
116 | | | | | | |
117 | | Get QRCode | | Weixin Init +------> Sync Check<----+
118 | | | | | | | |
119 | +-------+------+ +-------^-------+ +-------+------+ |
120 | | | | |
121 | | | +-----------+
122 | | | |
123 | +-------v------+ +-------+--------+ +-------v-------+
124 | | | Confirm Login | | | |
125 | +------> Login +---------------> New Login Page | | Weixin Sync |
126 | | | | | | | |
127 | | +------+-------+ +----------------+ +---------------+
128 | | |
129 | |QRCode Scaned|
130 | +-------------+
131 | */
132 |
133 | private System.Threading.Thread mMainLoopThread;
134 | private ClientStatusType mStatus = ClientStatusType.None;
135 | public void Run()
136 | {
137 | Quit();
138 | mIsQuit = false;
139 | IsLogin = false;
140 | CurrentStatus = ClientStatusType.GetUUID;
141 | mAPIService = new WechatAPIService();
142 | mMainLoopThread = new System.Threading.Thread(MainLoop);
143 | mMainLoopThread.Start();
144 | }
145 |
146 | public void Quit(bool force = false)
147 | {
148 | mIsQuit = true;
149 | Logout();
150 | if (force) {
151 | if (mMainLoopThread != null && mMainLoopThread.IsAlive) {
152 | mMainLoopThread.Abort();
153 | }
154 | }
155 | }
156 |
157 |
158 |
159 | private bool mIsQuit = false;
160 | private WechatAPIService mAPIService = null;
161 | private string mPass_ticket;
162 | private BaseRequest mBaseReq;
163 | private string mLoginSession;
164 | private void MainLoop()
165 | {
166 | while (!mIsQuit)
167 | {
168 | HandleStatus();
169 | }
170 | }
171 |
172 |
173 |
174 | #region StatusHandle
175 |
176 | private void HandleStatus()
177 | {
178 | switch (CurrentStatus)
179 | {
180 | case ClientStatusType.GetUUID:
181 | HandleGetLoginSession();
182 | break;
183 | case ClientStatusType.GetQRCode:
184 | HandleGetQRCode();
185 | break;
186 | case ClientStatusType.Login:
187 | HandleLogin();
188 | break;
189 | case ClientStatusType.QRCodeScaned:
190 | HandleQRCodeScaned();
191 | break;
192 | case ClientStatusType.WeixinInit:
193 | HandleInit();
194 | break;
195 |
196 | case ClientStatusType.WeixinSync:
197 | HandleSync();
198 | break;
199 | }
200 | }
201 |
202 |
203 | private void HandleGetLoginSession()
204 | {
205 | IsLogin = false;
206 | mLoginSession = mAPIService.GetNewQRLoginSessionID();
207 | if (!string.IsNullOrWhiteSpace(mLoginSession))
208 | {
209 | CurrentStatus = ClientStatusType.GetQRCode;
210 | }
211 | }
212 |
213 | private void HandleGetQRCode()
214 | {
215 | var QRCodeImg = mAPIService.GetQRCodeImage(mLoginSession);
216 | if (QRCodeImg != null)
217 | {
218 | CurrentStatus = ClientStatusType.Login;
219 | var wce = new GetQRCodeImageEvent()
220 | {
221 | QRImage = QRCodeImg
222 | };
223 | OnEvent?.Invoke(this, wce);
224 | }
225 | else {
226 | CurrentStatus = ClientStatusType.GetUUID;
227 | }
228 | }
229 |
230 |
231 |
232 | private void HandleLogin()
233 | {
234 | var loginResult = mAPIService.Login(mLoginSession,Util.GetTimeStamp());
235 | if (loginResult!=null && loginResult.code == 201)
236 | {
237 | // 已扫描,但是未确认登录
238 | // convert base64 to image
239 | byte[] base64_image_bytes = Convert.FromBase64String(loginResult.UserAvatar);
240 | MemoryStream memoryStream = new MemoryStream(base64_image_bytes, 0, base64_image_bytes.Length);
241 | memoryStream.Write(base64_image_bytes, 0, base64_image_bytes.Length);
242 | var image = Image.FromStream(memoryStream);
243 | OnEvent?.Invoke(this, new UserScanQRCodeEvent()
244 | {
245 | UserAvatarImage = image
246 | });
247 |
248 | CurrentStatus = ClientStatusType.QRCodeScaned;
249 | }
250 | else
251 | {
252 | CurrentStatus = ClientStatusType.GetUUID;
253 | }
254 | }
255 |
256 | private long mSyncCheckTimes = 0;
257 | private void HandleQRCodeScaned()
258 | {
259 | mSyncCheckTimes = Util.GetTimeStamp();
260 | var loginResult = mAPIService.Login(mLoginSession,mSyncCheckTimes);
261 | if (loginResult != null && loginResult.code == 200)
262 | {
263 | // 登录成功
264 | var redirectResult = mAPIService.LoginRedirect(loginResult.redirect_uri);
265 | mBaseReq = new BaseRequest();
266 | mBaseReq.Skey = redirectResult.skey;
267 | mBaseReq.Sid = redirectResult.wxsid;
268 | mBaseReq.Uin = redirectResult.wxuin;
269 | mBaseReq.DeviceID = CreateNewDeviceID();
270 | mPass_ticket = redirectResult.pass_ticket;
271 | CurrentStatus = ClientStatusType.WeixinInit;
272 | OnEvent?.Invoke(this, new LoginSucessEvent());
273 | }
274 | else
275 | {
276 | CurrentStatus = ClientStatusType.GetUUID;
277 | }
278 | }
279 |
280 |
281 | private void HandleInit()
282 | {
283 | var initResult = mAPIService.Init(mPass_ticket, mBaseReq);
284 | if (initResult!=null && initResult.BaseResponse.ret == 0)
285 | {
286 | Self = CreateContact(initResult.User);
287 | mSyncKey = initResult.SyncKey;
288 | // 开启系统通知
289 | var statusNotifyRep = mAPIService.Statusnotify(Self.ID, Self.ID, mPass_ticket, mBaseReq);
290 | if (statusNotifyRep != null && statusNotifyRep.BaseResponse != null && statusNotifyRep.BaseResponse.ret == 0)
291 | {
292 | CurrentStatus = ClientStatusType.WeixinSync;
293 | IsLogin = true;
294 | }
295 | else {
296 | CurrentStatus = ClientStatusType.GetUUID;
297 | return;
298 | }
299 | }
300 | else
301 | {
302 | CurrentStatus = ClientStatusType.GetUUID;
303 | return;
304 | }
305 |
306 | if (!InitContactAndGroups()) {
307 | CurrentStatus = ClientStatusType.WeixinInit;
308 | IsLogin = false;
309 | return;
310 | }
311 |
312 |
313 | OnEvent?.Invoke(this, new InitedEvent());
314 |
315 | }
316 |
317 |
318 | private bool InitContactAndGroups()
319 | {
320 | mContacts = new List();
321 | mGroups = new List();
322 |
323 | var contactResult = mAPIService.GetContact(mPass_ticket, mBaseReq.Skey);
324 | if (contactResult == null || contactResult.BaseResponse == null || contactResult.BaseResponse.ret != 0){
325 | return false;
326 | }
327 |
328 | List groupIDs = new List();
329 | foreach (var user in contactResult.MemberList)
330 | {
331 | if (user.UserName.StartsWith("@@")){
332 | groupIDs.Add(user.UserName);
333 | }
334 | else {
335 | var contact = CreateContact(user);
336 | mContacts.Add(contact);
337 | }
338 | }
339 |
340 | if (groupIDs.Count <= 0) return true;
341 | // 批量获得群成员详细信息
342 | var batchResult = mAPIService.BatchGetContact(groupIDs.ToArray(), mPass_ticket, mBaseReq);
343 | if (batchResult == null || batchResult.BaseResponse.ret != 0) return false;
344 |
345 | foreach (var user in batchResult.ContactList)
346 | {
347 | if (!user.UserName.StartsWith("@@") || user.MemberCount <= 0) continue;
348 | Group group = new Group();
349 | group.ID = user.UserName;
350 | group.NickName = user.NickName;
351 | group.RemarkName = user.RemarkName;
352 | List groupMembers = new List();
353 | foreach (var member in user.MemberList)
354 | {
355 | groupMembers.Add(CreateContact(member));
356 | }
357 | group.Members = groupMembers.ToArray();
358 | mGroups.Add(group);
359 | }
360 |
361 | return true;
362 | }
363 |
364 |
365 | private SyncKey mSyncKey;
366 | private void HandleSync()
367 | {
368 | if (mSyncKey == null) {
369 | CurrentStatus = ClientStatusType.GetUUID;
370 | return;
371 | }
372 | if (mSyncKey.Count <= 0) return;
373 |
374 | var checkResult = mAPIService.SyncCheck(mSyncKey.List, mBaseReq,++mSyncCheckTimes);
375 | if (checkResult == null) return;
376 |
377 |
378 | if (checkResult.retcode!=null && checkResult.retcode != "0") {
379 | CurrentStatus = ClientStatusType.GetUUID;
380 | return;
381 | }
382 | if (checkResult.selector == "0") return;
383 | var syncResult = mAPIService.Sync(mSyncKey, mPass_ticket, mBaseReq);
384 | if (syncResult == null) return;
385 | mSyncKey = syncResult.SyncKey;
386 |
387 | // 处理同步
388 | ProcessSyncResult(syncResult);
389 |
390 | }
391 |
392 | private void ProcessSyncResult(SyncResponse result)
393 | {
394 | // 处理消息
395 | if (result.AddMsgCount > 0) {
396 | foreach (var msg in result.AddMsgList)
397 | {
398 | var message = MessageFactory.CreateMessage(msg);
399 | OnEvent?.Invoke(this, new AddMessageEvent() {
400 | Msg = message
401 | });
402 | }
403 | }
404 | }
405 |
406 | #endregion
407 |
408 |
409 | private static string CreateNewDeviceID()
410 | {
411 | Random ran = new Random();
412 | int rand1 = ran.Next(10000, 99999);
413 | int rand2 = ran.Next(10000, 99999);
414 | int rand3 = ran.Next(10000, 99999);
415 | return string.Format("e{0}{1}{2}", rand1, rand2, rand3);
416 | }
417 |
418 |
419 | public Contact CreateContact(Wechat.API.User user)
420 | {
421 |
422 | Contact contact = new Contact();
423 | contact.ID = user.UserName;
424 | contact.NickName = user.NickName;
425 | contact.RemarkName = user.RemarkName;
426 | return contact;
427 | }
428 |
429 | public Contact[] GetGroupMembers(string groupID)
430 | {
431 |
432 | //获取群聊成员
433 | var batchResult = mAPIService.BatchGetContact(new string[] { groupID}, mPass_ticket, mBaseReq);
434 | if (batchResult == null || batchResult.BaseResponse.ret != 0) return null;
435 |
436 | List members = new List();
437 | foreach(var contact in batchResult.ContactList)
438 | {
439 | if (contact.UserName.StartsWith("@@")) continue;
440 | members.Add(CreateContact(contact));
441 | }
442 |
443 | return members.ToArray();
444 |
445 | }
446 |
447 |
448 |
449 | ///
450 | /// 置顶群聊
451 | ///
452 | ///
453 | public bool StickyPost(string groupUserName)
454 | {
455 | var rep = mAPIService.Oplog(groupUserName, 3, 0, null, mPass_ticket, mBaseReq);
456 | return rep.BaseResponse.ret == 0;
457 | }
458 |
459 | public bool SetRemarkName(string id, string remarkName)
460 | {
461 | var contact = GetContact(id);
462 | if (contact == null) return false;
463 | var rep = mAPIService.Oplog(id, 2, 0, remarkName, mPass_ticket, mBaseReq);
464 | if (rep.BaseResponse.ret == 0) {
465 | contact.RemarkName = remarkName;
466 | return true;
467 | }
468 | return false;
469 | }
470 |
471 |
472 | public bool SendMsg(string toUserName, string content)
473 | {
474 | Msg msg = new Msg();
475 | msg.FromUserName = Self.ID;
476 | msg.ToUserName = toUserName;
477 | msg.Content = content;
478 | msg.ClientMsgId = DateTime.Now.Millisecond;
479 | msg.LocalID = DateTime.Now.Millisecond;
480 | msg.Type = 1;//type 1 文本消息
481 | var response = mAPIService.SendMsg(msg, mPass_ticket, mBaseReq);
482 | if (response != null && response.BaseResponse != null && response.BaseResponse.ret == 0)
483 | {
484 | return true;
485 | }
486 | else
487 | {
488 | return false;
489 | }
490 | }
491 |
492 | int upLoadMediaCount = 0;
493 |
494 | public bool SendMsg(string toUserName, Image img, ImageFormat format = null, string imageName = null)
495 | {
496 | if (img == null) return false;
497 | string fileName = imageName != null ? imageName : "img_" + upLoadMediaCount;
498 | var imgFormat = format != null ? format : ImageFormat.Png;
499 |
500 | fileName += "." + imgFormat.ToString().ToLower();
501 |
502 | MemoryStream ms = new MemoryStream();
503 | img.Save(ms, imgFormat);
504 | ms.Seek(0, SeekOrigin.Begin);
505 | byte[] data = new byte[ms.Length];
506 | int readCount = ms.Read(data, 0, data.Length);
507 | if (readCount != data.Length) return false;
508 |
509 | string mimetype = "image/" + imgFormat.ToString().ToLower();
510 | var response = mAPIService.Uploadmedia(Self.ID, toUserName, "WU_FILE_" + upLoadMediaCount, mimetype, 2, 4, data, fileName, mPass_ticket, mBaseReq);
511 | if (response != null && response.BaseResponse != null && response.BaseResponse.ret == 0)
512 | {
513 | upLoadMediaCount++;
514 | string mediaId = response.MediaId;
515 | ImgMsg msg = new ImgMsg();
516 | msg.FromUserName = Self.ID;
517 | msg.ToUserName = toUserName;
518 | msg.MediaId = mediaId;
519 | msg.ClientMsgId = DateTime.Now.Millisecond;
520 | msg.LocalID = DateTime.Now.Millisecond;
521 | msg.Type = 3;
522 | var sendImgRep = mAPIService.SendMsgImg(msg, mPass_ticket, mBaseReq);
523 | if (sendImgRep != null && sendImgRep.BaseResponse != null && sendImgRep.BaseResponse.ret == 0)
524 | {
525 | return true;
526 | }
527 | return false;
528 | }
529 | else
530 | {
531 | return false;
532 | }
533 | }
534 |
535 | public void Logout()
536 | {
537 | if (!IsLogin || mMainLoopThread==null || !mMainLoopThread.IsAlive) return;
538 | mAPIService.Logout(mBaseReq.Skey, mBaseReq.Sid, mBaseReq.Uin);
539 | IsLogin = false;
540 | mContacts = null;
541 | mGroups = null;
542 | CurrentStatus = ClientStatusType.GetUUID;
543 | }
544 | }
545 | }
546 |
--------------------------------------------------------------------------------
/Wechat/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Wechat/tools/UniversalTool.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Cryptography;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Wechat.tools
9 | {
10 | public class Util
11 | {
12 | public static string getMD5(byte[] data) {
13 |
14 | MD5 md5Hash = MD5.Create();
15 | var hash = md5Hash.ComputeHash(data);
16 |
17 | // 创建一个 Stringbuilder 来收集字节并创建字符串
18 | StringBuilder sBuilder = new StringBuilder();
19 |
20 | // 循环遍历哈希数据的每一个字节并格式化为十六进制字符串
21 | for (int i = 0; i < hash.Length; i++) {
22 | sBuilder.Append(hash[i].ToString("x2"));
23 | }
24 |
25 | // 返回十六进制字符串
26 | return sBuilder.ToString();
27 |
28 | }
29 |
30 | ///
31 | /// 获取时间戳
32 | ///
33 | ///
34 | public static long GetTimeStamp()
35 | {
36 | TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
37 | return Convert.ToInt64(ts.TotalMilliseconds);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/WechatTest/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/WechatTest/LoginForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace WechatTest
2 | {
3 | partial class LoginForm
4 | {
5 | ///
6 | /// 必需的设计器变量。
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// 清理所有正在使用的资源。
12 | ///
13 | /// 如果应释放托管资源,为 true;否则为 false。
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null)) {
17 | components.Dispose();
18 | }
19 | base.Dispose(disposing);
20 | }
21 |
22 | #region Windows 窗体设计器生成的代码
23 |
24 | ///
25 | /// 设计器支持所需的方法 - 不要修改
26 | /// 使用代码编辑器修改此方法的内容。
27 | ///
28 | private void InitializeComponent()
29 | {
30 | this.pictureBox_qr = new System.Windows.Forms.PictureBox();
31 | this.comboBox_users = new System.Windows.Forms.ComboBox();
32 | this.button_send_msg_txt = new System.Windows.Forms.Button();
33 | this.textBox_msg_text = new System.Windows.Forms.TextBox();
34 | this.button_send_msg_image = new System.Windows.Forms.Button();
35 | this.label_status = new System.Windows.Forms.Label();
36 | this.button_refreshGroupMemberInfo = new System.Windows.Forms.Button();
37 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox_qr)).BeginInit();
38 | this.SuspendLayout();
39 | //
40 | // pictureBox_qr
41 | //
42 | this.pictureBox_qr.Location = new System.Drawing.Point(77, 50);
43 | this.pictureBox_qr.Name = "pictureBox_qr";
44 | this.pictureBox_qr.Size = new System.Drawing.Size(228, 202);
45 | this.pictureBox_qr.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
46 | this.pictureBox_qr.TabIndex = 0;
47 | this.pictureBox_qr.TabStop = false;
48 | //
49 | // comboBox_users
50 | //
51 | this.comboBox_users.FormattingEnabled = true;
52 | this.comboBox_users.Location = new System.Drawing.Point(12, 312);
53 | this.comboBox_users.Name = "comboBox_users";
54 | this.comboBox_users.Size = new System.Drawing.Size(365, 20);
55 | this.comboBox_users.TabIndex = 1;
56 | //
57 | // button_send_msg_txt
58 | //
59 | this.button_send_msg_txt.Location = new System.Drawing.Point(153, 352);
60 | this.button_send_msg_txt.Name = "button_send_msg_txt";
61 | this.button_send_msg_txt.Size = new System.Drawing.Size(99, 23);
62 | this.button_send_msg_txt.TabIndex = 2;
63 | this.button_send_msg_txt.Text = "发送文字消息";
64 | this.button_send_msg_txt.UseVisualStyleBackColor = true;
65 | this.button_send_msg_txt.Click += new System.EventHandler(this.button_send_msg_txt_Click);
66 | //
67 | // textBox_msg_text
68 | //
69 | this.textBox_msg_text.Location = new System.Drawing.Point(24, 353);
70 | this.textBox_msg_text.Name = "textBox_msg_text";
71 | this.textBox_msg_text.Size = new System.Drawing.Size(123, 21);
72 | this.textBox_msg_text.TabIndex = 3;
73 | //
74 | // button_send_msg_image
75 | //
76 | this.button_send_msg_image.Location = new System.Drawing.Point(258, 352);
77 | this.button_send_msg_image.Name = "button_send_msg_image";
78 | this.button_send_msg_image.Size = new System.Drawing.Size(119, 23);
79 | this.button_send_msg_image.TabIndex = 4;
80 | this.button_send_msg_image.Text = "发送图片消息";
81 | this.button_send_msg_image.UseVisualStyleBackColor = true;
82 | this.button_send_msg_image.Click += new System.EventHandler(this.button_send_msg_image_Click);
83 | //
84 | // label_status
85 | //
86 | this.label_status.Location = new System.Drawing.Point(12, 256);
87 | this.label_status.Name = "label_status";
88 | this.label_status.Size = new System.Drawing.Size(350, 53);
89 | this.label_status.TabIndex = 5;
90 | this.label_status.Text = "扫描二维码登陆微信";
91 | this.label_status.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
92 | //
93 | // button_refreshGroupMemberInfo
94 | //
95 | this.button_refreshGroupMemberInfo.Location = new System.Drawing.Point(24, 381);
96 | this.button_refreshGroupMemberInfo.Name = "button_refreshGroupMemberInfo";
97 | this.button_refreshGroupMemberInfo.Size = new System.Drawing.Size(107, 23);
98 | this.button_refreshGroupMemberInfo.TabIndex = 6;
99 | this.button_refreshGroupMemberInfo.Text = "设置备注名";
100 | this.button_refreshGroupMemberInfo.UseVisualStyleBackColor = true;
101 | this.button_refreshGroupMemberInfo.Click += new System.EventHandler(this.button_refreshGroupMemberInfo_Click);
102 | //
103 | // LoginForm
104 | //
105 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
106 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
107 | this.ClientSize = new System.Drawing.Size(411, 461);
108 | this.Controls.Add(this.button_refreshGroupMemberInfo);
109 | this.Controls.Add(this.label_status);
110 | this.Controls.Add(this.button_send_msg_image);
111 | this.Controls.Add(this.textBox_msg_text);
112 | this.Controls.Add(this.button_send_msg_txt);
113 | this.Controls.Add(this.comboBox_users);
114 | this.Controls.Add(this.pictureBox_qr);
115 | this.Name = "LoginForm";
116 | this.Text = "WeChat";
117 | this.Load += new System.EventHandler(this.Form1_Load);
118 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox_qr)).EndInit();
119 | this.ResumeLayout(false);
120 | this.PerformLayout();
121 |
122 | }
123 |
124 | #endregion
125 |
126 | private System.Windows.Forms.PictureBox pictureBox_qr;
127 | private System.Windows.Forms.ComboBox comboBox_users;
128 | private System.Windows.Forms.Button button_send_msg_txt;
129 | private System.Windows.Forms.TextBox textBox_msg_text;
130 | private System.Windows.Forms.Button button_send_msg_image;
131 | private System.Windows.Forms.Label label_status;
132 | private System.Windows.Forms.Button button_refreshGroupMemberInfo;
133 | }
134 | }
135 |
136 |
--------------------------------------------------------------------------------
/WechatTest/LoginForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 | using Wechat.API.Http;
11 | using Wechat.API;
12 | using Wechat;
13 | using System.IO;
14 | using System.Text.RegularExpressions;
15 | using System.Diagnostics;
16 |
17 | namespace WechatTest
18 | {
19 | public partial class LoginForm : Form
20 | {
21 |
22 | WechatClient wc;
23 |
24 | public LoginForm()
25 | {
26 | InitializeComponent();
27 | }
28 |
29 |
30 | /// 清除文本中Html的标签
31 | ///
32 | ///
33 | ///
34 | protected string ClearHtml(string Content)
35 | {
36 | Content = Zxj_ReplaceHtml("[^>]*;", "", Content);
37 | Content = Zxj_ReplaceHtml("?marquee[^>]*>", "", Content);
38 | Content = Zxj_ReplaceHtml("?object[^>]*>", "", Content);
39 | Content = Zxj_ReplaceHtml("?param[^>]*>", "", Content);
40 | Content = Zxj_ReplaceHtml("?embed[^>]*>", "", Content);
41 | Content = Zxj_ReplaceHtml("?table[^>]*>", "", Content);
42 | Content = Zxj_ReplaceHtml(" ", "", Content);
43 | Content = Zxj_ReplaceHtml("?tr[^>]*>", "", Content);
44 | Content = Zxj_ReplaceHtml("?th[^>]*>", "", Content);
45 | Content = Zxj_ReplaceHtml("?p[^>]*>", "", Content);
46 | Content = Zxj_ReplaceHtml("?a[^>]*>", "", Content);
47 | Content = Zxj_ReplaceHtml("?img[^>]*>", "", Content);
48 | Content = Zxj_ReplaceHtml("?tbody[^>]*>", "", Content);
49 | Content = Zxj_ReplaceHtml("?li[^>]*>", "", Content);
50 | Content = Zxj_ReplaceHtml("?span[^>]*>", "", Content);
51 | Content = Zxj_ReplaceHtml("?div[^>]*>", "", Content);
52 | Content = Zxj_ReplaceHtml("?th[^>]*>", "", Content);
53 | Content = Zxj_ReplaceHtml("?td[^>]*>", "", Content);
54 | Content = Zxj_ReplaceHtml("?script[^>]*>", "", Content);
55 | Content = Zxj_ReplaceHtml("(javascript|jscript|vbscript|vbs):", "", Content);
56 | Content = Zxj_ReplaceHtml("on(mouse|exit|error|click|key)", "", Content);
57 | Content = Zxj_ReplaceHtml("<\\?xml[^>]*>", "", Content);
58 | Content = Zxj_ReplaceHtml("<\\/?[a-z]+:[^>]*>", "", Content);
59 | Content = Zxj_ReplaceHtml("?font[^>]*>", "", Content);
60 | Content = Zxj_ReplaceHtml("?b[^>]*>", "", Content);
61 | Content = Zxj_ReplaceHtml("?u[^>]*>", "", Content);
62 | Content = Zxj_ReplaceHtml("?i[^>]*>", "", Content);
63 | Content = Zxj_ReplaceHtml("?strong[^>]*>", "", Content);
64 | string clearHtml = Content;
65 | return clearHtml;
66 | }
67 |
68 | ///
69 | /// 清除文本中的Html标签
70 | ///
71 | /// 要替换的标签正则表达式
72 | /// 替换为的内容
73 | /// 要替换的内容
74 | ///
75 | private string Zxj_ReplaceHtml(string patrn, string strRep, string content)
76 | {
77 | if (string.IsNullOrEmpty(content)) {
78 | content = "";
79 | }
80 | Regex rgEx = new Regex(patrn, RegexOptions.IgnoreCase);
81 | string strTxt = rgEx.Replace(content, strRep);
82 | return strTxt;
83 | }
84 |
85 |
86 | private void Form1_Load(object sender, EventArgs e)
87 | {
88 | comboBox_users.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
89 | comboBox_users.AutoCompleteSource = AutoCompleteSource.ListItems;
90 |
91 | wc = new WechatClient();
92 | wc.OnGetQRCodeImage = (image) => {
93 | RunInMainthread(()=> {
94 | pictureBox_qr.Image = image;
95 | });
96 | };
97 |
98 | wc.OnUserScanQRCode = (image) => {
99 | RunInMainthread(() => {
100 |
101 | pictureBox_qr.Image = image;
102 | label_status.Text = "扫描成功\n请在手机上确认登陆";
103 | });
104 | };
105 |
106 | wc.OnLoginSucess = () => {
107 | RunInMainthread(()=> {
108 | label_status.Text = "已确认,正在登陆....";
109 | });
110 | };
111 |
112 | wc.OnInitComplate = () => {
113 | RunInMainthread(() => {
114 | label_status.Text = wc.CurrentUser.NickName+"("+wc.CurrentUser.Alias+")";
115 | });
116 | };
117 |
118 | wc.OnRecvMsg = (msg) => {
119 | if (msg.ToUserName == wc.CurrentUser.UserName && !msg.FromUserName.StartsWith("@@")) {
120 | System.Diagnostics.Debug.WriteLine("RecvMsg:" + msg.Content + " from " + msg.FromUserName);
121 | string rep = "";
122 | if (msg.Content == "1") {
123 | rep = "你";
124 | }
125 | if (msg.Content == "2") {
126 | rep = "你好";
127 | }
128 | if (msg.Content == "3") {
129 | rep = "你好吗";
130 | }
131 | //var rep = Simsimi.say(msg.Content);
132 | wc.SendMsg(msg.FromUserName, rep);
133 | System.Diagnostics.Debug.WriteLine("SendMsg:" + rep + " to " + msg.FromUserName);
134 | }
135 | };
136 |
137 | wc.OnAddUser = (user) => {
138 | RunInMainthread(() => {
139 | string nickName = ClearHtml(user.NickName);
140 | comboBox_users.Items.Add(nickName + "|" + user.UserName);
141 | });
142 | };
143 |
144 |
145 | RunAsync(()=>{
146 | wc.Run();
147 | });
148 | }
149 |
150 |
151 |
152 | void RunAsync(Action action) {
153 | ((Action)(delegate () {
154 | action?.Invoke();
155 | })).BeginInvoke(null, null);
156 | }
157 |
158 | void RunInMainthread(Action action) {
159 | this.BeginInvoke((Action)(delegate () {
160 | action?.Invoke();
161 | }));
162 | }
163 |
164 | private void button_send_msg_txt_Click(object sender, EventArgs e)
165 | {
166 | string str = comboBox_users.Text;
167 | var args = str.Split('|');
168 | if (args.Length == 2) {
169 | string userName = args[1];
170 | wc.SendMsg(userName,textBox_msg_text.Text);
171 | }
172 | }
173 |
174 | private void button_send_msg_image_Click(object sender, EventArgs e)
175 | {
176 | string str = comboBox_users.Text;
177 | var args = str.Split('|');
178 | if (args.Length == 2) {
179 | string userName = args[1];
180 | OpenFileDialog ofd = new OpenFileDialog();
181 | if (ofd.ShowDialog() == DialogResult.OK) {
182 | if (File.Exists(ofd.FileName)) {
183 | var img = Image.FromFile(ofd.FileName);
184 | if (wc.SendMsg(userName, img)) {
185 | Debug.WriteLine("图片消息发送成功!");
186 | } else {
187 | Debug.WriteLine("图片消息发送失败!");
188 | }
189 | }
190 | }
191 |
192 | }
193 | }
194 |
195 | private void button_refreshGroupMemberInfo_Click(object sender, EventArgs e)
196 | {
197 | string str = comboBox_users.Text;
198 | var args = str.Split('|');
199 | if (args.Length == 2) {
200 | string userName = args[1];
201 | bool ret = wc.SetRemarkName(userName, "HelloSB");
202 | MessageBox.Show("设置备注名:" + ret);
203 | }
204 | }
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/WechatTest/LoginForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/WechatTest/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using System.Windows.Forms;
6 |
7 | namespace WechatTest
8 | {
9 | static class Program
10 | {
11 | ///
12 | /// 应用程序的主入口点。
13 | ///
14 | [STAThread]
15 | static void Main()
16 | {
17 | Application.EnableVisualStyles();
18 | Application.SetCompatibleTextRenderingDefault(false);
19 | Application.Run(new LoginForm());
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/WechatTest/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("WechatTest")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("WechatTest")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | //将 ComVisible 设置为 false 将使此程序集中的类型
18 | //对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
19 | //请将此类型的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("7241ddb9-6caf-4d68-8e06-ffafbc1acefe")]
24 |
25 | // 程序集的版本信息由下列四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
33 | // 方法是按如下所示使用“*”: :
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/WechatTest/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本: 4.0.30319.42000
5 | //
6 | // 对此文件的更改可能导致不正确的行为,如果
7 | // 重新生成代码,则所做更改将丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace WechatTest.Properties
12 | {
13 |
14 |
15 | ///
16 | /// 强类型资源类,用于查找本地化字符串等。
17 | ///
18 | // 此类是由 StronglyTypedResourceBuilder
19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
20 | // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen
21 | // (以 /str 作为命令选项),或重新生成 VS 项目。
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// 返回此类使用的缓存 ResourceManager 实例。
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null)) {
46 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WechatTest.Properties.Resources", typeof(Resources).Assembly);
47 | resourceMan = temp;
48 | }
49 | return resourceMan;
50 | }
51 | }
52 |
53 | ///
54 | /// 覆盖当前线程的 CurrentUICulture 属性
55 | /// 使用此强类型的资源类的资源查找。
56 | ///
57 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
58 | internal static global::System.Globalization.CultureInfo Culture
59 | {
60 | get
61 | {
62 | return resourceCulture;
63 | }
64 | set
65 | {
66 | resourceCulture = value;
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/WechatTest/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/WechatTest/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace WechatTest.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/WechatTest/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/WechatTest/Simsimi.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Wechat.API.Http;
7 | using Newtonsoft.Json;
8 | using Newtonsoft.Json.Linq;
9 | namespace WechatTest
10 | {
11 |
12 | public class SimsimiResponse
13 | {
14 | public string response;
15 | public string id;
16 | public int result;
17 | public string msg;
18 | }
19 |
20 | public static class Simsimi
21 | {
22 |
23 | public static SimsimiResponse say(string word)
24 | {
25 | HttpClient http = new HttpClient();
26 | string url = "http://api.simsimi.com/request.p?key=your_paid_key&lc=zh&ft=1.0&text=" + word;
27 | string ret = http.GET_UTF8String(url);
28 | var rep = JsonConvert.DeserializeObject(ret);
29 | return rep;
30 | }
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/WechatTest/WechatTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {7241DDB9-6CAF-4D68-8E06-FFAFBC1ACEFE}
8 | WinExe
9 | Properties
10 | WechatTest
11 | WechatTest
12 | v4.5.2
13 | 512
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 | ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
38 | True
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | Form
55 |
56 |
57 | LoginForm.cs
58 |
59 |
60 |
61 |
62 |
63 | LoginForm.cs
64 |
65 |
66 | ResXFileCodeGenerator
67 | Resources.Designer.cs
68 | Designer
69 |
70 |
71 | True
72 | Resources.resx
73 |
74 |
75 |
76 | SettingsSingleFileGenerator
77 | Settings.Designer.cs
78 |
79 |
80 | True
81 | Settings.settings
82 | True
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | {a48c55f5-02ab-49ea-b77a-f6a9cc81b1e4}
91 | Wechat
92 |
93 |
94 |
95 |
102 |
--------------------------------------------------------------------------------
/WechatTest/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------