I can close Google chrome via C# as follows:
Process[] chromeInstances = Process.GetProcessesByName("chrome");
foreach (Process p in chromeInstances)
{
p.Kill();
}
but I do not know of a way to check if Google Chrome is running.
I would like to know way check that if google chrome is running or not first, thus will close Google chrome via C#.
simply check the array you got
Process[] chromeInstances = Process.GetProcessesByName("chrome");
if (chromeInstances.Length > 0)
{
//then chrome is up
}
else
{
//not working now
}
If you would like to practice with dealing with the Chrome instances via the Process object you can do code snippets with LinqPad. Once you have this downloaded you can change your Language drop down to C# Program and paste this code in. Take your time and play here and try things before posting another question. I see that you kind of asked a question before, got a semi answer, took that semi answer then created a new question off of it that is still not 100% clear what you are looking for. StackOverflow is not here to do every step for you, make attempts first. If you are still stuck post YOUR code with a proper question to get help.
void Main()
{
var chromeProcess = new ChromeProcess();
Console.WriteLine(chromeProcess.AnyInstancesRunning());
Console.WriteLine(chromeProcess.NumberOfInstancesRunning());
chromeProcess.ChromeInstanceIds().Dump("Chrome Instance Ids");
chromeProcess.KillChromeInstance(2816);
//open and close a few chrome windows
chromeProcess.RefreshInstances();
Console.WriteLine(chromeProcess.AnyInstancesRunning());
Console.WriteLine(chromeProcess.NumberOfInstancesRunning());
chromeProcess.ChromeInstanceIds().Dump("Chrome Instance Ids");
}
// Define other methods and classes here
public class ChromeProcess
{
private const string ImageName = "chrome";
private IEnumerable<Process> _Instances;
public ChromeProcess()
{
_Instances = Process.GetProcessesByName(ImageName);
}
public bool AnyInstancesRunning()
{
return _Instances.Any();
}
public int NumberOfInstancesRunning()
{
return _Instances.Count();
}
public IEnumerable<int> ChromeInstanceIds()
{
return _Instances.Select(i => i.Id).ToArray();
}
public void KillChromeInstance(int id)
{
var process = Process.GetProcessById(id);
if(process.ProcessName != ImageName)
{
throw new Exception("Not a chrome instance.");
}
process.Kill();
}
public void RefreshInstances()
{
_Instances = Process.GetProcessesByName(ImageName);
}
}
Related
I have been tackling this issue for 3 months now.
Error I am Getting in Native Debugging:
"Exception thrown at 0x5A222FC2 (comct123.dll) in FileReader.exe:
0xC0000005: Access violation reading location 0x0000000C."
Normal Debug:
'System.AccessVioliationException' in System.Windows.Forms.dll
My setup is really simple:
public static Form_Interface Interface;
public static void Initialize()
{
Application.SetCompatibleTextRenderingDefault(false);
Interface = new Form_Interface();
Interface.Filesdgv.DataSource = File.SortableBindingList;
Application.Run(Interface);
}
Seems simple enough, right? No.
So basically I have a simple Event that simply opens the file using Process.Start() and no matter what I do it will randomly crash with 'System.AccessVioliationException' in System.Windows.Forms.dll here:
private void Filesdgv_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
Filesdgv.Invoke((Action)(() =>
{
try
{
int rowIndex = e.RowIndex;
if (rowIndex >= 0)
{
int columnIndex = e.ColumnIndex;
File file = (File)((DataGridView)sender).Rows[rowIndex].DataBoundItem;
switch (columnIndex)
{
case 0:
{
Process.Start(file.Location);
}
break;
}
}
}
catch
{
// This fking catch never works anyway.
}
}));
}
private void FileInterface_Load(object sender, EventArgs e)
{
foreach (string oCurrent in Directory.GetFiles(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "Files To Check")))
if (oCurrent.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
new File(oCurrent.Split('\\').Last(), oCurrent);
}
It doesn't matter if I am opening files/links or anything else, it still behaves in the same way.
The link and file location is a readonly field as well.
I have many other uses for reading row data and it never crashes, even if i spam click 10000 times, It will only crash randomly with Process.Start()
Things I tried:
Using BeginInvoke
Using Invoke
Not Using Invoke/BeginInvoke
Putting File Link into a string before reading it.
Using multiple Try Catch
Recoded on another machine... same results there aswell.
I tried using File.Open (either doesn't open the file or throws same error lmao)
Tried using [HandleProcessCorruptedStateExceptions], still won't catch the exception.
Dosen't matter if i click slow or fast still 1/30 chance it happens.
Tried Putting Task.Run(() => Process.Start()); you'd think that a thread will protect you from an exception? no still crashes...
File Class looks like this:
public class File
{
public static SortableBindingList<File> SortableBindingList = new SortableBindingList<File>(new List<File>());
public readonly string fileName;
public readonly string filePath;
public void AddRow()
{
Client.Interface.Invoke((Action)(() =>
{
lock (SortableBindingList)
if (!SortableBindingList.Contains(this))
SortableBindingList.Add(this);
}));
}
public string FileName
{
get
{
return fileName;
}
}
public string Location
{
get
{
return filePath;
}
}
public File(string fileName, string filePath)
{
this.fileName = fileName;
this.filePath = filePath;
AddRow();
}
}
Initalize() is called in static void Main(string[] args) btw.
There are no other threads running editing stuff or anything like that, the only thread running is the form thread. which waits for user input.
Solutions I am looking for:
Alternative Method to launch files/hyperlinks.
A way to avoid form crashing (try catch style)
Crashes even with static data!:
Other threads running although these were not started by me.
Task.Run(() =>
{
Thread.Sleep(100);
Process.Start("https://www.youtube.com");
});
This has fixed my issues, it seems that when trying to immediately run "process.start" during a click event, the GUI unfocusing + starting a new process the exact same moment causes an Exception. (Microsoft pls fix.)
I have been bouncing between guides and YouTube videos trying to implement Selenium Grid 2 on an existing project for a couple of days and I've gotten stuck, please help!
Our framework is Specflow 3.0.220, Selenium WebDriver 3.141.0, C#, NUnit 3.12.0, Selenium Grid selenium-server-standalone-3.141.59.
My initial objectives to implement Selenium Grid 2 are as follows:
Set up a hub and node(s) on my local machine = done.
Run a test through one of the nodes = done.
Run a test on all nodes simultaneously = headache.
Regarding item 2, I have set up two nodes, one is a Chrome node and one is a Firefox node. I can run a test through both of them, but not simultaneously.
I feel that I missing a piece of the puzzle here.
Here's the set-up:
Scenario Outline: Log in
Given I launch the site for <profile> and <environment> and <parallelEnvironment>
When I log in to the Normal account
Then I see that I am logged in
Examples:
| profile | environment | parallelEnvironment |
| parallel | Chrome75 | grid |
If profile is parallel and parallelEnvironment is grid, environment is ignored. The reason for parallelEnvironment is because we may still use Browserstack in the interim while setting up Selenium Grid.
These steps use relevant step files etc and page files (but not using Page Object Model as that's been deprecated).
The driver set-up is as follows:
namespace OurAutomation
{
[Binding]
public sealed class BrowserStack
{
private BrowserStackDriver bsDriver;
public static BrowserStackDriver bdriver;
[BeforeScenario]
public void BeforeScenario()
{
bsDriver = new BrowserStackDriver();
bdriver = bsDriver;
}
[AfterScenario]
public void AfterScenario()
{
bsDriver.Cleanup();
}
}
public class CustomRemoteWebDriver : RemoteWebDriver
{
public CustomRemoteWebDriver(Uri remoteAddress, ChromeOptions options) : base(remoteAddress, options)
{
}
public string getSessionID()
{
return base.SessionId.ToString();
}
}
public class BrowserStackDriver
{
private IWebDriver driver;
public static bool isBrowserStack = false;
public static string Platform;
public static string theEnvironment;
public static string sessionId;
public BrowserStackDriver()
{
}
public string GetString(string property)
{
if (TestContext.Parameters[property] == null)
{
throw new ArgumentException("Property does not exist, does not have a value, or a test setting is not selected. You may need to add the .runsettings file in Visual Studio (Test > Test Settings > Select Test Settings File).");
}
else
{
return TestContext.Parameters[property].ToString();
}
}
public IWebDriver Init(string profile, string environment, string parallelEnvironment)
{
String testString = GetString("BuildNumber");
theEnvironment = environment;
NameValueCollection caps = ConfigurationManager.GetSection("capabilities/" + profile) as NameValueCollection;
NameValueCollection settings = ConfigurationManager.GetSection("environments/" + environment) as NameValueCollection;
ChromeOptions chromeOptions = new ChromeOptions();
if (profile == "single")
{
// logic to invoke relevant browser locally based on Specflow parameter 'profile'
Thread.Sleep(3000);
}
else if (profile == "parallel")
{
if (parallelEnvironment == "browserstack")
{
foreach (string key in caps.AllKeys)
{
chromeOptions.AddAdditionalCapability(key, caps[key]);
}
foreach (string key in settings.AllKeys)
{
chromeOptions.AddAdditionalCapability(key, settings[key]);
}
string username = Environment.GetEnvironmentVariable("BROWSERSTACK_USERNAME");
if (username == null)
{
username = ConfigurationManager.AppSettings.Get("user");
}
string accesskey = Environment.GetEnvironmentVariable("BROWSERSTACK_ACCESS_KEY");
if (accesskey == null)
{
accesskey = ConfigurationManager.AppSettings.Get("key");
}
chromeOptions.AddAdditionalCapability("browserstack.user", username);
chromeOptions.AddAdditionalCapability("browserstack.key", accesskey);
chromeOptions.AddAdditionalCapability("browserstack.local", "true");
chromeOptions.AddAdditionalCapability("build", GetString("BuildNumber"));
chromeOptions.AddAdditionalCapability("name", TestContext.CurrentContext.Test.MethodName);
chromeOptions.AddAdditionalCapability("project", GetString("Project"));
BrowserStackDriver.isBrowserStack = true;
driver = new CustomRemoteWebDriver(
new Uri("http://" + ConfigurationManager.AppSettings.Get("server") + "/wd/hub/"), chromeOptions);
CustomRemoteWebDriver browserRemoteDriver = driver as CustomRemoteWebDriver;
sessionId = browserRemoteDriver.getSessionID();
}
else if (parallelEnvironment == "grid")
{
driver = new RemoteWebDriver(new Uri("http://000.00.00.00:4444/wd/hub"), chromeOptions);
}
}
return driver;
}
public void Cleanup()
{
Thread.Sleep(2000);
if (isBrowserStack)
{
Log.Status status = (TestContext.CurrentContext.Result.Message == null) ? Log.Status.Passed : Log.Status.Failed;
string reason = (TestContext.CurrentContext.Result.Message == null) ? "Passed" : "Error see exception";
Log.UpdateTestStatus(status, reason, sessionId);
}
driver.Quit();
driver = null;
}
}
}
So in here...
else if (parallelEnvironment == "grid")
{
driver = new RemoteWebDriver(new Uri("http://000.00.00.00:4444/wd/hub"), chromeOptions);
}
...I enter the address of one of the nodes and the test gets conducted. However, I just want to send the test to the hub and for it to then execute that one test on all active nodes in their related browsers simultaneously. How do I achieve that? The guides and videos only seem to be taking me so far.
thank you
UPDATE:
So I'm inching further in the right direction I think. Had to roll this back to basics, so I can see how to implement this in my existing project. I've made this work in my grid: https://github.com/teixeira-fernando/Parallel-Execution-with-Selenium-Grid
However I note that I need to add attributes to the tests (to run one test on multiple browsers simultaneously)...
namespace Tutorial_parallel_execution
{
[TestFixture(BrowserType.Chrome)]
[TestFixture(BrowserType.Firefox)]
[TestFixture(BrowserType.Opera)]
[TestFixture(BrowserType.IE)]
[Parallelizable(ParallelScope.Fixtures)]
public class GoogleTesting : Hooks
{
public GoogleTesting(BrowserType browser) : base(browser)
{
}
[Test]
public void GoogleTest()
{
Driver.Navigate().GoToUrl("http://www.google.com");
Driver.FindElement(By.Name("q")).SendKeys("selenium");
Driver.FindElement(By.Name("btnK")).Click();
Assert.That(Driver.PageSource.Contains("Selenium"), Is.EqualTo(true),
"The text selenium doenst exist");
}
}
}
However, since my project started complaining similarly to this SpecFlow Visual Studio extension attempted to use SpecFlow code-behind generator 1.9, I started using SpecFlow.Tools.MsBuild.Generation and lost access to the tests (the code-behind files) in order to add the attributes. The only attribute I can add is [Parallelizable(ParallelScope.Fixtures)] but I have to put this in AssemblyInfo.cs - the other attributes can't be added there.
Do I need to be downgrading the versions of Specflow/Selenium etc in order to make this work??
I was able to strip out the code necessary to implement parallel execution using ThreadLocal from https://github.com/minhhoangvn/AutomationFramework
Add this to your AssemblyInfo.cs file:
[assembly: Parallelizable(ParallelScope.Fixtures)]
[assembly: LevelOfParallelism(4)]
Where you see 4 is the number of tests you want to run at the same time. So if you have 2 nodes, but you want to run 4 tests at the same time, then each node will get 2 chrome browsers.
When you use MsBuild.Generation the feature.cs files are still there, they just don't show up in visual studio.
You could try adding this to your Hooks.cs file when creating the driver:
ScenarioContext _scenarioContext;
IWebDriver _currentWebDriver;
_currentWebDriver = new RemoteWebDriver(new Uri(Utilities.SeleniumHub), options.ToCapabilities(), TimeSpan.FromMinutes(3));
_scenarioContext.ScenarioContainer.RegisterInstanceAs<IWebDriver>(_currentWebDriver);
And then this when you are done with the scenario:
[AfterScenario]
public void CloseBrowserAfterScenario()
{
string driver_process_name = null;
string browser_process_name = null;
switch (browser)
{
case "Chrome":
driver_process_name = "chromedriver.exe";
break;
case "IEX64":
case "IEX86":
driver_process_name = "IEDriverServer.exe";
break;
case "Edge":
driver_process_name = "MicrosoftWebDriver.exe";
browser_process_name = "MicrosoftEdge.exe";
break;
case "Firefox":
driver_process_name = "geckodriver.exe";
break;
default:
LogMessage(browser + "is not found or not supported... Please update the TestUI.dll.Config File");
break;
}
System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName(driver_process_name);
foreach (System.Diagnostics.Process app_process in process)
{
if (!string.IsNullOrEmpty(app_process.ProcessName))
{
try
{
app_process.Kill();
}
catch
{
FunctionalUtil.LogMessage("app_process.Kill(); failed in CloseBrowserAfterScenario");
}
}
}
I don't think this is particular to Selenium, but I've included that tag because I think it's a problem that's very relevant to Selenium tests.
I have a Browser class that's working as it stands:
public static class Browser {
private static IWebDriver webDriver;
private static IWebDriver ieDriver;
private static IWebDriver chromeDriver;
private static BrowserType _browserType;
public static BrowserType BrowserType {
set {
_browserType = value;
switch (_browserType) {
case BrowserType.IE:
if (ieDriver == null)
{
var ieOptions = new InternetExplorerOptions();
ieOptions.InitialBrowserUrl = "about:home";
ieDriver = new InternetExplorerDriver(DriverPath, ieOptions);
}
webDriver = ieDriver;
break;
case BrowserType.Chrome:
if (chromeDriver == null)
{
chromeDriver = new ChromeDriver(DriverPath);
}
webDriver = chromeDriver;
break;
default:
if (chromeDriver == null)
{
chromeDriver = new ChromeDriver(DriverPath);
}
webDriver = chromeDriver;
break;
break;
}
} get { return _browserType; }
}
public static void Goto(string url) {
webDriver.Navigate().GoToUrl(url);
}
}
The problem is that each of these browsers should run in their own thread, so that each test can run on each browser simultaneously (cutting cross-browser test times to the time it takes to run a single browser's test). Right now tests are called sequentially with the following method:
public void RunTest(Func<TestSettings, TestRole, bool> testToRun)
{
foreach (var browserType in BrowserTypes)
{
// Assert test passes in given browser
// browser should have its own thread
}
}
How can multithreading be achieved in this scenario?
Multithreadding is usually achieved to run multiple tests with a testunit.
For PHP you have PHPUnit and some other options:
http://net.tutsplus.com/tutorials/php/parallel-testing-for-phpunit-with-paratest/
For Java you could try to dig in maven-surefire-plugin using JUnit.
http://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.html
Don't know if it is achievable through any selenium API.
If you find a way, please make sure to let me know!
Hope this helps.
I see that you have only one driver:
private static IWebDriver webDriver;
When you set BrowserType for the first time (for example as IE) you assign webDriver (as IE).
Then when you set BrowserType for the second time (for example as Chrome) you re-assign webDriver (now it is Chrome, IE is lost). You will never get simultaneously run of both browsers in this way.
BrowserType should be set externally. For example, as a parameter of your test-project or from App.config. If you want to run tests in one machine simultaneously, create an app (console app for example), that launches your test-project with different BrowserType values in two different threads.
I want to build an automation testing, so I have to know the errors that appear in the console of chrome.
there is an option to get the error lines that appear in the console?
In order to see the console: right click somewhere in the page, click "inspect element" and then go to "console".
I don't know C# but here's Java code that does the job, I hope you can translate it to C#
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.logging.LogEntries;
import org.openqa.selenium.logging.LogEntry;
import org.openqa.selenium.logging.LogType;
import org.openqa.selenium.logging.LoggingPreferences;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class ChromeConsoleLogging {
private WebDriver driver;
#BeforeMethod
public void setUp() {
System.setProperty("webdriver.chrome.driver", "c:\\path\\to\\chromedriver.exe");
DesiredCapabilities caps = DesiredCapabilities.chrome();
LoggingPreferences logPrefs = new LoggingPreferences();
logPrefs.enable(LogType.BROWSER, Level.ALL);
caps.setCapability(CapabilityType.LOGGING_PREFS, logPrefs);
driver = new ChromeDriver(caps);
}
#AfterMethod
public void tearDown() {
driver.quit();
}
public void analyzeLog() {
LogEntries logEntries = driver.manage().logs().get(LogType.BROWSER);
for (LogEntry entry : logEntries) {
System.out.println(new Date(entry.getTimestamp()) + " " + entry.getLevel() + " " + entry.getMessage());
//do something useful with the data
}
}
#Test
public void testMethod() {
driver.get("http://mypage.com");
//do something on page
analyzeLog();
}
}
Pay attention to setUp method in above code. We use LoggingPreferences object to enable logging. There are a few types of logs, but if you want to track console errors then LogType.BROWSER is the one that you should use. Then we pass that object to DesiredCapabilities and further to ChromeDriver constructor and voila - we have an instance of ChromeDriver with logging enabled.
After performing some actions on page we call analyzeLog() method. Here we simply extract the log and iterate through its entries. Here you can put assertions or do any other reporting you want.
My inspiration was this code by Michael Klepikov that explains how to extract performance logs from ChromeDriver.
You can get logs this way:
Driver().Manage().Logs.GetLog();
By specifying what log you are interested in you can get the browser log, that is:
Driver().Manage().Logs.GetLog(LogType.Browser);
Also remember to setup your driver accordingly:
ChromeOptions options = new ChromeOptions();
options.SetLoggingPreference(LogType.Browser, LogLevel.All);
driver = new ChromeDriver("path to driver", options);
This is the c# code for logging the brower log from chrome.
private void CheckLogs()
{
List<LogEntry> logs = Driver.Manage().Logs.GetLog(LogType.Browser).ToList();
foreach (LogEntry log in logs)
{
Log(log.Message);
}
}
here is my code for the actual log:
public void Log(string value, params object[] values)
{
// allow indenting
if (!String.IsNullOrEmpty(value) && value.Length > 0 && value.Substring(0, 1) != "*")
{
value = " " + value;
}
// write the log
Console.WriteLine(String.Format(value, values));
}
As per issue 6832 logging is not implemented yet for C# bindings. So there might not be an easy way to get this working as of now.
Here is a solution to get Chrome logs using the C#, Specflow and Selenium 4.0.0-alpha05.
Pay attention that the same code doesn't work with Selenium 3.141.0.
[AfterScenario]
public void AfterScenario(ScenarioContext context)
{
if (context.TestError != null)
{
GetChromeLogs(context); //Chrome logs are taken only if test fails
}
Driver.Quit();
}
private void GetChromeLogs()
{
var chromeLogs = Driver.Manage().Logs.GetLog(LogType.Browser).ToList();
}
public void Test_DetectMissingFilesToLoadWebpage()
{
try
{
List<LogEntry> logs = driver.Manage().Logs.GetLog(LogType.Browser).ToList();
foreach (LogEntry log in logs)
{
while(logs.Count > 0)
{
String logInfo = log.ToString();
if (log.Message.Contains("Failed to load resource: the server responded with a status of 404 (Not Found)"))
{
Assert.Fail();
}
else
{
Assert.Pass();
}
}
}
}
catch (NoSuchElementException e)
{
test.Fail(e.StackTrace);
}
}
You could do something like this in C#. It is a complete test case. Then print the console output as String i.e logInfo in your report. For some reason, Log(log.Message) from the solution above this one gave me build errors.So, I replaced it.
C# bindings to the Chrome console logs are finally available in Selenium 4.0.0-alpha05. Selenium 3.141.0 and prior do not have support.
Before instantiating a new ChromeDriver object, set the logging preference in a ChromeOptions object and pass that into ChromeDriver:
ChromeOptions options = new ChromeOptions();
options.SetLoggingPreference(LogType.Browser, LogLevel.All);
ChromeDriver driver = new ChromeDriver(options);
Then, to write the Chrome console logs to a flat file:
public void WriteConsoleErrors()
{
string strPath = "C:\\ConsoleErrors.txt";
if (!File.Exists(strPath))
{
File.Create(strPath).Dispose();
}
using (StreamWriter sw = File.AppendText(strPath))
{
var entries = driver.Manage().Logs.GetLog(LogType.Browser);
foreach (var entry in entries)
{
sw.WriteLine(entry.ToString());
}
}
}
driver.manage().logs().get("browser")
Gets all logs printed on the console. I was able to get all logs except Violations. Please have a look here Chrome Console logs not printing Violations
This is probably more of a general c# and simple threading question than it is a Facebook SDK question, but I may be wrong. But I could really use some help. I am reusing the sample code that comes with the SDK which includes a FacebookLoginDialog class. I am currently using it like this. In my GetMessages, GetFriendRequests, and other Get* classes, I always try/catch calls like this:
try
{
var result = (IDictionary<string, object>)fb.Get("/me/inbox");
}
catch (FacebookOAuthException e)
{
FacebookSession.Login();
}
Here's my login method in my FacebookSession class
public static void Login()
{
var fbLoginDialog = new FacebookLoginDialog(APP_ID, EXTENDED_PERMISSIONS);
DialogResult dr = fbLoginDialog.ShowDialog();
DisplayAppropriateMessage(fbLoginDialog.FacebookOAuthResult);
}
And here is the constructor in my FacebookLoginDialog class (this is where I have the problem)
public FacebookLoginDialog(string appId, string[] extendedPermissions, bool logout)
{
try
{
var oauth = new FacebookOAuthClient { AppId = appId };
var loginParameters = new Dictionary<string, object>
{
{ "response_type", "token" },
{ "display", "popup" }
};
if (extendedPermissions != null && extendedPermissions.Length > 0)
{
var scope = new StringBuilder();
scope.Append(string.Join(",", extendedPermissions));
loginParameters["scope"] = scope.ToString();
}
var loginUrl = oauth.GetLoginUrl(loginParameters);
if (logout)
{
var logoutParameters = new Dictionary<string, object>
{
{ "next", loginUrl }
};
System.Uri uri =
new Uri("https://www.facebook.com/logout.php?next=" +
"https://www.facebook.com/connect/login_success.html&access_token=" +
FacebookSession._accessToken);
this.navigateUrl = uri;
}
else
{
this.navigateUrl = loginUrl;
}
InitializeComponent(); // crash here... sometimes
}
catch (Exception e)
{
//Log error message
}
}
Sorry for all the code, but now the problem. This code works fine the first time through. If I go to my facebook applications permissions page in Facebook and remove the app (that is, remove its permissions), while my desktop app here is NOT running, when I do start it up, it sees that it does not have permission and shows the login dialog. I can save the access_key and it will work just fine. But if I go to the facebook apps page and yank the permissions while my desktop app is running, then bad things happen. I get an error message about the activex control cannot be instantiated because the current thread is not in a single-threaded apartment. I have seen many posts here that say all you have to do is put [STAThread] above your main(), and my code has that. I have also tried creating a new thread to call the FacebookLoginDialog, but not only did that not work, but since my code is really not designed to run in multiple threads, that started causing more problems.
Is there a simple solution to all this, or do I need to redesign my code so that it properly runs in multiple threads? Or should I just live with the program crashing in those few instances when someone monkeys with the facebook permissions while my app is running?