I created a small app using .NET framework 4 which processes info copied from an Excel spreadsheet and saves the processed data to the clipboard.
The problem is that when the app finishes, Excel's focus is still on the cell from which the data was copied.
My info is in the Office clipboard, but I have to manually remove focus before I can paste it. I would like my app to remove the focus for me, in order to simplify the process. How can this be done?
try
{
Clipboard.Clear();
}
catch (Exception)
{
MessageBox.Show("Clipbour Clear Error");
}
try
{
Clipboard.SetText(clipbourholder.ToString(), TextDataFormat.UnicodeText);
}
catch (Exception)
{
MessageBox.Show("Clipbour Paste Error");
}
When information is in clipboard excel has this border around cells, which i dont like because it is active clipboard. I need mine info in active office clipboard.
Active clipbourd example
I found workaround for that. I generated 64k number and puted to clipbourd and then i could pass my real value. It looks like only mine excel had this issue.
Related
I use the EPPlus library to batch edit some existing XLSM files. Inside the files I replace a line of VBA code and that's it. Everything works nice, if I edit the same line in the Excel code editor by hand.
When I open some of the files with Excel 2013 (15.0.4989.1000), the following error message is shown.
We found a problem with some content in 'test.xlsm'. Do you want us to
recover as much as we can? If you trust the source of this workbook,
click Yes.
If I click yes, the repair report shows the following entry. But the message is somewhat too generic to help me further.
Removed Records: Named range from /xl/workbook.xml-Part (Arbeitsmappe)
This is my C# code, which edits the XLSM file. Can I update my code or do I have to update the XLSM-file before editing it?
static void PatchVba(string filePath, string oldCode, string newCode)
{
var wbFileInfo = new FileInfo(filePath);
using (var package = new ExcelPackage(wbFileInfo, false))
{
foreach (var m in package.Workbook.VbaProject.Modules)
{
if (m.Code.Contains(oldCode))
{
m.Code = m.Code.Replace(oldCode, newCode);
Console.WriteLine("VBA Patched in \"{0}\"", filePath);
}
}
try
{
package.SaveAs(wbFileInfo);
}
catch
{
Console.WriteLine("Could not save patched file \"{0}\".", filePath);
}
}
}
I found out what the problem is. In the edited XLSM-file, a range name is used multiple times with overlapping scope. I was too focused on my C# code to find the root cause.
So removing the named ranges solves the issue. But it would still be interesting to know, why I can edit it without problems using Excel, but not by using EPPlus.
I am working on a project that I need to do the following:
I need to rename an image file. (Open an image from folder, and give a name & save it in to same folder)
try
{
string oldFileName = #"path\to\person1.jpg";
string desFileName = #"path\to\person2.jpg";
File.Copy(oldFileName, desFileName, true);
if (File.Exists(oldFileName))
{
File.Delete(#oldFileName);
}
}
catch (Exception ex)
{
}
I did rename the file using above way.
This process copy the old file with new name, but couldn't remove old file
Exception message :
The process cannot access the file 'path\to\person1.jpg' because it is
being used by another process.
How to resolve this? Please suggest any way to detect copying process has complete or not.
Your copy process is definatly complete on if statement becouse your code is sync.
I bet you got this error becouse file is used by another proccess (not your programm). Maby you have paint open or something else.
You should find it out with process monitor or something else. Check this question.
I am trying to read an excel file every 2 seconds, This file is getting updated by other RTD application.
I am able to read this file by Oledb connection, but problem comes when i am trying to read it every 2 seconds. Out of 10 attempts it is able to read 4-5 times only and at other attempts ,it throws exception.
Connection String
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\nids\shes.xlsm;Extended Properties="Excel 12.0 Macro;HDR=Yes;IMEX=1"
Code
//opening connection to excel file
using (OleDbConnection connection = new OleDbConnection(constr))//constr = connection string
{
try
{
connection.Open();
isconopen = true;
}
catch
{
dispatcherTimer2.Start();
connection.Close();
isconopen = false;
}
// If connection is ok , then query sheet
if (isconopen == true)
{
strcon = "SELECT * FROM [" + dsheet + "]";
using (OleDbDataAdapter adapter = new OleDbDataAdapter(strcon, connection))
{
try
{
adapter.Fill(result);
isread = true;
adapter.Dispose();
connection.Close();
}
catch
{
isread = false;
dispatcherTimer2.Start();
adapter.Dispose();
connection.Close();
}
}
}
//if able to retrieve data then call some other function
if (isread == true)
{
converToCSV(0);// for further processing
}
Please help me , i am trying this from last 1 month. Please please please please help me out
Sadly OleDB driver by default will open file exclusively then you can't open it when it's in use by someone else, even just for reading.
Two considerations:
Other application may finalize its work with the file within milliseconds so it's good to try again
Driver will always open file locked for writing (so you can't open it twice via OleDB) but it's shared for reading (so you can copy it).
That said I suggest you should first try to open it after a short pause, if it's still in use (and you can't wait more) then you can make a copy and open that.
Let me assume you have your code in a HandlExcelFile() function:
void HandleExcelFile(string path)
{
try
{
// Function will perform actual work
HandleExcelFileCore(path);
}
catch (Exception) // Be more specific
{
Thread.Sleep(100); // Arbitrary
try
{
HandleExcelFileCore(path);
}
catch (Exception)
{
string tempPath = Path.GetTempFileName();
File.Copy(path, tempPath);
try
{
HandleExcelFileCore(tempPath);
}
finally
{
File.Delete(tempPath);
}
}
}
}
Code is little bit ugly so just consider it a starting point to write your own function.
Considerations:
Retry isn't such bad thing and it's a common way to solve this kind of problems. It's, for example, what Windows shell does (and it's even more normal with networks).
If application didn't close the file then you may copy (and read) old data. If you always need most up-to-date data then you have only one choice: wait. If you can assume that unsaved data belongs to the previous time frame (T - 1, as in digital electronic when signal edge is on clock edge) then just do it and live happy.
Untested solution:
I didn't try this so you have to do it by yourself. Actuallly (I was initially wrong) you can open a read-only connection (through extended properties). It's not documented if this apply to connection only or both file handle and connection. Anyway let's try to change your connection string to:
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\nids\shes.xlsm;Extended Properties="Excel 12.0 Macro;HDR=Yes;IMEX=1;ReadOnly=true"
Just added a ReadOnly=true at the end of Extended Properties.
Other solutions:
The only alternative solution that comes to my mind is to...manually read Excel file (so you can open it just for reading). That said even in this case the other application may have not written new data (so you'll read old one).
Don't use a timer at all. Change your design to use a FileSystemWatcher, you'll read the file only when notified it has been changed.
When applicable...just do not use a shared file as IPC mechanism! Well, you may not be able to change 2nd application so this may not be your case.
Do not use OleDB to read Microsoft Excel files, there are many 3rd part free libraries that don't open file with exclusive lock, for example this one.
Do not read data directly from files, if Microsoft Excel instance is always running you can use COM interop to get notifications. Check this general article about COM add-ins and this to see how you can attach your C# application with Office Interop to an existing Microsoft Excel instance.
Not sure , why do you want to read the excel the way you are doing.
You can try LinqToExcel for excel reading , its a nice little library for reading excel files also if you need to create excel then try to EPPLUS library. These library i personally found really effective when working with Excels
I had similar problem. Below fixes worked for me
1) Don't hold your connection to sheet. Instead open connection read data and close the connection immediately.
2) If you are using managed code in the unmanaged application then consider using object of managed type instead of pointer(using gcnew) and use Stack Semantics to make sure that memory is cleaned up when object goes out of scope.
how to find whether specific .txt file is opened in notepad?
I have tried solutions mentioned here
Is there a way to check if a file is in use?
But they work fine for Word and pdf file but not working for txt file opened in Notepad.
here is code I have wrote.
public bool IsFileOpen(string strFileName)
{
bool retVal = false;
try
{
if (File.Exists(pstrFileName))
{
using (FileStream stream = File.OpenWrite(pstrFileName))
{
try
{
}
catch (IOException)
{
retVal = true;
}
finally
{
stream.Close();
stream.Dispose();
}
}
}
}
catch (IOException)
{ //file is opened at another location
retVal = true;
}
catch (UnauthorizedAccessException)
{ //Bypass this exception since this is due to the file is being set to read-only
}
return retVal;
}
am i missing somthing here.??
My requirement:
I have application which works similar to VSS. When user checks out specific file and opens ,and try to check in the same, while it has opened. Application is suppose to throw a warning message.For that i have used the above functionality.Its working fine for word and pdf.
To expand on my comment. A file is only locked if a handle is kept open by an application. Word for example will open the file, read in the stream and maintain the handle so that other applications cannot delete that file while the user is working on it.
Notepad, and other applications, just open the file, read in the entire stream and then close the file releasing the lock they have. This means that the file is no longer locked and can be edited by another application or even deleted and Notepad will not care as it has its own copy in memory.
You could try and hack around with getting instances of Notepad and checking if a file is open but this is ultimately not a great idea. If the file is not locked then you should be free to do what you want with it.
This is a hack solution I just came up with, but it should work for you. This makes use of System.Diagnostics.
Process[] processes = Process.GetProcessesByName("notepad");
for (int i = 0; i < processes.Length; i++)
{
Console.WriteLine(processes[i].MainWindowTitle);
if (processes[i].MainWindowTitle.Equals("myFile.txt - Notepad"))
{
Console.WriteLine("The file myFile is Open!");
}
}
Console.ReadLine();
Hopefully that should do the trick. My example looks to see if an instance of notepad is open with the window title "myFile.txt - Notepad". The window name is always "filename.extension - Notepad" so you can handle that however you might need to.
I suppose you could make a call to System.IO.File.GetLastAccessTime(filePath). You could then poll the file every so often and when the access time changes you know the file has been opened, you can then fire an event that the file has been opened. See Jeffs post here:
Detect File Read in C#
You could also do this using the following tactic: It seems that notepad does hold some kind of lock on the hosting folder (try to delete the folder and you'll see you can't).
you could use the following code Using C#, how does one figure out what process locked a file? to check list of processes that lock the folder.
one of the processes will be your notepad.
you could them compare by Title as another answers mentioned.
if you're issuing the open of the file - you could save the PID and comapre it with one of the processes that returned.
I will do my best to explain in detail what I'm trying to achieve.
I'm using C# with IntPtr window handles to perform a CTRL-C copy operation on an external application from my own C# application. I had to do this because there was no way of accessing the text directly using GET_TEXT. I'm then using the text content of that copy within my application. The problem here is that I have now overwritten the clipboard.
What I would like to be able to do is:
Backup the original contents of the clipboard which could have been set by any application other than my own.
Then perform the copy and store the value into my application.
Then restore the original contents of the clipboard so that the user still has access to his/her original clipboard data.
This is the code I have tried so far:
private void GetClipboardText()
{
text = "";
IDataObject backupClipboad = Clipboard.GetDataObject();
KeyboardInput input = new KeyboardInput(this);
input.Copy(dialogHandle); // Performs a CTRL-C (copy) operation
IDataObject clipboard = Clipboard.GetDataObject();
if (clipboard.GetDataPresent(DataFormats.Text))
{
// Retrieves the text from the clipboard
text = clipboard.GetData(DataFormats.Text) as string;
}
if (backupClipboad != null)
{
Clipboard.SetDataObject(backupClipboad, true); // throws exception
}
}
I am using the System.Windows.Clipboard and not the System.Windows.Forms.Clipboard. The reason for this was that when I performed the CTRL-C, the Clipboard class from System.Windows.Forms did not return any data, but the system clipboard did.
I looked into some of the low level user32 calls like OpenClipboard, EmptyClipboard, and CloseClipboard hoping that they would help my do this but so far I keep getting COM exceptions when trying to restore.
I thought perhaps this had to do with the OpenClipboard parameter which is expecting an IntPtr window handle of the application which wants to take control of the clipboard. Since I mentioned that my application does not have a GUI this is a challenge. I wasn't sure what to pass here. Maybe someone can shed some light on that?
Am I using the Clipboard class incorrectly? Is there a clear way to obtain the IntPtr window handle of an application with no GUI? Does anyone know of a better way to backup and restore the system clipboard?
It's folly to try to do this. You cannot faithfully restore the clipboard to its prior state. There could be dozens of unrendered data formats present using "delayed rendering", and if you attempt to render them all, you'll cause the source app to run out of resources. It's like walking into a resturaunt and saying "give me one of everything".
Suppose that the user has selected 500 rows x 100 columns in Excel, and has copied that to the clipboard. Excel "advertises" that it can produce this data in about 25 different formats, including Bitmap. Once you paste it as a Bitmap, you force Excel to render it as a bitmap. That's 50000 cells, and would be a bitmap approx 10,000 x 15,000 pixels. And you expect the user to wait around while Excel coughs that up, along with 24 other formats? Not feasible.
Furthermore, you're going to be triggering WM_DrawClipboard events, which will impact other clipboard viewers.
Give up.
You could save the content of the clipboard in a dictionary, and restore it afterwards :
public IDictionary<string, object> GetClipboardData()
{
var dict = new Dictionary<string, object>();
var dataObject = Clipboard.GetDataObject();
foreach(var format in dataObject.GetFormats())
{
dict.Add(format, dataObject.GetData(format));
}
return dict;
}
public void SetClipboardData(IDictionary<string, object> dict)
{
var dataObject = Clipboard.GetDataObject();
foreach(var kvp in dict)
{
dataObject.SetData(kvp.Key, kvp.Value);
}
}
...
var backup = GetClipboardData();
// Do something with the clipboard...
...
SetClipboardData(backup);