├── .gitignore ├── Communications ├── ZKPush.cs ├── ZKPushManager.cs └── ZKPushRequest.cs ├── Events ├── DeviceEventArgs.cs ├── DeviceMessageEventArgs.cs └── ServerLogEventArgs.cs ├── ExampleZKPush.csproj ├── ExampleZKPush.sln ├── LICENSE ├── Models ├── Biophoto.cs ├── IProtocol.cs ├── Templatev10.cs ├── Transaction.cs ├── User.cs ├── UserAuthorize.cs └── UserExtended.cs ├── Program.cs ├── README.md ├── frmMAIN.Designer.cs ├── frmMAIN.cs └── frmMAIN.resx /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /obj 3 | .vs -------------------------------------------------------------------------------- /Communications/ZKPush.cs: -------------------------------------------------------------------------------- 1 | using ExampleZKPush.Events; 2 | using ExampleZKPush.Models; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Text; 8 | using System.Threading; 9 | 10 | namespace ExampleZKPush.Communications 11 | { 12 | public class ZKPush 13 | { 14 | #region Communication Control 15 | 16 | public string SerialNumber { get; private set; } 17 | private DateTime TimeWait { get; set; } 18 | private ZKPushRequest CommunicationRequest { get; set; } 19 | 20 | private readonly object _lockRequest = new object(); 21 | 22 | public event EventHandler DeviceMessageEventHandler; 23 | 24 | public ZKPush(string serialNumber) 25 | { 26 | SerialNumber = serialNumber; 27 | } 28 | 29 | public void ProcessRequest(HttpListenerContext context) 30 | { 31 | var bytes = new byte[262144]; // 256 kb 32 | 33 | var bytesRead = context.Request.InputStream.Read(bytes, 0, bytes.Length); 34 | 35 | var data = Encoding.ASCII.GetString(bytes, 0, bytesRead); 36 | 37 | var rawUrl = context.Request.RawUrl; 38 | 39 | DeviceMessageEventHandler?.Invoke(this, new DeviceMessageEventArgs() 40 | { 41 | SerialNumber = SerialNumber, 42 | Message = $"{DateTime.Now:HH:mm:ss} - {rawUrl}" 43 | }); 44 | 45 | lock (_lockRequest) 46 | { 47 | VerifyRequest(context, rawUrl, data); 48 | } 49 | } 50 | 51 | private void VerifyRequest(HttpListenerContext context, string route, string data) 52 | { 53 | if (route.Contains("/iclock/registry")) 54 | { 55 | var registryCode = DateTime.Now.ToString("MMddHHmmss"); 56 | 57 | AnswerRequest(context, $"RegistryCode={registryCode}"); 58 | } 59 | else if (route.Contains("/iclock/push")) 60 | { 61 | var parameters = ConfigureParameters(); 62 | 63 | AnswerRequest(context, parameters); 64 | } 65 | else if (route.Contains("/iclock/getrequest")) 66 | { 67 | if (CommunicationRequest?.StateRequest == ZKPushRequest.TStateRequest.AwaitingTransmission) 68 | { 69 | CommunicationRequest.StateRequest = ZKPushRequest.TStateRequest.AwaitingResponse; 70 | 71 | AnswerRequest(context, CommunicationRequest.CommandText); 72 | } 73 | else 74 | { 75 | AnswerRequest(context, "OK"); 76 | } 77 | } 78 | else if (route.Contains("/iclock/ping")) 79 | { 80 | TimeWait = DateTime.Now; 81 | 82 | AnswerRequest(context, "OK"); 83 | } 84 | else if (route.Contains("/iclock/devicecmd")) 85 | { 86 | if (CommunicationRequest != null) 87 | { 88 | CommunicationRequest.StateRequest = ZKPushRequest.TStateRequest.Completed; 89 | CommunicationRequest.ReponseCommand = data; 90 | } 91 | 92 | AnswerRequest(context, "OK"); 93 | } 94 | else if (route.Contains("/iclock/querydata")) 95 | { 96 | if (CommunicationRequest != null) 97 | { 98 | if (!string.IsNullOrEmpty(CommunicationRequest.ResponseData)) 99 | { 100 | CommunicationRequest.ResponseData += "\r\n"; 101 | } 102 | 103 | CommunicationRequest.ResponseData += data; 104 | } 105 | 106 | AnswerRequest(context, "OK"); 107 | } 108 | else 109 | { 110 | AnswerRequest(context, "OK"); 111 | } 112 | } 113 | 114 | private void AnswerRequest(HttpListenerContext context, string data) 115 | { 116 | var bytes = Encoding.ASCII.GetBytes(data); 117 | 118 | context.Response.Headers.Add("Connection", "close"); 119 | context.Response.ContentType = "text/plain;charset=UTF-8"; 120 | context.Response.ContentLength64 = bytes.Length; 121 | context.Response.OutputStream.Write(bytes, 0, bytes.Length); 122 | context.Response.OutputStream.Close(); 123 | } 124 | 125 | private void AwaitRequest() 126 | { 127 | TimeWait = DateTime.Now; 128 | 129 | while (CommunicationRequest.StateRequest != ZKPushRequest.TStateRequest.Completed && 130 | DateTime.Now.Subtract(TimeWait).TotalSeconds < 10) 131 | { 132 | Thread.Sleep(100); 133 | } 134 | 135 | if (CommunicationRequest.StateRequest != ZKPushRequest.TStateRequest.Completed) 136 | { 137 | DeviceMessageEventHandler?.Invoke(this, new DeviceMessageEventArgs() 138 | { 139 | SerialNumber = SerialNumber, 140 | Message = "REQUEST_TIMEOUT" 141 | }); 142 | 143 | return; 144 | } 145 | 146 | var listResponse = TreatReceivedResponse(CommunicationRequest.ReponseCommand); 147 | 148 | foreach (var response in listResponse) 149 | { 150 | var returnCode = Convert.ToInt32(response["Return"]); 151 | 152 | DeviceMessageEventHandler?.Invoke(this, new DeviceMessageEventArgs() 153 | { 154 | SerialNumber = SerialNumber, 155 | Message = $"RETURN_CODE: {returnCode}" 156 | }); 157 | } 158 | } 159 | 160 | private string ConfigureParameters() 161 | { 162 | var pushParameters = new StringBuilder(); 163 | 164 | pushParameters.AppendLine("ServerVersion=3.0.1"); 165 | pushParameters.AppendLine("ServerName=ADMS"); 166 | pushParameters.AppendLine("PushVersion=3.0.1"); 167 | pushParameters.AppendLine("ErrorDelay=10"); 168 | pushParameters.AppendLine("RequestDelay=3"); 169 | pushParameters.AppendLine("TransInterval=1"); 170 | pushParameters.AppendLine("TransTables=User Transaction Facev7 templatev10"); 171 | pushParameters.AppendLine("TimeZone=-3"); 172 | pushParameters.AppendLine("RealTime=1"); 173 | pushParameters.AppendLine("TimeoutSec=10"); 174 | 175 | return pushParameters.ToString(); 176 | } 177 | 178 | private void SendCommand(string command) 179 | { 180 | CommunicationRequest = new ZKPushRequest() 181 | { 182 | CommandText = command 183 | }; 184 | 185 | AwaitRequest(); 186 | } 187 | 188 | private void SendCommand(List listData) 189 | { 190 | var listCommands = new List(); 191 | 192 | var commandIndex = 0; 193 | 194 | foreach (var data in listData) 195 | { 196 | commandIndex++; 197 | 198 | listCommands.Add($"C:{commandIndex}:DATA UPDATE {data.GetTableName()} {data.ToProtocol()}"); 199 | } 200 | 201 | CommunicationRequest = new ZKPushRequest() 202 | { 203 | CommandText = string.Join("\r\n", listCommands) 204 | }; 205 | 206 | AwaitRequest(); 207 | } 208 | 209 | private List> TreatReceivedResponse(string text) 210 | { 211 | var listResponse = new List>(); 212 | 213 | foreach (var response in text.Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries)) 214 | { 215 | var listText = response.Split('&'); 216 | 217 | var dictionaryData = CreateResponseDictionary(listText); 218 | 219 | listResponse.Add(dictionaryData); 220 | } 221 | 222 | return listResponse; 223 | } 224 | 225 | private Dictionary TreatReceivedData(string text) 226 | { 227 | var listText = text.Split('\t'); 228 | 229 | var dictionaryData = CreateResponseDictionary(listText); 230 | 231 | return dictionaryData; 232 | } 233 | 234 | private Dictionary TreatReceivedConfigurations(string text) 235 | { 236 | // Some properties has "~" in the name. 237 | var listText = text.Replace("~", "").Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries); 238 | 239 | var dictionaryData = CreateResponseDictionary(listText); 240 | 241 | return dictionaryData; 242 | } 243 | 244 | private Dictionary CreateResponseDictionary(string[] response) 245 | { 246 | var dictionaryData = new Dictionary(); 247 | 248 | foreach (var item in response) 249 | { 250 | var listText = item.Split('='); 251 | 252 | dictionaryData.Add(listText[0], listText[1]); 253 | } 254 | 255 | return dictionaryData; 256 | } 257 | 258 | #endregion 259 | 260 | #region Maintenance Date and Time 261 | 262 | public void SendDateAndTime() 263 | { 264 | SendCommand($"C:1:SET OPTIONS DateTime={GetDateAndTimeInSeconds()}"); 265 | } 266 | 267 | private int GetDateAndTimeInSeconds() 268 | { 269 | var utc = DateTime.UtcNow; 270 | 271 | var result = ((utc.Year - 2000) * 12 * 31 + ((utc.Month - 1) * 31) + utc.Day - 1) 272 | * (24 * 60 * 60) + (utc.Hour * 60 + utc.Minute) * 60 + utc.Second; 273 | 274 | return result; 275 | } 276 | 277 | private DateTime GetDateAndTimeFromSeconds(int segs) 278 | { 279 | var seconds = segs % 60; 280 | 281 | segs /= 60; 282 | 283 | var minutos = segs % 60; 284 | 285 | segs /= 60; 286 | 287 | var horas = segs % 24; 288 | 289 | segs /= 24; 290 | 291 | var dias = segs % 31 + 1; 292 | 293 | segs /= 31; 294 | 295 | var meses = segs % 12 + 1; 296 | 297 | segs /= 12; 298 | 299 | var anos = segs + 2000; 300 | 301 | return new DateTime(anos, meses, dias, horas, minutos, seconds); 302 | } 303 | 304 | #endregion 305 | 306 | #region Maintenance Users 307 | 308 | public void SendUsers() 309 | { 310 | var listUsers = GetUserList(); 311 | 312 | SendCommand(listUsers); 313 | 314 | var listUserExtended = GetUserExtendedList(); 315 | 316 | SendCommand(listUserExtended); 317 | 318 | var listUserAuthorize = GetUserAuthorizeList(); 319 | 320 | SendCommand(listUserAuthorize); 321 | } 322 | 323 | public void ReceiveUsers() 324 | { 325 | SendCommand("C:1:DATA QUERY tablename=user,fielddesc=*,filter=*"); 326 | 327 | var users = CommunicationRequest.ResponseData.Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries); 328 | 329 | var listUsers = new List(); 330 | 331 | foreach (var user in users) 332 | { 333 | var dicionaryUser = TreatReceivedData(user); 334 | 335 | listUsers.Add(new User() 336 | { 337 | Name = dicionaryUser["name"], 338 | Pin = int.Parse(dicionaryUser["pin"]), 339 | Password = dicionaryUser["password"], 340 | Privilege = (User.TPrivilege)int.Parse(dicionaryUser["privilege"]) 341 | }); 342 | } 343 | 344 | foreach (var user in listUsers) 345 | { 346 | DeviceMessageEventHandler?.Invoke(this, new DeviceMessageEventArgs() 347 | { 348 | SerialNumber = SerialNumber, 349 | Message = $"USER: PIN - {user.Pin} - NAME - {user.Name}" 350 | }); 351 | } 352 | } 353 | 354 | private List GetUserList() 355 | { 356 | var listUsers = new List(); 357 | 358 | foreach (var code in Enumerable.Range(1, 10)) 359 | { 360 | listUsers.Add(new User() 361 | { 362 | Pin = code, 363 | CardNumber = code, 364 | Name = $"User {code}", 365 | Password = code.ToString(), 366 | Privilege = User.TPrivilege.CommonUser 367 | }); 368 | } 369 | 370 | return listUsers; 371 | } 372 | 373 | private List GetUserExtendedList() 374 | { 375 | var listUsersExtended = new List(); 376 | 377 | foreach (var code in Enumerable.Range(1, 10)) 378 | { 379 | listUsersExtended.Add(new UserExtended() 380 | { 381 | Pin = code, 382 | FirstName = $"User {code}", 383 | }); 384 | } 385 | 386 | return listUsersExtended; 387 | } 388 | 389 | private List GetUserAuthorizeList() 390 | { 391 | var listUsersAuthorize = new List(); 392 | 393 | foreach (var code in Enumerable.Range(1, 10)) 394 | { 395 | listUsersAuthorize.Add(new UserAuthorize() 396 | { 397 | Pin = code 398 | }); 399 | } 400 | 401 | return listUsersAuthorize; 402 | } 403 | 404 | #endregion 405 | 406 | #region Maintenance Transactions 407 | 408 | public void ReceiveTransactions() 409 | { 410 | SendCommand("C:1:DATA QUERY tablename=transaction,fielddesc=*,filter=*"); 411 | 412 | var transactions = CommunicationRequest.ResponseData.Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries); 413 | 414 | var listTransactions = new List(); 415 | 416 | foreach (var transaction in transactions) 417 | { 418 | var listData = transaction.Split('\t'); 419 | 420 | var transactionDictionary = CreateResponseDictionary(listData); 421 | 422 | listTransactions.Add(new Transaction() 423 | { 424 | Pin = int.Parse(transactionDictionary["pin"]), 425 | CardNumber = int.Parse(transactionDictionary["transaction cardno"]), 426 | EventType = int.Parse(transactionDictionary["eventtype"]), 427 | InOutState = int.Parse(transactionDictionary["inoutstate"]), 428 | DoorId = int.Parse(transactionDictionary["doorid"]), 429 | Verified = int.Parse(transactionDictionary["verified"]), 430 | DateAndTime = GetDateAndTimeFromSeconds(int.Parse(transactionDictionary["time_second"])) 431 | }); 432 | } 433 | 434 | foreach (var transaction in listTransactions) 435 | { 436 | DeviceMessageEventHandler?.Invoke(this, new DeviceMessageEventArgs() 437 | { 438 | SerialNumber = SerialNumber, 439 | Message = $"TRANSACTION: PIN - {transaction.Pin} - DATETIME - {transaction.DateAndTime}" 440 | }); 441 | } 442 | } 443 | 444 | #endregion 445 | 446 | #region Maintenance Biometrics 447 | 448 | public void ReceiveTemplates() 449 | { 450 | SendCommand("C:1:DATA QUERY tablename=templatev10,fielddesc=*,filter=*"); 451 | 452 | var templates = CommunicationRequest.ResponseData.Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries); 453 | 454 | var listTemplates = new List(); 455 | 456 | foreach (var template in templates) 457 | { 458 | var listData = template.Split('\t'); 459 | 460 | var templateDictionary = CreateResponseDictionary(listData); 461 | 462 | listTemplates.Add(new Templatev10() 463 | { 464 | Pin = int.Parse(templateDictionary["pin"]), 465 | FingerId = int.Parse(templateDictionary["fingerid"]), 466 | Valid = int.Parse(templateDictionary["valid"]), 467 | Template = templateDictionary["template"] 468 | }); 469 | } 470 | 471 | foreach (var template in listTemplates) 472 | { 473 | DeviceMessageEventHandler?.Invoke(this, new DeviceMessageEventArgs() 474 | { 475 | SerialNumber = SerialNumber, 476 | Message = $"TEMPLATEV10: PIN - {template.Pin} - FINGER_ID - {template.FingerId}" 477 | }); 478 | } 479 | } 480 | 481 | public void ReceiveBiophotos() 482 | { 483 | SendCommand("C:1:DATA QUERY tablename=biophoto,fielddesc=*,filter=*"); 484 | 485 | var biophotos = CommunicationRequest.ResponseData.Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries); 486 | 487 | var listBiophotos = new List(); 488 | 489 | foreach (var biophoto in biophotos) 490 | { 491 | var listData = biophoto.Split('\t'); 492 | 493 | var templateDictionary = CreateResponseDictionary(listData); 494 | 495 | listBiophotos.Add(new Biophoto() 496 | { 497 | Pin = int.Parse(templateDictionary["biophoto pin"]), 498 | Size = int.Parse(templateDictionary["size"]), 499 | FileName = templateDictionary["filename"], 500 | Content = templateDictionary["content"], 501 | }); 502 | } 503 | 504 | foreach (var biophoto in listBiophotos) 505 | { 506 | DeviceMessageEventHandler?.Invoke(this, new DeviceMessageEventArgs() 507 | { 508 | SerialNumber = SerialNumber, 509 | Message = $"BIOPHOTO: PIN - {biophoto.Pin} - FILE_NAME - {biophoto.FileName}" 510 | }); 511 | } 512 | } 513 | 514 | #endregion 515 | 516 | #region Maintenance Options 517 | 518 | public void GetOptions() 519 | { 520 | SendCommand("C:1:GET OPTIONS ~DeviceName,FirmVer,IPAddress,NetMask,GATEIPAddress"); 521 | 522 | var configurationDictionary = TreatReceivedConfigurations(CommunicationRequest.ResponseData); 523 | 524 | foreach (var configuration in configurationDictionary) 525 | { 526 | DeviceMessageEventHandler?.Invoke(this, new DeviceMessageEventArgs() 527 | { 528 | SerialNumber = SerialNumber, 529 | Message = $"OPTIONS: {configuration.Key} - {configuration.Value}" 530 | }); 531 | } 532 | } 533 | 534 | #endregion 535 | } 536 | } 537 | -------------------------------------------------------------------------------- /Communications/ZKPushManager.cs: -------------------------------------------------------------------------------- 1 | using ExampleZKPush.Events; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Net; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace ExampleZKPush.Communications 9 | { 10 | public class ZKPushManager 11 | { 12 | public Dictionary ControlledZks { get; private set; } = new Dictionary(); 13 | 14 | private bool _stopListener; 15 | private Thread _threadServidor; 16 | private HttpListener _httpListener; 17 | private readonly object _lockRequest = new object(); 18 | 19 | public event EventHandler ServerLogEventHandler; 20 | public event EventHandler DeviceConnectedEventHandler; 21 | public event EventHandler DeviceMessageEventHandler; 22 | 23 | public void Start() 24 | { 25 | _stopListener = false; 26 | 27 | _threadServidor = new Thread(StartServerAsync); 28 | _threadServidor.Name = "ZKPushManager"; 29 | _threadServidor.Start(); 30 | } 31 | 32 | public void Stop() 33 | { 34 | _stopListener = true; 35 | 36 | try 37 | { 38 | if (_httpListener.IsListening) 39 | { 40 | _httpListener.Stop(); 41 | } 42 | 43 | if (!_threadServidor.Join(TimeSpan.FromSeconds(5))) 44 | { 45 | _threadServidor.Abort(); 46 | } 47 | 48 | ServerLogEventHandler?.Invoke(this, new ServerLogEventArgs() 49 | { 50 | Event = "STOP_SERVER" 51 | }); 52 | } 53 | catch (Exception ex) 54 | { 55 | ServerLogEventHandler?.Invoke(this, new ServerLogEventArgs() 56 | { 57 | Event = $"STOP_SERVER: {ex.Message}" 58 | }); 59 | } 60 | } 61 | 62 | private async void StartServerAsync() 63 | { 64 | try 65 | { 66 | _httpListener = new HttpListener(); 67 | _httpListener.Prefixes.Add("http://*:8083/"); 68 | _httpListener.Start(); 69 | 70 | ServerLogEventHandler?.Invoke(this, new ServerLogEventArgs() 71 | { 72 | Event = "START_SERVER" 73 | }); 74 | 75 | await ListenAsync(); 76 | } 77 | catch (Exception ex) 78 | { 79 | ServerLogEventHandler?.Invoke(this, new ServerLogEventArgs() 80 | { 81 | Event = $"START_SERVER: {ex.Message}" 82 | }); 83 | } 84 | } 85 | 86 | private async Task ListenAsync() 87 | { 88 | while (!_stopListener) 89 | { 90 | try 91 | { 92 | var context = await _httpListener.GetContextAsync(); 93 | 94 | var serialNumber = context.Request.QueryString["SN"]; 95 | 96 | if (string.IsNullOrWhiteSpace(serialNumber)) 97 | { 98 | return; 99 | } 100 | 101 | lock (_lockRequest) 102 | { 103 | if (!ControlledZks.ContainsKey(serialNumber)) 104 | { 105 | var newZkPush = new ZKPush(serialNumber); 106 | 107 | newZkPush.DeviceMessageEventHandler += 108 | (sender, e) => DeviceMessageEventHandler?.Invoke(sender, e); 109 | 110 | ControlledZks.Add(serialNumber, newZkPush); 111 | 112 | DeviceConnectedEventHandler?.Invoke(this, new DeviceEventArgs() 113 | { 114 | SerialNumber = serialNumber 115 | }); 116 | } 117 | 118 | var zkPush = ControlledZks[serialNumber]; 119 | 120 | Task.Run(() => zkPush.ProcessRequest(context)); 121 | } 122 | } 123 | catch (HttpListenerException ex) when (ex.ErrorCode == 995) 124 | { 125 | return; // Error 995 occurs when we are stopping the server 126 | } 127 | catch (Exception ex) 128 | { 129 | ServerLogEventHandler?.Invoke(this, new ServerLogEventArgs() 130 | { 131 | Event = $"LISTEN: {ex.Message}" 132 | }); 133 | } 134 | } 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /Communications/ZKPushRequest.cs: -------------------------------------------------------------------------------- 1 | namespace ExampleZKPush.Communications 2 | { 3 | public class ZKPushRequest 4 | { 5 | public string CommandText { get; set; } 6 | public string ReponseCommand { get; set; } 7 | public string ResponseData { get; set; } 8 | public TStateRequest StateRequest { get; set; } 9 | 10 | public enum TStateRequest 11 | { 12 | AwaitingTransmission = 0, 13 | AwaitingResponse = 1, 14 | Completed = 2 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Events/DeviceEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ExampleZKPush.Events 4 | { 5 | public class DeviceEventArgs : EventArgs 6 | { 7 | public string SerialNumber { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Events/DeviceMessageEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace ExampleZKPush.Events 2 | { 3 | public class DeviceMessageEventArgs : DeviceEventArgs 4 | { 5 | public string Message { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Events/ServerLogEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ExampleZKPush.Events 4 | { 5 | public class ServerLogEventArgs : EventArgs 6 | { 7 | public string Event { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ExampleZKPush.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | netcoreapp3.1 6 | true 7 | 8 | 9 | -------------------------------------------------------------------------------- /ExampleZKPush.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30413.136 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleZKPush", "ExampleZKPush.csproj", "{0A25DA1D-CC45-4E0D-9E9E-2C1EE00D78EE}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {0A25DA1D-CC45-4E0D-9E9E-2C1EE00D78EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {0A25DA1D-CC45-4E0D-9E9E-2C1EE00D78EE}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {0A25DA1D-CC45-4E0D-9E9E-2C1EE00D78EE}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {0A25DA1D-CC45-4E0D-9E9E-2C1EE00D78EE}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {6BC77D5A-6EC2-4370-9200-49C30DEA394A} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Rodrigo Weber 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Models/Biophoto.cs: -------------------------------------------------------------------------------- 1 | namespace ExampleZKPush.Models 2 | { 3 | public class Biophoto 4 | { 5 | public int Pin { get; set; } 6 | public int Type { get; set; } 7 | public int Size { get; set; } 8 | public string FileName { get; set; } 9 | public string Content { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Models/IProtocol.cs: -------------------------------------------------------------------------------- 1 | namespace ExampleZKPush.Models 2 | { 3 | interface IProtocol 4 | { 5 | string GetTableName(); 6 | string ToProtocol(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Models/Templatev10.cs: -------------------------------------------------------------------------------- 1 | namespace ExampleZKPush.Models 2 | { 3 | public class Templatev10 4 | { 5 | public int Pin { get; set; } 6 | public int Valid { get; set; } 7 | public int FingerId { get; set; } 8 | public string Template { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Models/Transaction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ExampleZKPush.Models 4 | { 5 | public class Transaction 6 | { 7 | public int CardNumber { get; set; } 8 | public int Pin { get; set; } 9 | public int Verified { get; set; } 10 | public int DoorId { get; set; } 11 | public int EventType { get; set; } 12 | public int InOutState { get; set; } 13 | public DateTime DateAndTime { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Models/User.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text; 3 | 4 | namespace ExampleZKPush.Models 5 | { 6 | public class User : IProtocol 7 | { 8 | public int Pin { get; set; } 9 | public string Name { get; set; } 10 | public int CardNumber { get; set; } 11 | public string Password { get; set; } 12 | public TPrivilege Privilege { get; set; } 13 | 14 | public enum TPrivilege 15 | { 16 | CommonUser = 0, 17 | SuperAdministrator = 14 18 | } 19 | 20 | public string ToProtocol() 21 | { 22 | var protocol = new StringBuilder(); 23 | 24 | protocol.AppendFormat("Pin={0}{1}", Pin, '\t'); 25 | protocol.AppendFormat("CardNo={0}{1}", CardNumber, '\t'); 26 | protocol.AppendFormat("Password={0}{1}", Password, '\t'); 27 | protocol.AppendFormat("Name={0}{1}", Name, '\t'); 28 | protocol.AppendFormat("Group={0}{1}", "1", '\t'); 29 | protocol.AppendFormat("Privilege={0}{1}", (int)Privilege, '\t'); 30 | 31 | return protocol.ToString(); 32 | } 33 | 34 | public string GetTableName() => "user"; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Models/UserAuthorize.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace ExampleZKPush.Models 4 | { 5 | public class UserAuthorize : IProtocol 6 | { 7 | public int Pin { get; set; } 8 | 9 | public string ToProtocol() 10 | { 11 | var protocol = new StringBuilder(); 12 | 13 | protocol.AppendFormat("Pin={0}{1}", Pin, '\t'); 14 | protocol.AppendFormat("AuthorizeTimezoneId={0}{1}", "1", '\t'); // Default Timezone 15 | protocol.AppendFormat("AuthorizeDoorId={0}{1}", "15", '\t'); // Granted in all ports 16 | 17 | return protocol.ToString(); 18 | } 19 | 20 | public string GetTableName() => "userauthorize"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Models/UserExtended.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace ExampleZKPush.Models 4 | { 5 | public class UserExtended : IProtocol 6 | { 7 | public int Pin { get; set; } 8 | public string FirstName { get; set; } 9 | 10 | public string ToProtocol() 11 | { 12 | var protocol = new StringBuilder(); 13 | 14 | protocol.AppendFormat("Pin={0}{1}", Pin, '\t'); 15 | protocol.AppendFormat("FirstName={0}{1}", FirstName, '\t'); 16 | 17 | return protocol.ToString(); 18 | } 19 | 20 | public string GetTableName() => "extuser"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /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 ExampleZKPush 8 | { 9 | static class Program 10 | { 11 | /// 12 | /// The main entry point for the application. 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | Application.SetHighDpiMode(HighDpiMode.SystemAware); 18 | Application.EnableVisualStyles(); 19 | Application.SetCompatibleTextRenderingDefault(false); 20 | Application.Run(new frmMAIN()); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # example-zkteco-push-protocol-communication 2 | Example of using ZK Teco communication with ZK Push Protocol 3 | -------------------------------------------------------------------------------- /frmMAIN.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ExampleZKPush 2 | { 3 | partial class frmMAIN 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.btnSTART = new System.Windows.Forms.Button(); 32 | this.btnSTOP = new System.Windows.Forms.Button(); 33 | this.lblCOMMUNICATION_OPTIONS = new System.Windows.Forms.Label(); 34 | this.btnSEND_DATE_AND_TIME = new System.Windows.Forms.Button(); 35 | this.btnSEND_USERS = new System.Windows.Forms.Button(); 36 | this.btnRECEIVE_TRANSACTIONS = new System.Windows.Forms.Button(); 37 | this.lblSERVER_OPTIONS = new System.Windows.Forms.Label(); 38 | this.label1 = new System.Windows.Forms.Label(); 39 | this.txtEVENTS = new System.Windows.Forms.TextBox(); 40 | this.btnRECEIVE_USERS = new System.Windows.Forms.Button(); 41 | this.lstDEVICES = new System.Windows.Forms.ListBox(); 42 | this.btnRECEIVE_TEMPLATES = new System.Windows.Forms.Button(); 43 | this.btnRECEIVE_BIOPHOTOS = new System.Windows.Forms.Button(); 44 | this.btnGET_OPTIONS = new System.Windows.Forms.Button(); 45 | this.SuspendLayout(); 46 | // 47 | // btnSTART 48 | // 49 | this.btnSTART.Location = new System.Drawing.Point(17, 52); 50 | this.btnSTART.Name = "btnSTART"; 51 | this.btnSTART.Size = new System.Drawing.Size(159, 23); 52 | this.btnSTART.TabIndex = 0; 53 | this.btnSTART.Text = "Start"; 54 | this.btnSTART.UseVisualStyleBackColor = true; 55 | this.btnSTART.Click += new System.EventHandler(this.btnSTART_Click); 56 | // 57 | // btnSTOP 58 | // 59 | this.btnSTOP.Location = new System.Drawing.Point(17, 81); 60 | this.btnSTOP.Name = "btnSTOP"; 61 | this.btnSTOP.Size = new System.Drawing.Size(159, 23); 62 | this.btnSTOP.TabIndex = 1; 63 | this.btnSTOP.Text = "Stop"; 64 | this.btnSTOP.UseVisualStyleBackColor = true; 65 | this.btnSTOP.Click += new System.EventHandler(this.btnSTOP_Click); 66 | // 67 | // lblCOMMUNICATION_OPTIONS 68 | // 69 | this.lblCOMMUNICATION_OPTIONS.AutoSize = true; 70 | this.lblCOMMUNICATION_OPTIONS.Location = new System.Drawing.Point(17, 123); 71 | this.lblCOMMUNICATION_OPTIONS.Name = "lblCOMMUNICATION_OPTIONS"; 72 | this.lblCOMMUNICATION_OPTIONS.Size = new System.Drawing.Size(139, 15); 73 | this.lblCOMMUNICATION_OPTIONS.TabIndex = 3; 74 | this.lblCOMMUNICATION_OPTIONS.Text = "Communication Options"; 75 | // 76 | // btnSEND_DATE_AND_TIME 77 | // 78 | this.btnSEND_DATE_AND_TIME.Location = new System.Drawing.Point(17, 143); 79 | this.btnSEND_DATE_AND_TIME.Name = "btnSEND_DATE_AND_TIME"; 80 | this.btnSEND_DATE_AND_TIME.Size = new System.Drawing.Size(159, 23); 81 | this.btnSEND_DATE_AND_TIME.TabIndex = 4; 82 | this.btnSEND_DATE_AND_TIME.Text = "Send Date and Time"; 83 | this.btnSEND_DATE_AND_TIME.UseVisualStyleBackColor = true; 84 | this.btnSEND_DATE_AND_TIME.Click += new System.EventHandler(this.btnSEND_DATE_AND_TIME_Click); 85 | // 86 | // btnSEND_USERS 87 | // 88 | this.btnSEND_USERS.Location = new System.Drawing.Point(17, 172); 89 | this.btnSEND_USERS.Name = "btnSEND_USERS"; 90 | this.btnSEND_USERS.Size = new System.Drawing.Size(159, 23); 91 | this.btnSEND_USERS.TabIndex = 4; 92 | this.btnSEND_USERS.Text = "Send Users"; 93 | this.btnSEND_USERS.UseVisualStyleBackColor = true; 94 | this.btnSEND_USERS.Click += new System.EventHandler(this.btnSEND_USERS_Click); 95 | // 96 | // btnRECEIVE_TRANSACTIONS 97 | // 98 | this.btnRECEIVE_TRANSACTIONS.Location = new System.Drawing.Point(17, 230); 99 | this.btnRECEIVE_TRANSACTIONS.Name = "btnRECEIVE_TRANSACTIONS"; 100 | this.btnRECEIVE_TRANSACTIONS.Size = new System.Drawing.Size(159, 23); 101 | this.btnRECEIVE_TRANSACTIONS.TabIndex = 4; 102 | this.btnRECEIVE_TRANSACTIONS.Text = "Receive Transactions"; 103 | this.btnRECEIVE_TRANSACTIONS.UseVisualStyleBackColor = true; 104 | this.btnRECEIVE_TRANSACTIONS.Click += new System.EventHandler(this.btnRECEIVE_TRANSACTIONS_Click); 105 | // 106 | // lblSERVER_OPTIONS 107 | // 108 | this.lblSERVER_OPTIONS.AutoSize = true; 109 | this.lblSERVER_OPTIONS.Location = new System.Drawing.Point(17, 32); 110 | this.lblSERVER_OPTIONS.Name = "lblSERVER_OPTIONS"; 111 | this.lblSERVER_OPTIONS.Size = new System.Drawing.Size(84, 15); 112 | this.lblSERVER_OPTIONS.TabIndex = 3; 113 | this.lblSERVER_OPTIONS.Text = "Server Options"; 114 | // 115 | // label1 116 | // 117 | this.label1.AutoSize = true; 118 | this.label1.Location = new System.Drawing.Point(17, 363); 119 | this.label1.Name = "label1"; 120 | this.label1.Size = new System.Drawing.Size(108, 15); 121 | this.label1.TabIndex = 3; 122 | this.label1.Text = "Devices Connected"; 123 | // 124 | // txtEVENTS 125 | // 126 | this.txtEVENTS.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 127 | | System.Windows.Forms.AnchorStyles.Left) 128 | | System.Windows.Forms.AnchorStyles.Right))); 129 | this.txtEVENTS.Location = new System.Drawing.Point(192, 32); 130 | this.txtEVENTS.Multiline = true; 131 | this.txtEVENTS.Name = "txtEVENTS"; 132 | this.txtEVENTS.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; 133 | this.txtEVENTS.Size = new System.Drawing.Size(747, 563); 134 | this.txtEVENTS.TabIndex = 6; 135 | // 136 | // btnRECEIVE_USERS 137 | // 138 | this.btnRECEIVE_USERS.Location = new System.Drawing.Point(17, 201); 139 | this.btnRECEIVE_USERS.Name = "btnRECEIVE_USERS"; 140 | this.btnRECEIVE_USERS.Size = new System.Drawing.Size(159, 23); 141 | this.btnRECEIVE_USERS.TabIndex = 4; 142 | this.btnRECEIVE_USERS.Text = "Receive Users"; 143 | this.btnRECEIVE_USERS.UseVisualStyleBackColor = true; 144 | this.btnRECEIVE_USERS.Click += new System.EventHandler(this.btnRECEIVE_USERS_Click); 145 | // 146 | // lstDEVICES 147 | // 148 | this.lstDEVICES.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 149 | | System.Windows.Forms.AnchorStyles.Left))); 150 | this.lstDEVICES.FormattingEnabled = true; 151 | this.lstDEVICES.ItemHeight = 15; 152 | this.lstDEVICES.Location = new System.Drawing.Point(17, 381); 153 | this.lstDEVICES.Name = "lstDEVICES"; 154 | this.lstDEVICES.Size = new System.Drawing.Size(159, 214); 155 | this.lstDEVICES.TabIndex = 5; 156 | // 157 | // btnRECEIVE_TEMPLATES 158 | // 159 | this.btnRECEIVE_TEMPLATES.Location = new System.Drawing.Point(17, 259); 160 | this.btnRECEIVE_TEMPLATES.Name = "btnRECEIVE_TEMPLATES"; 161 | this.btnRECEIVE_TEMPLATES.Size = new System.Drawing.Size(159, 23); 162 | this.btnRECEIVE_TEMPLATES.TabIndex = 4; 163 | this.btnRECEIVE_TEMPLATES.Text = "Receive Templates"; 164 | this.btnRECEIVE_TEMPLATES.UseVisualStyleBackColor = true; 165 | this.btnRECEIVE_TEMPLATES.Click += new System.EventHandler(this.btnRECEIVE_TEMPLATES_Click); 166 | // 167 | // btnRECEIVE_BIOPHOTOS 168 | // 169 | this.btnRECEIVE_BIOPHOTOS.Location = new System.Drawing.Point(17, 288); 170 | this.btnRECEIVE_BIOPHOTOS.Name = "btnRECEIVE_BIOPHOTOS"; 171 | this.btnRECEIVE_BIOPHOTOS.Size = new System.Drawing.Size(159, 23); 172 | this.btnRECEIVE_BIOPHOTOS.TabIndex = 4; 173 | this.btnRECEIVE_BIOPHOTOS.Text = "Receive Biophotos"; 174 | this.btnRECEIVE_BIOPHOTOS.UseVisualStyleBackColor = true; 175 | this.btnRECEIVE_BIOPHOTOS.Click += new System.EventHandler(this.btnRECEIVE_BIOPHOTOS_Click); 176 | // 177 | // btnGET_OPTIONS 178 | // 179 | this.btnGET_OPTIONS.Location = new System.Drawing.Point(17, 317); 180 | this.btnGET_OPTIONS.Name = "btnGET_OPTIONS"; 181 | this.btnGET_OPTIONS.Size = new System.Drawing.Size(159, 23); 182 | this.btnGET_OPTIONS.TabIndex = 4; 183 | this.btnGET_OPTIONS.Text = "Get Options"; 184 | this.btnGET_OPTIONS.UseVisualStyleBackColor = true; 185 | this.btnGET_OPTIONS.Click += new System.EventHandler(this.btnGET_OPTIONS_Click); 186 | // 187 | // frmMAIN 188 | // 189 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); 190 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 191 | this.ClientSize = new System.Drawing.Size(951, 607); 192 | this.Controls.Add(this.btnGET_OPTIONS); 193 | this.Controls.Add(this.btnRECEIVE_BIOPHOTOS); 194 | this.Controls.Add(this.btnRECEIVE_TEMPLATES); 195 | this.Controls.Add(this.btnRECEIVE_USERS); 196 | this.Controls.Add(this.txtEVENTS); 197 | this.Controls.Add(this.lstDEVICES); 198 | this.Controls.Add(this.label1); 199 | this.Controls.Add(this.lblSERVER_OPTIONS); 200 | this.Controls.Add(this.btnRECEIVE_TRANSACTIONS); 201 | this.Controls.Add(this.btnSEND_USERS); 202 | this.Controls.Add(this.btnSEND_DATE_AND_TIME); 203 | this.Controls.Add(this.lblCOMMUNICATION_OPTIONS); 204 | this.Controls.Add(this.btnSTOP); 205 | this.Controls.Add(this.btnSTART); 206 | this.Name = "frmMAIN"; 207 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 208 | this.Text = "ZK Push Server"; 209 | this.ResumeLayout(false); 210 | this.PerformLayout(); 211 | 212 | } 213 | 214 | #endregion 215 | 216 | private System.Windows.Forms.Button btnSTART; 217 | private System.Windows.Forms.Button btnSTOP; 218 | private System.Windows.Forms.Label lblCOMMUNICATION_OPTIONS; 219 | private System.Windows.Forms.Button btnSEND_DATE_AND_TIME; 220 | private System.Windows.Forms.Button btnSEND_USERS; 221 | private System.Windows.Forms.Button btnRECEIVE_TRANSACTIONS; 222 | private System.Windows.Forms.Label lblSERVER_OPTIONS; 223 | private System.Windows.Forms.Label label1; 224 | private System.Windows.Forms.TextBox txtEVENTS; 225 | private System.Windows.Forms.Button btnRECEIVE_USERS; 226 | private System.Windows.Forms.ListBox lstDEVICES; 227 | private System.Windows.Forms.Button btnRECEIVE_TEMPLATES; 228 | private System.Windows.Forms.Button btnRECEIVE_BIOPHOTOS; 229 | private System.Windows.Forms.Button btnGET_OPTIONS; 230 | } 231 | } 232 | 233 | -------------------------------------------------------------------------------- /frmMAIN.cs: -------------------------------------------------------------------------------- 1 | using ExampleZKPush.Events; 2 | using ExampleZKPush.Communications; 3 | using System; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace ExampleZKPush 8 | { 9 | public partial class frmMAIN : Form 10 | { 11 | public frmMAIN() 12 | { 13 | InitializeComponent(); 14 | } 15 | 16 | private readonly ZKPushManager zkPushManager = new ZKPushManager(); 17 | 18 | private void btnSTART_Click(object sender, EventArgs e) 19 | { 20 | zkPushManager.ServerLogEventHandler += OnServerLogEventHandler; 21 | zkPushManager.DeviceMessageEventHandler += OnDeviceEventsEventHandler; 22 | zkPushManager.DeviceConnectedEventHandler += OnDeviceConnectedEventHandler; 23 | 24 | zkPushManager.Start(); 25 | } 26 | 27 | private void btnSTOP_Click(object sender, EventArgs e) 28 | { 29 | zkPushManager.Stop(); 30 | 31 | zkPushManager.ServerLogEventHandler -= OnServerLogEventHandler; 32 | zkPushManager.DeviceMessageEventHandler -= OnDeviceEventsEventHandler; 33 | zkPushManager.DeviceConnectedEventHandler -= OnDeviceConnectedEventHandler; 34 | } 35 | 36 | private void OnDeviceConnectedEventHandler(object sender, DeviceEventArgs e) 37 | { 38 | Invoke(new Action(() => 39 | { 40 | lstDEVICES.Items.Add(e.SerialNumber); 41 | })); 42 | } 43 | 44 | private void OnServerLogEventHandler(object sender, ServerLogEventArgs e) 45 | { 46 | Invoke(new Action(() => 47 | { 48 | txtEVENTS.AppendText($"{e.Event}" + "\r\n"); 49 | })); 50 | } 51 | 52 | private void OnDeviceEventsEventHandler(object sender, DeviceMessageEventArgs e) 53 | { 54 | Invoke(new Action(() => 55 | { 56 | txtEVENTS.AppendText($"{e.SerialNumber} - {e.Message}" + "\r\n"); 57 | })); 58 | } 59 | 60 | private void btnSEND_DATE_AND_TIME_Click(object sender, EventArgs e) 61 | { 62 | foreach (var zkPush in zkPushManager.ControlledZks) 63 | { 64 | Task.Run(zkPush.Value.SendDateAndTime); 65 | } 66 | } 67 | 68 | private void btnSEND_USERS_Click(object sender, EventArgs e) 69 | { 70 | foreach (var zkPush in zkPushManager.ControlledZks) 71 | { 72 | Task.Run(zkPush.Value.SendUsers); 73 | } 74 | } 75 | 76 | private void btnRECEIVE_USERS_Click(object sender, EventArgs e) 77 | { 78 | foreach (var zkPush in zkPushManager.ControlledZks) 79 | { 80 | Task.Run(zkPush.Value.ReceiveUsers); 81 | } 82 | } 83 | 84 | private void btnRECEIVE_TEMPLATES_Click(object sender, EventArgs e) 85 | { 86 | foreach (var zkPush in zkPushManager.ControlledZks) 87 | { 88 | Task.Run(zkPush.Value.ReceiveTemplates); 89 | } 90 | } 91 | 92 | private void btnRECEIVE_TRANSACTIONS_Click(object sender, EventArgs e) 93 | { 94 | foreach (var zkPush in zkPushManager.ControlledZks) 95 | { 96 | Task.Run(zkPush.Value.ReceiveTransactions); 97 | } 98 | } 99 | 100 | private void btnGET_OPTIONS_Click(object sender, EventArgs e) 101 | { 102 | foreach (var zkPush in zkPushManager.ControlledZks) 103 | { 104 | Task.Run(zkPush.Value.GetOptions); 105 | } 106 | } 107 | 108 | private void btnRECEIVE_BIOPHOTOS_Click(object sender, EventArgs e) 109 | { 110 | foreach (var zkPush in zkPushManager.ControlledZks) 111 | { 112 | Task.Run(zkPush.Value.ReceiveBiophotos); 113 | } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /frmMAIN.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | --------------------------------------------------------------------------------