I am using folderBrowserDialog in my winform.
I need the default or initial path to be a network location.
for eg:
folderBrowserDialog1.SelectedPath = #"\\server1\foo\bar\";
This does not work. My system is on the right network and I am able to access the directory thru my browser and run command.
Is this a non-feature? or is there a work-around?
I would appreciate it if someone can guide me thru!
Thanks,
Ivar
In my experience, .NET has always been hit-or-miss with UNC paths. Sometimes it works and sometimes it doesn't. I'm sure there's a good explanation for it, but early on, I searched and searched without finding an answer.
Rather than deal with the issue, I just adopted the policy that it's better to map a drive myself and then disconnect when done in code. (If you find the answer, I'd be interested in knowing why this is, but since I have a working solution, I don't care enough to research it myself.) It works for us 100% of the time, and it's very easy. I created a class for doing it, since it's such a common task in our shop.
I don't know if you're open to the idea, at any rate, but if you're interested, and don't already have the code, our routine is pasted in below. It would be fairly simple to check for an open drive letter, and just map it, then disconnect when done.
public static class NetworkDrives
{
public static bool MapDrive(string DriveLetter, string Path, string Username, string Password)
{
bool ReturnValue = false;
if(System.IO.Directory.Exists(DriveLetter + ":\\"))
{
DisconnectDrive(DriveLetter);
}
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "net.exe";
p.StartInfo.Arguments = " use " + DriveLetter + ": " + Path + " " + Password + " /user:" + Username;
p.Start();
p.WaitForExit();
string ErrorMessage = p.StandardError.ReadToEnd();
string OuputMessage = p.StandardOutput.ReadToEnd();
if (ErrorMessage.Length > 0)
{
throw new Exception("Error:" + ErrorMessage);
}
else
{
ReturnValue = true;
}
return ReturnValue;
}
public static bool DisconnectDrive(string DriveLetter)
{
bool ReturnValue = false;
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "net.exe";
p.StartInfo.Arguments = " use " + DriveLetter + ": /DELETE";
p.Start();
p.WaitForExit();
string ErrorMessage = p.StandardError.ReadToEnd();
string OuputMessage = p.StandardOutput.ReadToEnd();
if (ErrorMessage.Length > 0)
{
throw new Exception("Error:" + ErrorMessage);
}
else
{
ReturnValue = true;
}
return ReturnValue;
}
}
Windows makes a temporary mapping when you access a network resource using the \\name convention. I am not sure if there's a provision to do the same from a .net app in a concise manner. You may want to map the drive first to a letter then access it using #"Z:\foo\bar\" but obviously mapping a drive may not be something you want to do if your app is deployed in a way that prevents it.
Related
I'm making an application where I have to enable and disable the UWF in Windows 10.
But I want to intercept the success or failure, the problem is that when I only displays a letter.
string output = string.Empty;
string error = string.Empty;
ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd", "/c uwfmgr.exe volume protect c:");
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardError = true;
processStartInfo.UseShellExecute = false;
processStartInfo.Verb = "runas";
Process process = Process.Start(processStartInfo);
using (StreamReader streamReader = process.StandardOutput)
{
output = streamReader.ReadToEnd();
}
using (StreamReader streamReader = process.StandardError)
{
error = streamReader.ReadToEnd();
}
if (!string.IsNullOrEmpty(error))
{
MessageBox.Show("Error: " + error);
return;
}
MessageBox.Show("OK: " + output);
Here comes the message box "OK U"
Thanks
Thank you for your reply.
I tried to read the articles but given my lack of experience I can apply what it says, Could you give me a little extra help?
The thing I noticed is that I can enable the UWF only if you use the following code
ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd", "/k uwfmgr.exe volume protect " + cmbBox_Disk.SelectedItem.ToString().Substring(0, 2) + " & exit");
processStartInfo.CreateNoWindow = false;
processStartInfo.WindowStyle = ProcessWindowStyle.Normal;
processStartInfo.UseShellExecute = true;
processStartInfo.Verb = "runas";
Process process = Process.Start(processStartInfo);
processStartInfo = new ProcessStartInfo("cmd", "/k uwfmgr.exe filter enable & exit");
processStartInfo.CreateNoWindow = false;
processStartInfo.WindowStyle = ProcessWindowStyle.Normal;
processStartInfo.UseShellExecute = true;
processStartInfo.Verb = "runas";
process = Process.Start(processStartInfo);
but the problem is that in this way if there is an error I can not agree with the user.
You can read the output of the shell, see this answer:
Process.start: how to get the output?
Unfortunately there is no good way to detect errors using process.
It would be better to use WMI and UWF's WMI provider:
See:
https://learn.microsoft.com/en-us/windows-hardware/customize/enterprise/uwf-wmi-provider-reference
Make sure you read the docs thoroughly though. For example, in order to protect a volume you need to run Protect(); on an instance which has 'currentSession = false'. This instance needs to be created by yourself.
It has some small caveats here an there.
I am encountering small problem with windows updates silent install.
Why I need it? I have bit copy of system disk which I am using for reinstall win7(with advantage of .net framework, visual studio, java and 50+ another apps installed in once).
Then I need install some important update. I coded small utillity in c#, working OK except
install is not silent even using startInfo.Arguments = "/quiet/norestart/passive";.
Not silent : I mean there are at least two windows like asking if I need install or reboot options in end.
Problem is spoken in another forum How are people deploying HOTFIXES .msu files?
but solution is a bit not clear for me. Does somebody know any way how fix it?
Again, startInfo.Arguments = "/quiet/norestart/passive"; or startInfo.Arguments = #"/qb!"+ "REBOOT=ReallySuppress"+ #"/qn"; are not working and in link is explained why.
textBox1.Text is location af all hotfixes and updates in one directory.
{
string[] filePaths = Directory.GetFiles(textBox1.Text);
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = true;
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
//startInfo.Arguments = "/quiet/norestart/passive";
for (int i = 0; i < filePaths.Length; i++)
{
label1.Text = "Working";
startInfo.FileName = filePaths[i];
startInfo.Arguments = #"/qb!"+ "REBOOT=ReallySuppress"+ #"/qn";
try
{
Process.Start(startInfo.FileName).WaitForExit();
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
label1.Text = " Done ";
}
For a start you're just chaining together the arguments without spaces and thus are only passing a single argument that likely won't work. Try
startInfo.Arguments = "/qb! REBOOT=ReallySuppress /qn"
Finally I bypassed it using pure CMD line. Silent install without windows except exceptions.
private void button1_Click(object sender, EventArgs e)
{
string[] filePaths = Directory.GetFiles(textBox1.Text);
Process process = new Process();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.EnableRaisingEvents = false;
for (int i = 0; i < filePaths.Length; i++)
{
if (i == 0) { label1.Text = "Working On first task"; }
process.StartInfo.Arguments = "/C " + "#" + "\"" + filePaths[i] + "\"" + " /quiet /norestart";
process.Start();
process.WaitForExit();
label1.Text = (100 * i / filePaths.Length).ToString() + " % is done";
}
label1.Text = "Done";
}
File.Move System.IO.IOException: "No more connections can be made to this remote computer at this time because there are already as many connections as the computer can accept".
I have a process running under SYS account. It is processing files on local HD and move them to a remote drive on a domain using impersonation.
Edit, added code sample:
The method bellow is called repeatedly (The Impersonation is a utility class I use for impersonation, this is irrelevant to the issue).
private void moveFileUsingImpersonation(string srcFilePath, string dstFilePath, string userName, string passWord)
{
WindowsImpersonationContext wic = null;
// move it to destination
try
{
wic = Impersonation.Impersonate(userName, passWord);
if (wic != null)
{
File.Move(srcFilePath, dstFilePath);
}
else
{
Console.WriteLine("moveFileUsingImpersonation, Failure to impersonate!");
}
}
catch(Exception ex)
{
Console.WriteLine("moveFileUsingImpersonation, Exception={0}", ex.ToString());
}
finally
{
Impersonation.UndoImpersonate(wic);
}
}
Edit, added code sample.
When the process is running on XP machine and the remote Drive is on either XP or Win7 machine the call to File.Move works just fine and move the required files. However when the process is running on Win7 and remote Drive is on Win7 machine the mentioned exception is thrown after 20 files have been moved.
I've also tried to call the win32 API MoveFileEx with the MOVEFILE_REPLACE_EXISTING & MOVEFILE_COPY_ALLOWED & MOVEFILE_WRITE_THROUGH flags, with the same result - ERROR_REQ_NOT_ACCEP 71 (0x47).
It seems that the underlying connection made by the call to File.Move isn't closed properly on Win7.
Is there a way to overcome this?
What am I missing here?
Thanks, Ilan
Based on your code, you're probably copying using a UNC path. I've alway had issues doing this, and I've learned it's best to just map and then disconnect drives in code as needed. It saves me from having to deal with permissions issues, and also issues like the one you're describing.
We have a class that handles this for us. We've been using it for over 5 years with no issues, including on Win7 machines on both the code and remote side. Hoefully it will work for you as well.
public static class NetworkDrives
{
public static bool MapDrive(string DriveLetter, string Path, string Username, string Password)
{
bool ReturnValue = false;
if(System.IO.Directory.Exists(DriveLetter + ":\\"))
{
DisconnectDrive(DriveLetter);
}
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "net.exe";
p.StartInfo.Arguments = " use " + DriveLetter + ": " + '"' + Path + '"' + " " + Password + " /user:" + Username;
p.Start();
p.WaitForExit();
string ErrorMessage = p.StandardError.ReadToEnd();
string OuputMessage = p.StandardOutput.ReadToEnd();
if (ErrorMessage.Length > 0)
{
throw new Exception("Error:" + ErrorMessage);
}
else
{
ReturnValue = true;
}
return ReturnValue;
}
public static bool DisconnectDrive(string DriveLetter)
{
bool ReturnValue = false;
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "net.exe";
p.StartInfo.Arguments = " use " + DriveLetter + ": /DELETE";
p.Start();
p.WaitForExit();
string ErrorMessage = p.StandardError.ReadToEnd();
string OuputMessage = p.StandardOutput.ReadToEnd();
if (ErrorMessage.Length > 0)
{
throw new Exception("Error:" + ErrorMessage);
}
else
{
ReturnValue = true;
}
return ReturnValue;
}
}
I'm trying to use the following C# code to compile Java using javac:
Process p = new Process();
p.StartInfo.FileName = "javac";
Directory.CreateDirectory(Application.StartupPath + #"/TempJava");
p.StartInfo.Arguments = "-d "Application.StartupPath + #"/TempJava" + files;
p.Start();
"files" represents a string variable containing the name(s) of the *.java files.
All in all, I want to create a new folder, and then take the Java files (from where ever they may be located) and compile it into a class file(s) in TempJava.
For some reason, the code doesn't work, no errors, no warnings, but when I run it and check TempJava, there's no files in it.
Just because your child process ends with a possible error, it doesn't mean your parent process must be aware of it.
Inspect the process' exit code and standard output stream, and especially the standard error stream. Your answer lies in there...
here i have 2 buttons run and compile here is some code to help.
private void comp_Click(object sender, EventArgs e)
{
string text = "javac " + label1.Text + file + "#pause" + "#stop";
text = text.Replace("#", System.Environment.NewLine);
File.WriteAllText(label1.Text + "Compile.bat", text);
Process proc = null;
try
{
proc = new Process();
proc.StartInfo.FileName = label1.Text + "Compile.bat";
proc.StartInfo.CreateNoWindow = false;
proc.Start();
proc.WaitForExit();
}
catch
{
}
}
private void runp_Click(object sender, EventArgs e)
{
string news = file.Remove(file.Length - 5);
string text = "java " + news + "#pause";
text = text.Replace("#", System.Environment.NewLine);
File.WriteAllText(label1.Text + "Run.bat", text);
Process proc = null;
try
{
proc = new Process();
proc.StartInfo.FileName = label1.Text + "Run.bat";
proc.StartInfo.WorkingDirectory = label1.Text.Remove(label1.Text.Length - 1);
proc.StartInfo.CreateNoWindow = true;
proc.Start();
proc.WaitForExit();
}
catch
{
}
}
all i really do is create a batch and run it using c#.
how to pass html as a string instead of url in wkhtmltopdf using asp.net, c#?
STDIn and STDOut have been redirected in this example, so you shouldn't need files at all.
public static class Printer
{
public const string HtmlToPdfExePath = "wkhtmltopdf.exe";
public static bool GeneratePdf(string commandLocation, StreamReader html, Stream pdf, Size pageSize)
{
Process p;
StreamWriter stdin;
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = Path.Combine(commandLocation, HtmlToPdfExePath);
psi.WorkingDirectory = Path.GetDirectoryName(psi.FileName);
// run the conversion utility
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
// note: that we tell wkhtmltopdf to be quiet and not run scripts
psi.Arguments = "-q -n --disable-smart-shrinking " + (pageSize.IsEmpty? "" : "--page-width " + pageSize.Width + "mm --page-height " + pageSize.Height + "mm") + " - -";
p = Process.Start(psi);
try {
stdin = p.StandardInput;
stdin.AutoFlush = true;
stdin.Write(html.ReadToEnd());
stdin.Dispose();
CopyStream(p.StandardOutput.BaseStream, pdf);
p.StandardOutput.Close();
pdf.Position = 0;
p.WaitForExit(10000);
return true;
} catch {
return false;
} finally {
p.Dispose();
}
}
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0) {
output.Write(buffer, 0, read);
}
}
}
Redirecting STDIN is probably the easiest way to accomplish what you're trying to do.
One method of redirecting STDIN with wkhtmltopdf (in ASP.Net) is as follows:
private void WritePDF(string HTML)
{
string inFileName,
outFileName,
tempPath;
Process p;
System.IO.StreamWriter stdin;
ProcessStartInfo psi = new ProcessStartInfo();
tempPath = Request.PhysicalApplicationPath + "temp\\";
inFileName = Session.SessionID + ".htm";
outFileName = Session.SessionID + ".pdf";
// run the conversion utility
psi.UseShellExecute = false;
psi.FileName = "c:\\Program Files (x86)\\wkhtmltopdf\\wkhtmltopdf.exe";
psi.CreateNoWindow = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
// note that we tell wkhtmltopdf to be quiet and not run scripts
// NOTE: I couldn't figure out a way to get both stdin and stdout redirected so we have to write to a file and then clean up afterwards
psi.Arguments = "-q -n - " + tempPath + outFileName;
p = Process.Start(psi);
try
{
stdin = p.StandardInput;
stdin.AutoFlush = true;
stdin.Write(HTML);
stdin.Close();
if (p.WaitForExit(15000))
{
// NOTE: the application hangs when we use WriteFile (due to the Delete below?); this works
Response.BinaryWrite(System.IO.File.ReadAllBytes(tempPath + outFileName));
//Response.WriteFile(tempPath + outFileName);
}
}
finally
{
p.Close();
p.Dispose();
}
// delete the pdf
System.IO.File.Delete(tempPath + outFileName);
}
Note that the code above assumes that there's a temp directory available in your application directory. Also, you must explicitly enable write access to that directory for the user account used when running the IIS process.
I know this is an older post, but I want future developers to have this option. I had the same need, and the idea of having to start a background process just to get a PDF inside of a web app is terrible.
Here's another option: https://github.com/TimothyKhouri/WkHtmlToXDotNet
It's a .NET native wrapper around wkhtmltopdf.
Sample code here:
var pdfData = HtmlToXConverter.ConvertToPdf("<h1>COOOL!</h1>");
Note, it's not thread-safe as of right now - I'm working on that. So just use a monitor or something or a lock.