I'm trying to edit Skype's config.xml file from code. It works fine, but after change Skype delete it and generate another one, undoing all my changes. For example, code:
public Core()
{
try
{
var processes = Process.GetProcessesByName("Skype");
if (processes.Length == 0)
{
AddRegistryKeys();
RemovePlaceholder();
}
else
{
RestartSkypeAndRun(processes[0],
() =>
{
AddRegistryKeys();
RemovePlaceholder();
});
}
Environment.Exit(0);
}
catch (Exception ex)
{
MessageBox.Show(string.Format("{0} - {1}", ex.GetType(), ex.Message), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Environment.Exit(-1);
}
}
private static void RemovePlaceholder()
{
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string skypePath = Path.Combine(appDataPath, "Skype");
foreach (var configPath in Directory.EnumerateFiles(skypePath, "config.xml", SearchOption.AllDirectories))
{
string userConfig = File.ReadAllText(configPath);
string fixedConfig = userConfig.Remove("<AdvertPlaceholder>1</AdvertPlaceholder>");
File.Move(configPath, configPath + ".bak");
File.WriteAllText(configPath, fixedConfig);
}
}
private static void RestartSkypeAndRun(Process skypeProc, Action action)
{
string skypeExePath = skypeProc.Modules[0].FileName;
skypeProc.Kill();
skypeProc.WaitForExit();
Thread.Sleep(TimeSpan.FromMilliseconds(500)); //just in case
action();
Process.Start(skypeExePath);
}
So how can it be done? I have no idea, except blocking file modification, e.g. change ACL and other permissions for file, set readonly attribute e.t.c.
See https://www.safaribooksonline.com/library/view/skype-hacks/0596101899/ch04s04.html
"Always stop Skype from running (by right-clicking on Skype in the system tray and choosing Quit) before making any changes to config.xml (or shared.xml), because even though your editor may tell you it has saved your updated version of config.xml, you may find that Skype ignores your changes and they are missing when you reopen config.xml. The procedure for editing any of Skype's configuration files should go like this: quit Skype (that is, stop it from running), edit (or delete) the configuration file, save the changes, and restart Skype."
C:\Documents and Settings\Username\Application Data\Skype\Skypename\config.xml
"There is another file, shared.xml, from which Skype obtains configuration information that is common to all users of Skype on the same Windows machine... You also can edit this file to tweak how Skype behaves, but the scope for tweaking is far more limited than for config.xml. You typically can find shared.xml in these locations on each platform:
Windows (version 1.3 and before)
C:\Documents and Settings\All Users\Application Data\Skype\shared.xml
Windows (version 1.4 and after)
C:\Documents and Settings\Username\Application Data\Skype\shared.xml
"
Related
thanks because you has been come to this post.
I have an error with my script, that log says:
Access to the path 'C:\Windows\system32\Com\dmp' is denied.
I want to set my application to windows startup, so when that computer client started, my software is automatically running. So i put this script on my Main Load.
private void Main_Load(object sender, EventArgs e)
{
//Menjadikan software ke dalam Startup Windows, sehingga dapat berjalan ketika pc pertama kali dinyalakan
RegistryKey reg = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
reg.SetValue("PR Reminder", Application.ExecutablePath.ToString());
listMapel();
bool notif = Properties.Settings.Default.Notification;
if (notif == true)
{
checkExpired(); //Mengecek tanggal penyerahan dan pemberian
}
The result is work. But I'm getting an error like this.
After explored more deeply, the center of the issue is the method listMapel();
where he was tasked to search for files ending in .db in the local directory.
I dont know why this method is got error. When i try to remove this method, my application running fine when startup.
I think the problem is on system.io.
This is my listMapel(); method script
public void listMapel()
{
comboListMapel.Items.Clear();
string path = Directory.GetCurrentDirectory(); //Lokal direktori
string[] files = Directory.GetFiles(path, "*.db", SearchOption.AllDirectories);
foreach (string file in files)
{
nama = file.Split(".".ToCharArray()); //Hasil result yang ditampilkan Matapelajaran.db (Tapi dengan ini kita mengambil string sebelum .db
comboListMapel.Items.Add(Path.GetFileName(nama[0]));
}
}
You should always run as an administrator.
Hope this helps link
And another one
Give the access to your file like FileMode.Create, FileAccess.Write, FileShare.None
try this it will may work.
I've written a simple windows service to watch a folder and run relog (the windows tool to export data from binary perf mon files) on any files that arrive.
When I run it from my c# process (using System.Diagnostics.Process.Start()) I get:
Error:
Unable to open the specified log file.
But if I copy and paste the command into a console window it works fine.
I've looked all over the net but everything seems to point to a corrupt file, which I know is not the case as I can import perfectly when running manually.
Any help greatly appreciated.
If you are using FileSystemWatcher to monitor for files it will fire the created event before the file is completely written to disk, this would cause the kind of error from relog about being unable to "open" a file since it might still be locked and technically corrupt as far as it's concerned.
I've written the following helper method that I always use in conjunction with FileSystemWatcher to wait for a file to be completely written and ready for processing after a created event and will also kick out after a timeout:
public static bool WaitForFileLock(string path, int timeInSeconds)
{
bool fileReady = false;
int num = 0;
while (!fileReady)
{
if (!File.Exists(path))
{
return false;
}
try
{
using (File.OpenRead(path))
{
fileReady = true;
}
}
catch (Exception)
{
num++;
if (num >= timeInSeconds)
{
fileReady = false;
}
else
{
Thread.Sleep(1000);
}
}
}
return fileReady;
}
I have an application written in C#, and I am seeking to write some information to the hidden ProgramData in order to access the same connection string from both the application's front end and back end.
I am accessing the directory using path variables as follows:
private bool ProgramDataWriteFile(string contentToWrite)
{
try
{
string strProgramDataPath = "%PROGRAMDATA%";
string directoryPath = Environment.ExpandEnvironmentVariables(strProgramDataPath) + "\\MyApp\\";
string path = Environment.ExpandEnvironmentVariables(strProgramDataPath)+"\\MyApp\\ConnectionInfo.txt";
if (Directory.Exists(directoryPath))
{
System.IO.StreamWriter file = new System.IO.StreamWriter(path);
file.Write(contentToWrite);
file.Close();
}
else
{
Directory.CreateDirectory(directoryPath);
System.IO.StreamWriter file = new System.IO.StreamWriter(path);
file.Write(contentToWrite);
file.Close();
}
return true;
}
catch (Exception e)
{
}
return false;
}
This seems to work correctly. However, my question is, when I used this path variable: %AllUsersProfile%(%PROGRAMDATA%)
instead, it expanded into an illegal(and redundant) file path : C:\ProgramData(C:\ProgramData)\
However, I thought that the latter path variable was the correct full name. Was I just using it incorrectly? I need to ensure that this connection info will be accessible to all users, will just using %PROGRAMDATA% allow that? I am using Windows 7 in case that is relevant.
From here:
FOLDERID_ProgramData / System.Environment.SpecialFolder.CommonApplicationData
The user would never want to browse here in Explorer, and settings changed here should affect every user on the machine. The default location is %systemdrive%\ProgramData, which is a hidden folder, on an installation of Windows Vista. You'll want to create your directory and set the ACLs you need at install time.
So, just use %PROGRAMDATA%, or better still:
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)
I have a windows service which polls for a specific folder for creation of new files. This works fine when the folder is in one of the local drives such as C: or D:
The service fails to find a folder on a mapped drive.
Here is the code which does the checking for folder exist before polling:
System.Security.Principal.WindowsIdentity userIdentity =
System.Security.Principal.WindowsIdentity.GetCurrent();
System.Security.Principal.WindowsPrincipal principal =
new System.Security.Principal.WindowsPrincipal(userIdentity);
MappedDriveResolver mdr = new MappedDriveResolver();
if (mdr.isNetworkDrive(folderPath))
{
LoggingAppWrapper.LogDeveloperMessage(folderPath + " is on a Mapped drive", 1, TraceEventType.Information, string.Empty);
}
MappedDriveResolver is a class that I found hereHow do I determine a mapped drive's actual path?
The code in that link works fine from a simple console application, but fails when it is part of windows service.
Any suggestions as to what has to be done for the code to work for a windows service?
Regards.
I would recommend you configure your service to use UNC paths for folders not on the server running the service.
Mapped drives are a usability feature for users and as such they are specific to that users profile/environment. Meaning, when you login you may have a drive X: that is mapped to \\server1\share1 but when I login my drive X: could be mapped to \\server2\share2 instead. The actual mapping process is either saved as part of your profile with the "Reconnect at logon" or is handled by a logon script.
You need to check what account the service is running under and make sure that mapped drive exists for that user environment (This might help How to map a network drive to be used by a service).
Edit:
The reason your console application works and the service doesn't is because of the differences between the environment they are running in.
To illustrate this, take this console application, compile it and then run it as a Schedule Task. Set the "path" variable to be a mapped drive that your user can access.
static void Main(string[] args) {
MappedDriveResolver mdr = new MappedDriveResolver();
string logfile;
string path = #"I:\";
string[] files;
// Write out "log" file to where this is running from
logfile = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
logfile = Path.Combine(logfile, "log.txt");
using (StreamWriter sw = new StreamWriter(logfile, true)) {
try {
sw.WriteLine("Checking path " + path);
if (mdr.isNetworkDrive(path)) {
sw.WriteLine("Network Drive: Yes");
} else {
sw.WriteLine("Network Drive: No");
}
} catch (Exception ex) {
sw.WriteLine("Exception: " + ex.Message);
}
try {
sw.WriteLine("Resolve path " + path);
string newpath = mdr.ResolveToUNC(path);
sw.WriteLine("Resolved path " + newpath);
} catch (Exception ex) {
sw.WriteLine("Exception: " + ex.Message);
}
try {
sw.WriteLine("Get file list from " + path);
files = Directory.GetFiles(path);
if (files == null || files.Length == 0) {
sw.WriteLine("No files found");
} else {
sw.WriteLine(string.Format("Found {0} files.", files.Length));
}
} catch (Exception ex) {
sw.WriteLine("Exception: " + ex.Message);
}
sw.Flush();
sw.Close();
}
}
Note: This is with the Windows 7 Task Scheduler
Test 1: Just run the app by double-clicking on it.
Result: Success
Test 2: Configure scheduled task to run as your user account with "Run only when user is logged on"
Result: Success
Test 3: Configure scheduled task to run as your user account with "Run whether user is logged on or not"
Result: Exceptions
Test 4: Configure schedule task to run as "Local Service" account.
Result: Exceptions
Test 1 & 2 work because they are using the currently logged in user environment including the mapped drives that are part of it.
Test 3 & 4 fail because they have their own user environment created for them, which does not have any mapped drives configured. It escapes me at the moment what the differences there are, but an "interactive" and "non-interactive" environment are different in some significant ways.
I have a small deploy tool that I'm upgrading. The tool takes a version of code from the build box, updates SVN, and then plops it on X servers (A deploy moves specific parts of the deploy installs to different servers within the stack).
What is happening now is when it's ran on anything other than our build box, it will not work due to securities.
Our build box is internal and on our own domain. The servers we're copying to are on a high security domain. I have used the techniques explained here: Accessing Password Protected Network Drives in Windows in C#? for accessing files / data on those domain drives so i don't need to map it.
But here's the catch.
Build box - Domain A
Deploy Server - Domain B
Deploy Server 2 - Domain B
My box has complete control over our Build Box because the dev's run as administrators, and it is on our domain. However, once I impersonate my login so I'm on Domain B, I can't access my Domain A build box.
This is an internal utility, and any help would be appreciated.
*If there's extensive work on this instead of copying I can open new threads and run a command line to get these files from SVN on each server as that is a possibility instead of copying. We keep all deploy install files in SVN.
IntPtr token;
if (!Security.Access.LogonUser("ChuckNorris", "a_small_bunny[0]", "OfficeSpace", Security.Enums.LogonType.NewCredentials, Security.Enums.LogonProvider.Default, out token))
{
throw new Win32Exception();
}
try
{
IntPtr dToken;
if (!Security.Access.DuplicateToken(token, Security.Enums.SecurityImpersonationLevel.Impersonation, out dToken))
throw new Win32Exception();
try
{
using (WindowsImpersonationContext iContext = new WindowsIdentity(dToken).Impersonate())
{
Directory.CreateDirectory(destDir); //Works Here as I have impersonation
// copy each file to destination
//This will bomb as my user is now linked to the prod domain.
foreach (string file in Directory.GetFiles(srcDir))
{
// update property bag
UpdatePropertyBag(
propertyBag,
PropertyBag.Step,
"Copying [" + file + "] to [" + destDir + "]");
// copy each file
File.Copy(file, CombinePath(destDir, Path.GetFileName(file)));
}
// deal with each file/folder
foreach (string dir in Directory.GetDirectories(srcDir))
{
// copy each subdirectory
CopyDirectory(propertyBag, srcDir, destDir, Path.GetFileName(dir));
}
iContext.Undo();
}
}
catch (Exception ex)
{
}
finally
{
if (dToken != IntPtr.Zero)
{
if (!Security.Access.CloseHandle(dToken))
{
// Uncomment if you need to know this case.
////throw new Win32Exception();
}
}
}
}
catch (Exception ex)
{
}
finally
{
if (token != IntPtr.Zero)
{
if (!Security.Access.CloseHandle(token))
{
// Uncomment if you need to know this case.
////throw new Win32Exception();
}
}
}
I may have missed something in the flow above but can you:
Impersonate domain A
Copy to a shared location with permissions for both domains.
Impersonate domain b, move to final location.
Other options are to read the file details, load into memory, and write to the destination and preserve timestamp if necessary.