I am manipulating JPEG images programmatically from C# in a WinForms app in Win 10 and would like File Explorer to show the manipulated rather than the original image thumbnail. Closing Explorer, deleting %LocalAppData%\Microsoft\Windows\Explorer\thumbcache_*.db and restarting does this but it is slow and intrusive. I would like to update an individual file's thumbnail programmatically. Windows does this when an image is rotated via the Explorer context menu, but the means for doing this from a program aren't clear.
The batch file which I currently use to close Explorer, delete the thumbnail cache file and restart is
taskkill /f /im explorer.exe
timeout 2 /nobreak>nul
DEL /F /S /Q /A %LocalAppData%\Microsoft\Windows\Explorer\thumbcache_*.db
timeout 2 /nobreak>nul
start "" %windir%\explorer.exe
start "" %windir%\explorer.exe "Folder To Update"
The proper way to do something like this is to use the SHChangeNotify() function. If you're using C#, you can p/invoke it like so:
[DllImport( "Shell32.dll", CharSet = CharSet.Auto, SetLastError = true )]
static extern void SHChangeNotify(uint wEventId, uint uFlags, [MarshalAs(UnmanagedType.LPWStr)] string dwItem1, IntPtr dwItem2);
...and then use it to notify Explorer that an item has been modified (i.e. the image that you manipulated):
private const uint SHCNE_UPDATEITEM = 0x00002000;
private const uint SHCNF_PATHW = 0x0005;
private const uint SHCNF_FLUSH = 0x1000;
string pathName = "your image file.jpg"
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATHW | SHCNF_FLUSH, pathName, IntPtr.Zero);
Increasing the file modified date by 1 sec and then changing it back triggers Windows into thinking the file has changed so that the thumbnail is updated. Code used is
DateTime modDate = System.IO.File.GetLastWriteTime(sFile);
System.IO.File.SetLastWriteTime(sFile, modDate.AddSeconds(1.0));
System.IO.File.SetLastWriteTime(sFile, modDate.AddSeconds(-1.0));
Related
I have some program that login to webSite and trying to download file,right now i am using WatIn and User32 FindWindowEx to find the SaveAs dialog and send PostMessage with tab and enter to press Save button
MainPopUp = browserToRun.hWnd.ToInt32();
int currChild = FindWindowEx(MainPopUp, 0, ClassName, WindowName);
PostMessage(currChild, WM_KEYDOWN, VK_TAB, 2);
PostMessage(currChild, WM_KEYDOWN, VK_ENTER, 2);
this works,but not all the time.
This is secured webSite sow i cant see the DownloadUrl and i can't use
[DllImport("urlmon.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern Int32 URLDownloadToFile(Int32 pCaller, string szURL, string szFileName, Int32 dwReserved, Int32 lpfnCB);
int response = URLDownloadToFile(0, browserToRun.Button(Find.ById("btnExcelExport")).Url, #"C:\Users\vladimirp\VN.xls", 0, 0);
I need some mothed that can handle this PopUp dialog,and with out UI,because the User Pc can be locked,sow this have to work even if user windows is lock.
*I dont see the downloadURL sow WebClient.DownloadFileAsync(url,Path) will not work
Do any one know how to handle IE save dialog? .Net c#
Please refer to Handling File Download PopUp post. However the solution in that post requires an active session of desktop.
I would like to close notepad file without prompting "Would you like to save changes" dialog box. I tried:
SendMessage(handle, 0x0010, IntPtr.Zero, IntPtr.Zero);
But asks me whether I'd like to save changes or not. Also DestroyWindow(HWND) doesn't work.
How to overcome this problem?
Thanks a lot...
If you don't care about the data on notepad then simply kill its process.
[DllImport("user32.dll", SetLastError=true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
Now kill the process using its process id
Process p = Process.GetProcessById(processId);
p.Kill();
Just to add to the answer posted by #prem, there is absolutely no need for using APIs. .NET already includes everything to do this like in the example below.
var processes = Process.GetProcessesByName("notepad");
foreach (var process in processes)
process.Kill();
I have a C# win form app. In it I'm getting a unique serial of HDD by using this method.
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool GetVolumeInformation(string Volume, StringBuilder VolumeName,
uint VolumeNameSize, out uint SerialNumber, uint SerialNumberLength,
uint flags, StringBuilder fs, uint fs_size);
with Volume variable as Path.GetPathRoot(Environment.CurrentDirectory)
I get the serial as SerialNumber.ToString("X")
Works fine but the situation is;
I have Shared the app folder. I get XXXXXXXX as serial when I run the EXE
When another person run the app from my shared path he gets 00000000 as serial
But when that another user Mapped this folder and run the app he gets XXXXXXXX as serial
So what is the cause of this problem? Is there any better way to use?
I referred WMI but didn't fit to my need.
I need to find open process or application textbox and change its value. But i wanna do it with c# way. If anyone knows could you please share with me? Or do i have to use c++ and how?
Thanks for your advices.
Like another said, UIAutomation is the way to go. http://msdn.microsoft.com/en-us/library/ms753107.aspx
The following code will open Notepad.exe, open its File dialog, then type in some text into the file name field.
Process notepad = Process.Start("notepad");
Thread.Sleep(5000);
SendKeys.SendWait("^o"); //ctrl+o to open the File Dialog
var notepadTextBox = AutomationElement.RootElement.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.AutomationIdProperty, "1148"));
object valuePattern = null;
if (notepadTextBox.TryGetCurrentPattern(ValuePattern.Pattern, out valuePattern))
{
((ValuePattern)valuePattern).SetValue("THERE YOU GO"); // this text will be entered in the textbox
}
else
{
//ERROR
}
So this is really a combination of sending keystrokes to control the UI (bring up the File Open dialog) & UIAutomation, but you could change it to drive the Menu like a user would if you need to.
Also you might be wondering where the magic string "1148" comes from - that is the "Automation Id" of the file name entry field in Notepad. I used inspect.exe (included in the Windows SDK) to find the automation Id, you will need that for your application to see its AutomationIds, if it has any.
One way to do this is if the application is out of your control in terms of using libraries and wrappers:
Process[] Procs = Process.GetProcessesByName("NameofProcess");
that will give you the process in question. Now this is where it will get tricky and depend upon what exactly you need to do.
You would eventually need to find where the strings are stored in memory, you could use a memory profiler to do this or something like CheatEngine to find the values, not going to get into what you use CheatEngine for or how you use it, but it is just a simple way of finding memory locations.
You could then read/write to the memory locations using something like this:
[DllImport("kernel32.dll")]
public static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesRead);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out int lpNumberOfBytesWritten);
public static byte[] ReadMem(IntPtr MemAddy, uint bytestoread, Process Proc)
{
//
//Create new Memory buffer and pointer to that buffer
//
byte[] buffer = new byte[bytestoread];
IntPtr bufferptr;
//
//Read Process Memory and output to buffer
//
ReadProcessMemory(Proc.Handle, MemAddy, buffer, bytestoread, out bufferptr);
//
//Return the buffer
//
return buffer;
}
public static bool WriteMem(IntPtr MemAddy, byte[] buffer, Process Proc)
{
int NumWriten;
WriteProcessMemory(Proc.Handle, MemAddy, buffer, (uint)buffer.Length, out NumWriten);
if (NumWriten != buffer.Length)
{
return false;
}
else return true;
}
These two functions would allow you to read and write to some arbitrary processes memory locations.
if you want the window in question you could use:
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
Like So:
IntPtr HWND = FindWindow(null, "WinName");
Which will give you the handle to the window in question.
Another way to do this would be to find the window and then pass some events to it, like bring the window to focus and then tab through the text boxes programmatically. However without more information about what exactly you are trying to do I am not sure what else to say here.
The tool you are looking for is UI Automation. It will let you see the other program's controls and send text to those controls. I have done this in the past where I had to export data from a corrupted database and I had to click OK on a dialog every time it hit a corrupted record.
The topic is too complex to go in to depth on how to do it in the space of a SO answer, but here is a tutorial I found on CodePlex that goes over how to do it.
There are also 3rd party wrapper libraries to make it easier to do. My personal favorite is White.
I want to automate a program called Spotify from C#, the best way (I think) to do this is by triggering fake keypresses. I want to program to pause playback, and I don't know enough about this stuff to find another way than keypresses. So I use Visual Studio's Spy++ to see what message Spotify gets when pressing the play button on my keyboard, I copy the data from that message into my Console Application and run it, when I run I can see the PostMessage in Spy++'s Message Logging, so this is working but it doesn't pause/play my music. I guess this is because I also have to send another PostMessage with another destination, but how do I know what else to send?
Post Message call:
MessageHelper.PostMessage((int)hwndSpotify, 0x100, 0x000000B3, 0x01000001);
I hope someone is familiar with this and can help me out.
To automate Spotify, first you have to get the handle of the window with the following class name: SpotifyMainWindow (using FindWindow()).
Then, you can use the SendMessage() method to send a WM_APPCOMMAND message to the Spotify's window.
Following a simple code to do that:
internal class Win32
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
internal static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
internal class Constants
{
internal const uint WM_APPCOMMAND = 0x0319;
}
}
public enum SpotifyAction : long
{
PlayPause = 917504,
Mute = 524288,
VolumeDown = 589824,
VolumeUp = 655360,
Stop = 851968,
PreviousTrack = 786432,
NextTrack = 720896
}
For instance, to play or pause the current track:
Win32.SendMessage(hwndSpotify, Win32.Constants.WM_APPCOMMAND, IntPtr.Zero, new IntPtr((long)SpotifyAction.PlayPause));
Pressing the "play buttion" results in a virtual key code - for an official list see http://msdn.microsoft.com/en-us/library/dd375731%28v=VS.85%29.aspx .
There you find for example VK_VOLUME_UP VK_MEDIA_PLAY_PAUSE VK_ZOOM .
Even some Remotes translate to these codes to be as compatible as possible with existing software.
These were introduced back in the day when Windows ME (!) came out and are still in use - at least when I checked the registry of my Windows 2008 R2 !
Basically Windows translates certain VK* into WM_APPCOMMAND messages with certain codes which the applications listen to...
If the key has something to do with launching an app to do (i.e. Mail, Browser etc.) then the magic happens via Windows Explorer which reads the mapping (either by association or direct exec) from the registry at Software\ Microsoft\ Windows\ CurrentVersion\ Explorer\ AppKey - either HKLM or HKCU.
Some links with old but as it seems still valid information:
http://msdn.microsoft.com/en-us/windows/hardware/gg463446.aspx
http://msdn.microsoft.com/en-us/windows/hardware/gg462991
http://msdn.microsoft.com/en-us/windows/hardware/gg463372