I was working on a security monitor application and the best approach i found was Skype.
when a possible intrusion occurs the application calls a specified Skype ID which is probably my android phone i am done with all the image processing stuff. But i am stuck with this Skype API i wrote this piece of code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SKYPE4COMLib;
namespace SkypeCall
{
class Program
{
static void Main(string[] args)
{
Skype skype;
skype = new Skype("Skype4COM.Skype", "Skype_");
Call call = skype.PlaceCall(SkypeID);
call.StartVideoSend();
}
}
}
This initiates a voice call but in the call.StartVideoSend(); shows an error
An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in SkypeCall.exe
Additional information: CALL: Action failed
i even tried this but i guess that's old API and couldn't get anything out of it.
And not even by sending commands .
if somebody would help me out i'll be grateful.
I think you need to wait until the call is connected.
easiest way would be to test the call.Status
class Program
{
static void Main(string[] args)
{
Skype skype;
skype = new SKYPE4COMLib.Skype();
string SkypeID = args[1];
Call call = skype.PlaceCall(SkypeID);
do
{
System.Threading.Thread.Sleep(1);
} while (call.Status != TCallStatus.clsInProgress);
call.StartVideoSend();
}
}
You could also add an event, however I think this will fire on every call so unless you are only using it for this project it might be too much.
class Program
{
static string SkypeID = "";
static void Main(string[] args)
{
Skype skype;
skype = new SKYPE4COMLib.Skype();
skype.CallStatus += new _ISkypeEvents_CallStatusEventHandler(skype_CallStatus);
Call call = skype.PlaceCall(SkypeID);
Console.ReadKey();
}
static void skype_CallStatus(Call pCall, TCallStatus Status)
{
if (Status == TCallStatus.clsInProgress && pCall.PartnerHandle == SkypeID) { pCall.StartVideoSend(); }
}
}
Related
I'm trying to make a simple console app client (starter.exe) on c# .NET Framework 4.6 to make a WireGuard protocol based connection using Wireguard source code.
What is done:
Downloaded wireguard source code from here: git://git.zx2c4.com/wireguard-windows
Successfuly built Tunnel.dll in ..\embeddable-dll-service\amd64\tunnel.dll via build.bat
Created a project in Visual Studio 2015.using the c# code from ..\embeddable-dll-service\csharp
Starting from here some strange thing are happenning:
if launching starter.exe \service <path to *.conf> I receive the
error
Service run error: The service process could not connect to the
service controller.
if launching starter.exe without parameters everything works fine until I remove the if{} block:
Unhandled Exception: System.ComponentModel.Win32Exception: The service
did not respond to the start or control request in a timely fashion
at WireGuardTunnel.Service.Add(String configFile) in
D:\Depository\BitBucket\WireGuard_Tunnel_Repository\WireGuardTunnel_proj\Launcher\Service.cs:line
69 at WireGuardTunnel.Program.Main(String[] args) in
D:\Depository\BitBucket\WireGuard_Tunnel_Repository\WireGuardTunnel_proj\Launcher\Program.cs:line
83
That means even if the code in if{} block is not executed it influencese somehow the application behaviour.
Next, as I want to make my app work with parameters I solved the
issue by removing return afer Service.Run and passing args[1] to Service.Add(args[1]). It works OK, but I have an extra log line (the first one due to Service.Run perpetual error described above) in the log:
Service run error: The service process could not connect to the
service controller. 235660: [TUN] [chicago4] Watching network
interfaces 245661: [TUN] [chicago4] Resolving DNS names
245661: [TUN] [chicago4] Creating Wintun interface 225660: [TUN]
[chicago4] Starting WireGuard/0.3.1 (Windows 6.1.7601; amd64)
So finally the questions:
Why Service.Run(confFile) does not work
Why Service.Run(confFile) influences the Service.Add(confFile)
Why if{} block is executed when I launch starte.exe with no parameters
The original Program.cs without modification:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.InteropServices;
namespace Tunnel
{
class Program
{
[DllImport("kernel32.dll")]
private static extern bool SetConsoleCtrlHandler(SetConsoleCtrlEventHandler handler, bool add);
private delegate bool SetConsoleCtrlEventHandler(UInt32 signal);
public static void Main(string[] args)
{
string baseDirectory = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
string configFile = Path.Combine(baseDirectory, "demobox.conf");
string logFile = Path.Combine(baseDirectory, "log.bin");
if (args.Length == 2 && args[0] == "/service")
{
configFile = args[1];
Service.Run(configFile);
return;
}
try { File.Delete(logFile); } catch { }
Ringlogger log = new Ringlogger(logFile, "GUI");
var logPrintingThread = new Thread(() =>
{
var cursor = Ringlogger.CursorAll;
while (Thread.CurrentThread.IsAlive)
{
var lines = log.FollowFromCursor(ref cursor);
foreach (var line in lines)
Console.WriteLine(line);
Thread.Sleep(300);
}
});
logPrintingThread.Start();
SetConsoleCtrlHandler(delegate
{
Service.Remove(configFile);
Environment.Exit(0);
return true;
}, true);
try
{
Service.Add(configFile);
logPrintingThread.Join();
}
finally
{
Service.Remove(configFile);
}
}
}
}
Bit late to the party but I was having the exact same issue as above and discovered that in order to get everything working correctly you have to have Tunnel.Service.Run("path to config") defined on application initialization either in your main loop or your constructor then you can run Tunnel.Service.Add("path to config", true) which will create the service and start the VPN connection. It's also good practice to destroy the service on close using Tunnel.Service.Remove("path to config", true) as the service will continue to run and you will still be connected to your VPN until it is stopped manually.
I've been trying to make a direct method call using the AMQP protocol. But can't make it work. I believe calling direct method is possible over AMQP if I'm not wrong. It works with MQTT though. Any clues would be much appreciated.
Here's the code:
using Microsoft.Azure.Devices.Client;
using Microsoft.Azure.Devices.Shared;
using Newtonsoft.Json;
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace VirtualIoTDevice
{
internal class Program
{
private const string DeviceConnectionString = "device-connection-string";
private const string DEVICE_ID = "device01";
private static DeviceClient _device;
private static async Task Main(string[] args)
{
Console.WriteLine("Initializing virtual IoT device..");
using (_device = DeviceClient.CreateFromConnectionString(DeviceConnectionString, DEVICE_ID))
{
await _device.OpenAsync();
await _device.SetMethodHandlerAsync("showMessage", ShowMessage, null);
Console.ReadKey();
}
}
private static Task<MethodResponse> ShowMessage(MethodRequest methodRequest, object userContext)
{
Console.WriteLine("***Direct message received***");
Console.WriteLine(methodRequest.DataAsJson);
var responsePayload = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(new { response = "Message shown!" }));
return Task.FromResult(new MethodResponse(responsePayload, 200));
}
}
}
And here's the command to invoke the direct method:
az iot hub invoke-device-method -n "iothub-name" -d "device01" --method-name "showMessage"
Ok, I know what your issue is: In the latest version of the SDK there was some change in regards to blocking threads. I don't know if this was an intended change or a regression.
However, in your case the Console.ReadKey() is somehow blocking AMQP from connecting in the first place. MQTT is not affected by this - which could indicate it might be a regression.
So, if you change Console.ReadKey() to for example await Task.Delay(-1) it works again in my test.
I created 2 simple C# Console Projects (.net 4.5.2), added the v4.0.0.1 NetMQ Nuget package to each, loaded each program up into separate Visual Studio 2017 Community Editions, put a breakpoint on the 1 line contained within the OnReceiveReady callback method, started the subscriber program first, then started the publisher program. The ReceieveReady event is not being triggered in the subscriber. What am I doing wrong? Even if I chose subSocket.Subscribe("") then I still didn't get any messages received. Also, removing/modifying the Send/Receive HighWatermarks didn't change things either. Thanks for your help!
Here's the Publisher code:
using System;
using NetMQ;
using NetMQ.Sockets;
using System.Threading;
namespace SampleNQPub
{
class Program
{
static void Main(string[] args)
{
var addr = "tcp://127.0.0.1:3004";
using (var pubSocket = new PublisherSocket())
{
Console.WriteLine("Publisher socket binding.");
pubSocket.Options.SendHighWatermark = 10;
pubSocket.Bind(addr);
for (int i=0; i < 30; i++)
{
pubSocket.SendMoreFrame("NQ").SendFrame(i.ToString());
Thread.Sleep(1000);
}
pubSocket.Disconnect(addr);
}
}
}
}
Here's the Subscriber code:
using System.Threading;
using NetMQ;
using NetMQ.Sockets;
namespace SampleNQSub
{
class Program
{
static void Main(string[] args)
{
var addr = "tcp://127.0.0.1:3004";
using (var subSocket = new SubscriberSocket())
{
subSocket.ReceiveReady += OnReceiveReady;
subSocket.Options.ReceiveHighWatermark = 10;
subSocket.Connect(addr);
subSocket.Subscribe("NQ");
for (int i=0; i < 20; i++)
{
Thread.Sleep(1000);
}
subSocket.Disconnect(addr);
}
}
static void OnReceiveReady(object sender, NetMQSocketEventArgs e)
{
var str = e.Socket.ReceiveFrameString();
}
}
}
Ok, this is a gotcha question in the NetMQ world and I just figured it out. You MUST setup a NetMQPoller that will wind up calling every ReceiveReady callback which you have added to it (NetMQPoller).
Here is the corrected code which will at least (i.e., ReceiveFrameString still only getting the "NQ" part but that's just another method call to fix) get the ReceiveReady event triggered:
using System.Threading;
using System.Threading.Tasks;
using NetMQ;
using NetMQ.Sockets;
namespace SampleNQSub
{
class Program
{
static void Main(string[] args)
{
var addr = "tcp://127.0.0.1:3004";
NetMQPoller poller = new NetMQPoller();
using (var subSocket = new SubscriberSocket())
{
subSocket.ReceiveReady += OnReceiveReady;
subSocket.Options.ReceiveHighWatermark = 10;
subSocket.Connect(addr);
subSocket.Subscribe("NQ");
poller.Add(subSocket);
poller.RunAsync();
for (int i = 0; i < 20; i++)
{
Thread.Sleep(1000);
}
subSocket.Disconnect(addr);
}
}
static void OnReceiveReady(object sender, NetMQSocketEventArgs e)
{
var str = e.Socket.ReceiveFrameString();
e.Socket.ReceiveMultipartStrings();
}
}
}
I noticed that the authors of NetMQ decided in 4.x to take care of the Context object internally so the user wouldn't have to bare the burden of managing it. It would be nice also if they could hide this "polling pump" code from the user as well for the most simple use case.
As a comparison, take a look at the subscriber using NodeJS (with the zmq library) utilizing the Publisher console app I posted above (save this code to sub.js and, in a Windows console, type 'node sub.js'):
var zmq = require('zmq'), sock = zmq.socket('sub');
sock.connect('tcp://127.0.0.1:3004');
sock.subscribe('NQ');
console.log('Subscriber connected to port 3004');
sock.on('message', function() {
var msg = [];
Array.prototype.slice.call(arguments).forEach(function(arg) {
msg.push(arg.toString());
});
console.log(msg);
});
So where's the poller pump mechanism in this? (Answer: I don't care! I just want the messages supplied to me in a callback that I register. [Obviously, tongue-in-cheek. I get that a NetMQPoller is versatile and handles more complex issues, but for basic "give me a message in a callback when it arrives", it would be nice if it were handled internally by the library.])
So I know this API is quite old and very undocumented, exactly the reason that I'm making a SO question, so I wanted to know how I can select a chat in Skype using the C# Skype Desktop API, I've done some looking around but most people seem to be using WinForms to make their app, mine's just a simple console application, code:
Skype Skype = new Skype();
Skype.Attach(5, true);
Skype.Chat.SendMessage("Hello ??");
Parser.Pause();
On runtime, I of course get an exception telling me I need to select a chat, but I'm not sure as to how I can do that, I've looked here but that didn't help me much.
Is there a way to reference a chat easily using a specific code? etc... Thanks!
I have constructed this snippet which should help you...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Channels;
using System.Text;
using System.Threading.Tasks;
using SKYPE4COMLib;
namespace skypeExperiment
{
class Program
{
static void Main(string[] args)
{
Skype s = new Skype();
s.Attach();
if (!s.Client.IsRunning)
{
// start minimized with no splash screen
s.Client.Start(true, true);
}
// wait for the client to be connected and ready
//you have to click in skype on the "Allow application" button which has popped up there
//to allow this application to communicate with skype
s.Attach(6, true);
//this will print out all the chat names to the console
//it will enumerate all the chats you've been in
foreach (Chat ch in s.Chats)
{
Console.WriteLine(ch.Name);
}
//pick one chat name of the enumerated ones and get the chat object
string chatName = "#someskypeuser/someskypeuser;9693a13447736b9";
Chat chat = GetChatByName(s, chatName);
//send a message to the selected chat
if (chat != null)
{
chat.SendMessage("test");
}
else
{
Console.WriteLine("Chat with that name was not found.");
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
private static Chat GetChatByName(Skype client, string chatName)
{
foreach (Chat chat in client.Chats)
{
if (chat.Name == chatName) return chat;
}
return null;
}
}
}
Instead of using an existing chat object, you can create new chat object with method
Chat chat = s.CreateChatWith("name of the user to chat with");
chat.SendMessage("test");
You can create a group chat with:
Group mygroup = s.CreateGroup("mygroup");
mygroup.AddUser("user1");
mygroup.AddUser("user2");
Chat myGroupChat = s.CreateChatMultiple(mygroup.Users);
myGroupChat.SendMessage("test");
or create method to retrieve group by display name
private static Group GetGroupByDisplayName(Skype client, string groupDisplayName)
{
foreach (Group g in client.Groups)
{
if (g.DisplayName == groupDisplayName)
{
return g;
}
}
return null;
}
and use it then like:
Group majesticSubwayGroup = GetGroupByDisplayName("majesticsubway");
Chat majesticSubwayGroupChat = s.CreateChatMultiple(majesticSubwayGroup.Users);
majesticSubwayGroupChat.SendMessage("test");
I developed a softphone for windows, I know how to register it as default tell application by reading this question, but I don`t know how get arguments sent from a web application or another win application while my softphone is running.
The standard code to call tell app from web app is something like this:
window.open("tel: 05525825");
If you have registered your application for the scheme tel: and the Command is "yourapp.exe %1", then you can read them from the commandline arguments as explained in How to access command line parameters outside of Main in C#:
string arguments = Environment.GetCommandLineArgs();
string phoneNumber = arguments[1];
Of course you need to do some sanity checking before bluntly accessing and using the array element.
If you setup the protocol URL keys correctly your application will be run with the data in the command line (E.g. args[] in main())
To pass data to an already running instance of your application the easiest way is to use the StartupNextInstance event provided by VisualBasic.ApplicationServices and re-process new incomming command lines:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Microsoft.VisualBasic.ApplicationServices;
namespace Foo
{
static class Program
{
[STAThread]
static void Main(string[] args)
{
var applicationBase = new ThisWindowsApplicationBase();
applicationBase.StartupNextInstance += (sender, e) => { applicationBase.HandleCommandLine(e.CommandLine); };
applicationBase.Run(args);
}
}
class ThisWindowsApplicationBase : WindowsFormsApplicationBase
{
internal ThisWindowsApplicationBase()
: base()
{
this.IsSingleInstance = true;
this.MainForm = new Form1();
this.HandleCommandLine(Environment.GetCommandLineArgs().Skip(1));
}
internal void HandleCommandLine(IEnumerable<string> commandLine)
{
this.MainForm.Text = "Processing: " + commandLine.FirstOrDefault();
}
}
}
Note this will not fire for the first run.