Shortenned path still throwing PathTooLongException - c#

I need to create files with path exceeding the MAX_PATH limit. What I expected to work is to shorten the already existing directory name like this:
public static String GetShortPathName(String longPath)
{
StringBuilder shortPath = new StringBuilder(longPath.Length + 1);
if (0 == GetShortPathName(longPath, shortPath, shortPath.Capacity))
{
throw new Exception("Path shortenning failed");
}
return shortPath.ToString();
}
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern Int32 GetShortPathName(String path, StringBuilder shortPath, Int32 shortPathLength);
and then use the result to create the new file like:
using (FileStream writeStream = File.Create(shortPath + newFile))
...
But it still throws PathTooLongException like before. Any idea why?
I know I can use Delimon Lib or other lib, but I just cannot figure out why it does not work.
Thanks a lot.

Related

How do you automatically close a specific excel file when it is already open (without killing excel)?

Is it possible to close an excel file when it is already open? I have written a code that can determine if a specific excel file is already open, however I cannot close the file once it has been determined to be open. I have tried the following method (see below) to close a workbook and excel application:
// The name of my workbook is "workbook", while the Excel application is named "excel."
workbook.Close(true);
excel.Quit();
Performing the latter code does not close the already open Excel window. It may also be of assistance to know the code I am using to determine if a file is open (it is provided below):
// The following checks to see if a file is open and returns truth1 as "true" if the file is open and "false" if the file is closed.
file = new FileInfo(file_name);
truth1 = IsFileinUse(file);
// ...
protected static bool IsFileinUse(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
return true;
}
finally
{
if (stream != null)
stream.Close();
}
return false;
}
Again, I cannot create a program in which I "kill Excel". I just need know how to close an already open Excel window if its path is the same as the one I am trying to read and write to.
Please have a look on below sample code :-
using Excel = Microsoft.Office.Interop.Excel;
Excel.Application exl = new Excel.Application();
# open a file
Excel.Workbook wbook = exl.Workbooks.Open("some_file.xlsx");
# To close the file
wbook.Close();
exl.Quit();
Edit 1:-
You can refer below link if above solution not works for you :-
Closing an Excel Workbook
You can use the Windows API, to close a certain Window by it's title.
This will invoke a Window-Close, so it will prompt the user if he really wants to close:
using System.Runtime.InteropServices;
...
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
const UInt32 WM_CLOSE = 0x0010;
And then
IntPtr windowPtr = FindWindowByCaption(IntPtr.Zero, "MyFile.xlsx - Excel");
if (windowPtr == IntPtr.Zero)
{
MessageBox.Show("Document not open");
return;
}
SendMessage(windowPtr, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
If you need to force a close, even if the file has been modified, you only can kill the related excel-process. But keep in mind that this will forcefully kill other excel-windows as well, if they are running within the same excel-process-instance.
using System.Diagnostics;
...
Process[] processes = Process.GetProcesses();
foreach (Process p in processes)
{
if (p.MainWindowTitle == "MyFile.xlsx - Excel")
{
p.Kill();
break;
}
}

Xna not writing onto console

While working on a project of mine. I found the need to have the normal console aplication for changing numbers and putting them out. I found out a post that made that pretty easy, but it doesn't output anything. it opens the console aplication and the name changes, but there is no output.
This is what i use to open it
[DllImport("kernel32")]
static extern bool AllocConsole();
private void UseConsole(object sender)
{
AllocConsole();
Console.Title = "Output";
Console.Write("hello world");
}
If you know what might help to get an output. that would be great
Thanks already
Dan
I had the same problem when trying to create a console with my XNA/FNA application. All the common solutions found didn't worked: the written console lines were printed into the "Output" window of Visual Studio (Community), but when the application was started by executing the game directly (outside of Visual Studio), the console window remained empty. The following answer on a similar question worked for me: https://stackoverflow.com/a/34170767 by https://stackoverflow.com/users/1087922/zunair
The copied code:
using System;
using System.Windows.Forms;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace WindowsApplication
{
static class Program
{
[DllImport("kernel32.dll",
EntryPoint = "GetStdHandle",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll",
EntryPoint = "AllocConsole",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern int AllocConsole();
private const int STD_OUTPUT_HANDLE = -11;
private const int MY_CODE_PAGE = 437;
static void Main(string[] args)
{
Console.WriteLine("This text you can see in debug output window.");
AllocConsole();
IntPtr stdHandle=GetStdHandle(STD_OUTPUT_HANDLE);
SafeFileHandle safeFileHandle = new SafeFileHandle(stdHandle, true);
FileStream fileStream = new FileStream(safeFileHandle, FileAccess.Write);
Encoding encoding = System.Text.Encoding.GetEncoding(MY_CODE_PAGE);
StreamWriter standardOutput = new StreamWriter(fileStream, encoding);
standardOutput.AutoFlush = true;
Console.SetOut(standardOutput);
Console.WriteLine("This text you can see in console window.");
MessageBox.Show("Now I'm happy!");
}
}
}

C# open file dialog; specify name and extension?

In C#, you can specify a filter on an OpenFileDialog object.
var dlg = new OpenFileDialog();
dlg.DefaultExt = ".xml";
dlg.Filter = "XML Files|*.xml";
Is there a way to automatically select files by name? For example, if I navigated to a folder of xml files, is there any filtering option that would automatically target "myxml.xml"?
Yes, just set the FileName property of the OpenFileDialog like this:
dlg.FileName = "myxml.xml";
However, it would be more appropriate if you use the name in the filter. Just place it instead of the star which acts as a wildcard:
dlg.Filter = "XML Files|myxml.xml";
And always remember you can have multiple filters like this: (It may be useful in the future):
"Image Files (*.bmp, *.jpg)|*.bmp;*.jpg"
// -- OR --
"Text Files (*.txt)|*.txt|All Files (*.*)|*.*"
More documentation on filters at MSDN.
Yes, you can actually set the filter to a complete filename:
dlg.Filter = "myxml Files|myxml.xml";
Note that when this filter is selected, you won't be able to select other XML files. If you simply want to default to that filename while showing and allowing selection of any XML file, go with Fᴀʀʜᴀɴ Aɴᴀᴍ's (original) answer. And now that he copied my answer into his, you can just go with his.
What you can do is either set the FileName property like this:
dlg.FileName = "myxml.xml";
or set the Filter property like this:
dlg.Filter = "XML files|file.xml";
(it's important to check that there's no space at the end like this "file.xml ", because if there is, your file won't show up, in other words OpenFileDialog doesn't trim the Filter property)
if you don't know what the file name is beforehand, you can use DirectoryInfo and FileInfo like this:
DirectoryInfo dir = new DirectoryInfo("PATHHERE");
FileInfo[] files = dir.GetFiles();
and loop through the files to find the one you are looking for
Step 1: Add this method to your code:
[DllImport("shell32.dll", SetLastError = true)]
public static extern int SHOpenFolderAndSelectItems(IntPtr pidlFolder, uint cidl, [In, MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, uint dwFlags);
[DllImport("shell32.dll", SetLastError = true)]
public static extern void SHParseDisplayName([MarshalAs(UnmanagedType.LPWStr)] string name, IntPtr bindingContext, [Out] out IntPtr pidl, uint sfgaoIn, [Out] out uint psfgaoOut);
public static void OpenFolderAndSelectItem(string folderPath, string file)
{
IntPtr nativeFolder;
uint psfgaoOut;
SHParseDisplayName(folderPath, IntPtr.Zero, out nativeFolder, 0, out psfgaoOut);
if (nativeFolder == IntPtr.Zero)
return;
IntPtr nativeFile;
SHParseDisplayName(System.IO.Path.Combine(folderPath, file), IntPtr.Zero, out nativeFile, 0, out psfgaoOut);
IntPtr[] fileArray;
if (nativeFile == IntPtr.Zero)
{
fileArray = new IntPtr[0];
}
else
{
fileArray = new IntPtr[] { nativeFile };
}
SHOpenFolderAndSelectItems(nativeFolder, (uint)fileArray.Length, fileArray, 0);
Marshal.FreeCoTaskMem(nativeFolder);
if (nativeFile != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(nativeFile);
}
}
Step 2: Call the method OpenFolderAndSelectItem(string folderPath, string file) to use.
Step 3: Enjoy!

Handle PathtoolongException with Shareddrive [duplicate]

I having trouble of copying some folder 260+ chars (for example: F:\NNNNNNNNNNNNNNNN\NNNNNNNNNNN\ROOT\$RECYCLE.BIN\S-1-5-21-3299053755-4209892151-505108915-1000\$RMSL3U8\NNNNNNNNN NNNNNNNN\NNNNNNNNNNN\NNNNNNNNNN\NNNNNNNNNN\publish\Application Files\TNNNNNNNNNNNN_1_0_0_0\NNNNNNNNNNNN.exe.manifest) to some other place with standart DrectoryInfo.Create(); adding \?\ or \?\UNC\ (like "\\?\UNC\") just throw another ArgumentException.
What am i doing wrong? What else i can do without using Directory.SetCurrentDirectory() ?
Actually you need to call win32 from c#. We have done this
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
public static class LongPath
{
static class Win32Native
{
[StructLayout(LayoutKind.Sequential)]
public class SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr pSecurityDescriptor;
public int bInheritHandle;
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CreateDirectory(string lpPathName, SECURITY_ATTRIBUTES lpSecurityAttributes);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, FileShare dwShareMode, SECURITY_ATTRIBUTES securityAttrs, FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
}
public static bool CreateDirectory(string path)
{
return Win32Native.CreateDirectory(String.Concat(#"\\?\", path), null);
}
public static FileStream Open(string path, FileMode mode, FileAccess access)
{
SafeFileHandle handle = Win32Native.CreateFile(String.Concat(#"\\?\", path), (int)0x10000000, FileShare.None, null, mode, (int)0x00000080, IntPtr.Zero);
if (handle.IsInvalid)
{
throw new System.ComponentModel.Win32Exception();
}
return new FileStream(handle, access);
}
}
A sample code:
string path = #"c:\".PadRight(255, 'a');
LongPath.CreateDirectory(path);
path = String.Concat(path, #"\", "".PadRight(255, 'a'));
LongPath.CreateDirectory(path);
string filename = Path.Combine(path, "test.txt");
FileStream fs = LongPath.Open(filename, FileMode.CreateNew, FileAccess.Write);
using (StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine("abc");
}
There's a great library on Microsoft TechNet for overcoming the long filenames problem, it's called Delimon.Win32.I​O Library (V4.0) and it has its own versions of key methods from System.IO
For example, you would replace:
System.IO.Directory.GetFiles
with
Delimon.Win32.IO.Directory.GetFiles
which will let you handle long files and folders.
From the website:
Delimon.Win32.IO replaces basic file functions of System.IO and
supports File & Folder names up to up to 32,767 Characters.
This Library is written on .NET Framework 4.0 and can be used either
on x86 & x64 systems. The File & Folder limitations of the standard
System.IO namespace can work with files that have 260 characters in a
filename and 240 characters in a folder name (MAX_PATH is usually
configured as 260 characters). Typically you run into the
System.IO.PathTooLongException Error with the Standard .NET Library.
Yes, using the standard APIs will give you this kind of limitations (255 chars IIRC).
From .NET you can use the AlphaFS project which lets you use very long paths (using the "\\?\" style) and mimics the System.IO namespace.
You will probably be able to use this library just as if you were using System.IO, for example : AlphaFS.Win32.Filesystem.File.Copy() instead System.IO.File.Copy()
If you don't want or cannot use AlphaFS you'll have to pinvoke the Win32 API

How to print QR Code using Commands with Zebra RW 420 thermal printer via USB in C#

Before you go on and flag my question as a duplicate, believe me, its
not. I have gone through virtually every solution provided here and I
still can't get to get my app to work, so please will you just be nice
and take some time to help me.
Scenario: I have a Zebra RW 420 thermal printer which I would like to use for printing vouchers with a QR Code on them. I am using C# and have followed all the help as given by Scott Chamberlain here and the code here for sending the commands to the printer. I have the EPL2 manual as well as the CPCL, and ZPL reference manuals with a whole lot of stuff on how to format my commands.
Problem:
All the commands I am sending are either printing as plain text replicas of the commands or the printer just hangs with the small message icon showing on its display. I have tried sending the same commands using the Zebra Utilitis and still getting the same result as with my sample app.
Below is the code snippets I have, please do advise me if there are any reference libraries I may require to get this to work.
private void btnPrint_Click(object sender, RoutedEventArgs e)
{
string s = "! 0 200 200 500 1\nB QR 10 100 M 2 U 10\nMA,QR code ABC123\nENDQR\nFORM\nPRINT";
// Have also tried \r\n for the line feeds with the same result.
// Allow the user to select a printer.
PrintDialog pd = new PrintDialog();
if ((bool)pd.ShowDialog())
{
var bytes = Encoding.ASCII.GetBytes(s);
// Send a printer-specific to the printer.
RawPrinterHelper.SendBytesToPrinter(pd.PrintQueue.FullName, bytes, bytes.Length);
}
}
PrinterHelper class as modified by Scott here
public class RawPrinterHelper
{
// Structure and API declarions:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DOCINFOA
{
[MarshalAs(UnmanagedType.LPStr)] public string pDocName;
[MarshalAs(UnmanagedType.LPStr)] public string pOutputFile;
[MarshalAs(UnmanagedType.LPStr)] public string pDataType;
}
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter,
IntPtr pd);
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level,
[In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);
[DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, byte[] pBytes, Int32 dwCount, out Int32 dwWritten);
// SendBytesToPrinter()
// When the function is given a printer name and an unmanaged array
// of bytes, the function sends those bytes to the print queue.
// Returns true on success, false on failure.
public static bool SendBytesToPrinter(string szPrinterName, byte[] pBytes, Int32 dwCount)
{
Int32 dwError = 0, dwWritten = 0;
IntPtr hPrinter = new IntPtr(0);
DOCINFOA di = new DOCINFOA();
bool bSuccess = false; // Assume failure unless you specifically succeed.
di.pDocName = "Zebra Label";
di.pDataType = "RAW";
// Open the printer.
if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
{
// Start a document.
if (StartDocPrinter(hPrinter, 1, di))
{
// Start a page.
if (StartPagePrinter(hPrinter))
{
// Write your bytes.
bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
EndPagePrinter(hPrinter);
}
EndDocPrinter(hPrinter);
}
ClosePrinter(hPrinter);
}
// If you did not succeed, GetLastError may give more information
// about why not.
if (bSuccess == false)
{
dwError = Marshal.GetLastWin32Error();
throw new Win32Exception(dwError);
}
return bSuccess;
}
}
I did a lot of work on Zebra ZT230 and GX430t printers last year, and the thing I found out about them was using the ZPL instructions over TCP sockets via port 9100 was a LOT more reliable.
I know this is taking your conversation in a very different direction, but having tried the spool / Win32 approach I can tell you using sockets was a lot more reliable. Let me know if you need some sample code.
Wrote a kiosk application using a KR403 last year. I was able to
successfully print and poll the status of the printer to see if there
was a paper jam low paper etc via usb using the blog post below.
http://danielezanoli.blogspot.com/2010/06/usb-communications-with-zebra-printers.html
Using print spooler (Print only)
https://sharpzebra.codeplex.com/SourceControl/latest#src/Com.SharpZebra/Printing/RawPrinter.cs
I used the ZebraDesigner to do my initial layout. On the print screen
inside the zebra designer there is a print to file option that will
save your design as a txt file with ZPL in it. I then took that file
broke it up into sections and created a helper class that uses a
StringBuilder internally so I could focus on certain pieces of the zpl
since it can be overwhelming to look at more than 1-2 lines.
var kioskTicketBuilder = new KioskTicketBuilder();
kioskTicketBuilder.SetPrinterDefaults();
kioskTicketBuilder.DisplayTicketHeader();
kioskTicketBuilder.DisplayInformationHeading(data.Name, data.todaysDate, data.ClientName, data.ClientCode);
kioskTicketBuilder.DisplayMoreStuff()
kioskTicketBuilder.DisplayBarcode(data.TrackingId);
kioskTicketBuilder.EndOfJob();
return kioskTicketBuilder.GetPrintJobToArray();
Also if you go to the the printer properties > Printing Defaults > Tools
Tab There is an option to send a file of zpl to the printer or send
individual commands. This is really good for testing your zpl seperate
from your application.

Categories