The steps of my application are:
Go to the setting page first, and the setting page will register the Registry Log (as 'regedit' in command line) in the background (people may seldom go to the setting page).
When users clicks the URL in a web page, it will trigger the registry and open my application.
The appplication reads the parameter that it gets and does things depending on the parameter value.
User may click on different links to send different parameters to my application
That is, if the application is not opened, it should be launched it and reads the parameter. If the application is already opened, it should just read the parameter.
The problem is: how could find out the different situations of my application - whether it is opened or not - and then use the parameter correctly?
The part of registry( in setting page):
Registry.ClassesRoot.CreateSubKey("MyApp").SetValue("", "URL:MyApp Protocol");
Registry.ClassesRoot.CreateSubKey("MyApp").SetValue("URL Protocol", "");
Registry.ClassesRoot.CreateSubKey("MyApp\\DefaultIcon").SetValue("", "\"" + Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + "\\" + "MyApp.exe" + ",1\"");
Registry.ClassesRoot.CreateSubKey("MyApp\\shell\\open\\command").SetValue("", "\"" + Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + "\\" + "MyApp.exe" + "\" \"%1\"");
%1 is the parameter I will get( from url to my application).
And the web link may be:
Call for Function 1
Call for Function 2
So there are many links in the web page to call same application.
But I cannot let my application be opened every time (that is, there should be only one application opened, and other clicks on links will only send parameters to the app).
I know how to find out whether the application is opened or not by the code:
Mutex mul = null;
bool is_createdNew;
try
{
string mutexName = Process.GetCurrentProcess().MainModule.FileName.Replace(Path.DirectorySeparatorChar, '_');
mul = new Mutex(true, "Global\\" + mutexName, out is_createdNew);
if (!is_createdNew)
{
// application be opened already, I close the application originally
Environment.Exit(Environment.ExitCode);
}
else
{
// the application is first run, open my MainWindow
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
}
Is it possible to send the parameter as a method of registry when the application is opened?
I even think about reading registry by Registry.GetValue, when my application starts up,
to use timer to read registry value per second......
This is my first time face this situation of user's request,
hope someone can give me any direction!
Thanks in advance.
When you find out that another instance of your application is already running (which you do in your code above using Mutex), you can programatically pass the parameter (of the second app instance) to the first, already running app instance and then just close the second app instance. This code for passing parameter to the first app instance would then be just before Environment.Exit(Environment.ExitCode);
(Presuming that your app is relatively small and does not loads lots of libraries on startup - in that case it would be better to create a separate small launcher app)
The problem is, how to pass the parameter between two independent processes - two instances of your app.exe. There are of course several options, look here:
Send/Receive message To/From two running application
I would use FileWatcher or Memory mapped file as it is specified in that answer.
The solution with timer and changing registry values is not good (registry operations require admin access, registry operations are not so fast etc.).
Here is a nice library that shows, how to pass parameters between 2 processes using Memory mapped file.
http://code.msdn.microsoft.com/windowsdesktop/Inter-process-communication-e96e94e7
I found another way to solve my problem,
just simply add 'static' before Mutex.
See the detail: C# static
Related
I am trying to restrict my application from having multiple instances at machine level, i.e. A computer will have multiple users logging into it and this application is required to have only one instance for performance reasons. So if User A starts the application, User B should simply get a message that this application is already running on User A's account. Now before you start schooling me on processes, I already tried that, and it doesn't work because for my application to check if a similar process is running, it needs to start the process(the application), in this case, the application will never start.
I am using this to restrict multiple instances, and it works great but it only works at user level.
Microsoft.VisualBasic.ApplicationServices
public class SingleInstanceApplication : WindowsFormsApplicationBase
{
private SingleInstanceApplication()
{
base.IsSingleInstance = true;
}
public static void Run(Form f, StartupNextInstanceEventHandler startupHandler)
{
SingleInstanceApplication app = new SingleInstanceApplication();
app.MainForm = f;
app.StartupNextInstance += startupHandler;
app.Run(Environment.GetCommandLineArgs());
}
}
Any help or advice will be much appreciated...
How are users accessing the application? You could create batch script that checks the process, if one is running then the script simply won't start the application. Not sure if you want to solve this programatically inside your application or through other means. But if you don't want a second instance of said application running your best bet would be outside of your application such as a batch script.
There is also this: cross-user C# mutex.
Where I work we have flags set to specific SQL tables that prevent multiple users from editing records at the same time. Or you could create a hidden lock file when a user logs in and than remove said file once the user logs out.
I have the following, using Kentico API 7 via a console application:
String connectionString = CMS.DataEngine.ConnectionHelper.GetConnectionString("MyConnString");
Console.WriteLine("connectionString ? " + connectionString);
//CMS.DataEngine.GeneralConnection
CMS.DataEngine.GeneralConnection conn = CMS.DataEngine.ConnectionHelper.GetConnection(connectionString);
conn.Open();
Console.WriteLine("connection is open? " + conn.IsOpen());
CMS.CMSHelper.CMSContext.Init();
Console.WriteLine("CurrentSiteID " + CMS.CMSHelper.CMSContext.CurrentSiteID);
The connection is open. I get error
Console.WriteLine("CurrentSiteID " + CMS.CMSHelper.CMSContext.CurrentSiteID);
that says connection is not initialized. Got help?
It certainly is possible to use Kentico API outside of Kentico itself. Recently, I published an article on this topic. However, the article demonstrates the possibility on a newer version of Kentico. But back to your problem...
The CMS.CMSHelper.CMSContext.Init(); method expects a connection string named "CMSConnectionString" to exist in your app.config or web.config.
The documentation also says
You can call this method at any point in your application's life cycle, but it must occur before you use any other Kentico CMS API.
so you should not be touching CMS.DataEngine or any other CMS.* namespace before you call CMSContext.Init().
Once you call that method you can start using the parameter-less overload ConnectionHelper.GetConnection() but I would advise you to take advantage of the Info-Provider pattern that Kentico offers instead of using the direct DB access through CMS.DataEngine.
For instance, this is how you delete users:
// Get the user
UserInfo deleteUser = UserInfoProvider.GetUserInfo("MyNewUser");
// Delete the user
UserInfoProvider.DeleteUser(deleteUser);
Unless there's a specific need to create a console application to perform your task, then I would recommend avoiding a console app and instead creating a custom scheduled task.
You can write the code that your task needs to perform within the App_Code folder of your project - or within the CMSAppCode project if you're using a web application project type. This way you don't have to worry about having access to the database or referencing all the DLLs you'll need to utilize the Kentico API.
I am working with an ASP.NET 2.0 application (created by my predecessor). Users log into it with AD credentials, and everything done within the app uses those credentials. I modified a page in the application that has nothing to do with event logging, and now my users get this error:
Here is the relevant code from the global.asax file:
public void LogException(Exception e)
{
string exceptionXml = RenderException(e, true);
_EventLog.WriteEntry("Exception of type " + e.GetType().FullName + " occurred.\n\n" + exceptionXml, EventLogEntryType.Error);
}
RenderException() just puts the exception XML into a flat string, removing white spaces.
I am at a loss on how to get rid of this error. I have tried re-publishing the website with an iisreset. I have tried restarting the web server (2k3 w/ iis 6.0), flushing the app pool. I have also tried modifying the permissions in the registry for the top-level event log key. Can anyone tell me how to get rid of this error? It does not happen on my computer, so it is very hard to replicate. Also, the browser used does not seem to matter. The previous version will work for the same persons getting this error.
By default the ASPNET user cannot access the existing event logs categories.
If you do want to write messages to the event log you must create your own category
Launch RegEdit
Navigate to HKEY_LOCAL_MACHINE\SYSTEM\
CurrentControlSet\Services\EventLog\
From the menu, select Edit->Permissions
Click the Add button and write ASPNET. (if ASP.NET is running under a different user id, use that id instead)
Click OK.
Select the newly added user from the list (ASP.NET Machine User by default).
Click on Full Control in the Allow column.
Click OK.
You can also check that the user, under which the applications is running, belongs to the correct group, for example IIS_WPG
http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/3648346f-e4f5-474b-86c7-5a86e85fa1ff.mspx?mfr=true
You appear to be calling an instance method of the EventLog class on the _EventLog instance:
_EvengLog.WriteEvent(message, ...);
But according to MSDN documentation for the EventLog class:
Any instance members are not guaranteed to be thread safe.
I suspect this is a likely source of your problem, and would recommend you use one of the static methods (which are guaranteed to be thread safe):
System.Diagnostics.EventLog.WriteEvent(source, message, ...);
Alternatively you could implement your own synchronization, but I wouldn't recommend this.
The basic concept of the project is it accesses SharePoint, verifies a certain file exists, verifies the file is NOT locked by another user, and then, if those two conditions are met, excel opens the file up and does some stuff with it, then saves the file and closes it again.
The issue is at the point where the program accesses SharePoint and runs through the verification steps. Initially, my first crack at this was directly from VBA using SOAP, and, until Microsoft decided to downgrade SharePoint to 2013 from 2010, it worked quite well, meaning now, I'm into using Visual Studio and C# to accomplish the same thing that SOAP was doing in SP2010.
I've attempted implementing the code found here: http://www.vrdmn.com/2013/01/authenticating-net-client-object-model.html, however I can't get it to work. What I did manage to get working was the 2010 authentication model which pops up a browser window, checks for valid cookies, and, if it finds them, reads the cookies, otherwise prompts the user to log into SharePoint and then closes the browser and continues on.
public CookieCollection Show()
{
if (string.IsNullOrEmpty(this.LoginPageUrl)) throw new ApplicationException(Constants.MSG_NOT_CLAIM_SITE);
// navigate to the login page url.
this.webBrowser.Navigate(this.LoginPageUrl);
DisplayLoginForm = new Form();
DisplayLoginForm.SuspendLayout();
// size the login form
int dialogWidth = Constants.DEFAULT_POP_UP_WIDTH;
int dialogHeight = Constants.DEFAULT_POP_UP_HEIGHT;
if (PopUpHeight != 0 && PopUpWidth != 0)
{
dialogWidth = Convert.ToInt32(PopUpWidth);
dialogHeight = Convert.ToInt32(PopUpHeight);
}
DisplayLoginForm.Width = dialogWidth;
DisplayLoginForm.Height = dialogHeight;
DisplayLoginForm.Text = this.fldTargetSiteUrl;
DisplayLoginForm.Controls.Add(this.webBrowser);
DisplayLoginForm.ResumeLayout(false);
//DisplayLoginForm.Show();
Application.Run(DisplayLoginForm);
// see ClaimsWebBrowser_Navigated event
//DisplayLoginForm.Dispose();
return this.fldCookies;
}
The problem comes about with the Application.Run(DisplayLoginForm). If I step through the code line-by-line, everything works fine, and I get the results I need within my VBA code. However, if I run the program with F5 (either by building it in Debug mode or in Release mode), Application.Run(DisplayLoginForm) kills the application (and Excel along with it) once the cookie jar (my term, and most likely not a computer term) has been examined for valid cookies.
You can see in the code, I attempted to use DisplayLoginForm.Show(); rather than Application.Run, however I kept getting null references to the file I'm trying to find, so that approach does not work either.
So here's the question:
How do I go about popping up a web browser (which is obviously set up as a windows form), look for the cookies, prompt the user if needed, close the web browser and remain alive long enough to return the appropriate values (file.exists and file.islockedbyuser.email, both of which are in functions called by the VBA and both of which work just fine) to excel, and then finish up the program without shutting Excel down in the process?
The answer to this question is to set up a new and separate thread on which to operate the browser and login sequence, returning to the main thread (and the thread Excel is running on) the context with the credentials, with which the file can be queried.
I’m building an app that acts as a share target for URI’s; it takes the URI then URL for invokes the browser to our web site for sharing. I have the code working using the sharing target sample, however Launcher.LaunchUriAsync is always failing when I’m outside the debugger. It doesn’t throw though so I’m having a hard time figuring out what the error might be; maybe some security context.
Any ideas? The code itself is pretty short; I get success = false running directly from the shell and invoking via Win-C/Share. I’ve made sure the manifest has all three networking declarations set. Other thoughts?
if (this.shareOperation.Data.Contains(StandardDataFormats.Uri))
{
Uri uri = await this.shareOperation.Data.GetUriAsync();
if (uri != null)
{
Uri tempUri;
Uri.TryCreate("http://www.mysite.com/#/search?v=results&bk=1.0&q="+uri.ToString(), UriKind.Absolute, out tempUri);
bool success = await Windows.System.Launcher.LaunchUriAsync(tempUri);
if (success) {
contentValue.Text += "Success invoking browser" + ":URL="+tempUri.ToString()+ Environment.NewLine;
} else {
contentValue.Text += "Fail invoking browser" + ":URL=" + tempUri.ToString() + Environment.NewLine;
}
}
}
A sharing target shouldn't be launching another application. Share targets are meant to be hosted inside the sharing pane, and should provide a quick, in-context way for the user to share content with your app or service.
In your case, perhaps you should host a WebView and navigate that to your service's URL?
There are several conditions that needs to be met in order to successfully call LaunchUriAsync.
As seen here on MSDN you need to ensure the following:
The calling app must be visible to the user when the API is invoked.
Unless you are calling this API from a Classic Windows application, this API must be called from within an ASTA thread (also known as a UI thread).
You must specify the privateNetworkClientServer capability in the manifest in order to launch intranet URIs, for example a file:/// URI pointing to a network location.
You cannot use this method to launch a URI in the local zone. For example, apps cannot use the file:/// protocol to access files on the local computer. Instead, you must use the Storage APIs to access files.
I guess that one of the first two conditions is why your code fails. (At least that was my problem)