Can the last opened file location be directly altered? - winapi

As I understand it, when a file open dialog box (such as GetOpenFileName) is used, Windows will automatically remember where the last file was that was opened by the program, and Windows remembers these locations separately for each program. Is there a way to directly alter this, in order to cause the file picking dialog for program X to start in C:\Example\Directory?
I'm attempting to automate a program which has been programmed to work only through a GUI, and I don't have any access to the internals of this program (such as being able to alter how it calls the file picker). Instead, I'm using a mouse macro (via AutoHotkey). If I can be completely sure that the file picker will start in a particular place, I should be able to automate the rest with mouse clicks.

If you had access to the source code, I'd suggest you just change the lpstrInitialDir property of the OPENFILENAME passed to GetOpenFileName().
Outside of that, you'll want to change the registry keys for the MRUs:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32
What might make more sense, and might fix the issue you're having, is also changing the Working Directory so that the default location isn't "My Documents", if you're experiencing that.
Depending on the operating system, the results vary:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646839%28v=vs.85%29.aspx

Related

SAS - Fails to load program with long name from Windows Explorer

I am using Base SAS 9.4 on Windows 7. For various reasons, which are detailed below, some of my programs have extremely long names. Exacerbating this further, the programs are stored deep in the abyss of a network drive. This causes problems when trying to open from Windows Explorer. I believe the problem lies with SAS, but have tagged the question with Windows in case not. I'm hoping there is some way to address this problem via a configuration file or an edit to the registry.
To open a program, I typically double click on the .sas file in Windows Explorer. This opens the Enhanced Editor after a brief waiting period in which a SAS message box states:
The SAS System is processing requests. Please wait...
When a program's full name, including path and extension, exceeds 182 characters (i.e. has form: \\network-location\a\bunch\of\....\folders\program path exceeding 182 char.sas), the same "SAS System is processing requests" message appears, but then a Windows error is generated.
Not surprisingly, no solution is proffered by Windows.
When the program name is such that the full path is exactly 182 characters, nothing happens. I double click on the program and the only result is to select the file in Windows Explorer. If I monitor "Processes" within the Windows Task Manager, no new processes are started when such a program is double clicked.
When the program name is such that the full path is less than 182 characters, the program opens in the Enhanced Editor as expected.
According to MSDN, the max path is 260 characters. Clearly, 182 is well below that limit. SAS is the only application which has a problem with the path length. For example, I can copy the file name and extension, create a new text document with the same name (plus .txt) and open the file in Notepad, Notepad++, Word, Wordpad, Emacs, etc.
I have deduced two workarounds for working with names exceeding 182 characters.
If I open SAS via SAS.exe, I can load a program through the Open dialog with a path exceeding 182 characters just fine. This is not a good solution, however, as the Open dialog does not allow paths to be copy/pasted. The entire file path must be traversed. I can also drag such a program into the editor window within SAS to load it. This too is not a good solution, as a program will only load if there is a blank editor window. If the program is accidentally dragged on the the log window, it will execute automatically. Also, the program does not open in a convenient location. It opens in the middle of the Enhanced Editor and must be manually resized. That the programs can be loaded and executed at all leads me to believe that there is some way to fix this problem. It seems that somewhere in the process of loading the file, SAS violates some variable limit.
Of course, people would suggest that I use a different network location or shorter names. To the former, I am required to use a specific network location. To the latter, these programs are being developed in parallel with various reports. Many of the programs are similar and the corresponding references (table/figure numbers) in the reports change multiple times/aren't always communicated to me. Through experience, I've found the surest way to work with these uncertainties is to simply name the file by the label it's given in the report. Otherwise, I need to adopt unclear abbreviations, bad organizational practices, or introduce intermediate steps (like creating codes or a document which indexes the programs).
Edit: Per Joe's comment, it seems that the Open dialog allows copy and paste for specific file names. A file path can be copied in Windows Explorer via Shift + Right Mouse Click > Copy as Path and pasted into the "File Path" box in the Open dialog.
To avoid traversing the tree, the Current Folder may be updated before accessing the Open dialog. This is located at the bottom right of the Enhanced Editor.
The Open dialog starts at whatever the Current Folder location is set to.
I suspect your issue is that your 260 limit is in fact applicable.
When you double-click a program file, it doesn't just copy the path to SAS. Instead, what happens is SASOACT.exe is called, with a command of something similar to this:
"C:\Program Files\SAS94\SASFoundation\9.4\core\sasexe\sasoact.exe" action=Open datatype=Access filename="%1" progid=SAS.Application.940
That's well over 100 characters already by itself; presumably, behind the scenes, you end up with something like
"C:\Program Files\SAS94\SASFoundation\9.4\core\sasexe\sasoact.exe -open ""%1"""
Which adds around 70 or 80 characters to what you're passing it. Thus the 260 character limit.
You should use one of the workarounds - I personally prefer to just file->open, myself, but really whatever works best for you is fine. You could also consider using another editor for the simple double-click actions, though any editor you chose would still have some issues.
You could also consider asking IT to install SAS itself in a location that had a shorter path name, though realistically that might save 10 characters or so.
As for pasting; you can paste a path name just as easily as a file name into the file->open dialog. I have no idea why you don't seem to think you can, but I just did so now with no more difficulty than any other folder dialog...
Another workaround to consider, by the way, is mapping a drive letter to the network path. I.e., if your network path is
//myserver/projects/financial/projectnumber/.../
You map some letter (let's say R: arbitrarily) to that root path, //myserver/projects/financial/projectnumber, which is not changing anything other than how you refer to it locally. Then you can use:
R:\...\filename.sas
And you don't have to navigate paths, etc. You'd have to repeat that mapping process on any machine that you wanted to do this on, but if this mostly about your own workflow, that shouldn't be an issue. Just don't refer to R: inside the program itself and nobody else will ever know that you've changed anything.

Windows API hook, custom save as file dialog to save directly to webserver via POST

I want to write a custom save as dialog that is hooked into the File -> "Save As" of most Windows program. This custom dialog will allow the user to enter their username, password, destination folder and uploads the file to the web server via a POST. If the user clicks cancel, it will call the original file dialog.
I've been reading up about Windows API hooking and this is vaguely how I think I would approach this:
Intercept "Save As"
Display my custom dialog, return some temporary path on the drive
Let the program write file to the temporary path, assume it calls WINAPI CreateFile(...) for now
Read the temporary file and upload to web server
Clean up temporary file
But I still can't get my head around the steps required to pull this off. Assuming I can intercept the "Save As" and CreateFile function, how do I detect the CreateFile was called from a "Save As" and not just any random file creation? I can think of a hack where I keep track of the time difference of when the File dialog got open and CreateFile got called.
My alternative solution is to use the existing file dialog and create a special folder on the disk, that is constantly monitored. When a file gets written there it will call an external program that uploads the file. I haven't looked into how to do this yet. I suspect this is easier.
UPDATE
As a first baby step, I wrote a .NET task tray application that allows the user to enter their login details and a folder to monitor. Whenever a file gets dropped in there there it will upload to the web server. So far it seems to work. Now I just need to figure out how to add a nice shortcut to the left pane of the file dialog. Once that's done I think I got a solution I'm happy with.
There is no need to hook or patch anything. Create a shell namespace extension that supports IStorage::CreateStream and implements it by returning a stream that POSTs its data to the Web server. The user can then choose to save the file to your namespace extension in order to upload the file.
Hooking the standard save dialog requires you to inject a DLL into every running process and have it replace the import stub of the the Win32 API GetSaveFileName() function in the process's PE header (something anti-virus and anti-malware apps are not likely to be happy about).
Then there is the new-style save dialog that was introduced in Vista using the new IFileSaveDialog COM interface instead of GetSaveFileName(). For that, you would have to uninstall and replace Microsoft's default FileDialog COM object with a custom implementation.
That does not count custom-made save dialogs, which you are not likely to hook.
If, by some miracle, you can hook the dialog and have it return a custom path of your own creation, you don't need to hook CreateFile() itself, Just monitor the folder that you create for your purposes. Place it where it is unlikely that any other app (or user) besides you will write files to. You can create a custom subfolder in the user's or system'ss AppData folder for that purpose. You can use SHGetSpecialFolderPath() and/or SHGetKnownFolderPath() to find those folders.
The tricky part will be detecting when the file is finished being written to and has been closed. You will have to monitor the folder for changes, such as with ReadDirectoryChangesW() or SHChangeNotifyRegister(), and periodically open new/modified files for exclusive access. If a file is still open by someone else, you won't be able to open it yourself. But once you do open it, you can do whatever you want with it.

Read content of cursor location in terminal/Shell

I'm working on a unique project using terminal/Shell but I've hit a little bit of a roadblock I haven't been able to work around.
I want to be able to read the content of the location of the cursor.
For example, if the cursor is currently located on line 2, column 5 which contains an E, I want to be able to read that E and create a variable with it.
Can you explain what your project entails? It might help if we knew what you're trying to accomplish.
No tools exist to do this in the shell, as far as I know. To actually read a remote screen would require this as a feature of the remote terminal (or emulator).
Neither do any compiled language support this. All applications that appear to do this fake it by keeping an internal copy of what they assume is displayed on the screen.
Lookup the curses* library for more information. This toolkit allows a programmer to address the screen as a random accessible grid, and hides all of the updates to the actual terminal screen.
See also: ncurses

Debugging a Cocoa droplet application in Xcode

When debugging in Xcode, how do I simulate a user starting my Cocoa droplet application by dropping one or more files onto it's application icon?
The app just opens, processes the files while displaying it's progress and then closes again.
Passing arguments (via the "Arguments" tab of the entry under "Executables") should allow this, but I could not find out how.
What I really want is to hit "Build and Go" and then have the droplet open with whatever files I need.
A last resort would be to use AppleScript or the "open" command on the command line to achieve this. I want to streamline this as much as possible.
Thanks for any pointers!
Add each absolute path to a file you want to open with the application as an argument. You may need to wrap each one in quotation marks (which shouldn't be necessary, and is a bug if it is, but I do remember needing to do).
You should be able to use variable references like $SRCROOT in order to refer to files within the project root directory.

Is it possible to replace the system open file dialog?

I want to replace the standard system open file dialog with the one I wrote, that means no matter within which programs you are opening a file, my dialog will be shown instead of the standard one, is this possible?
It seems that that there is no such API provided to accomplish this, is it possible to use some hooking technique, but this has to be reliable and not to be treated as spyware by anti-virus tools?
any other options?
If this is not possible, is it possible to add to the spacebar or toolbar in the standard open file dialog a button which invokes my dialog, which allow users select a file and in turn returns the path of the selected file to the "File name" input box of the standard dialog?
Any hits, links and code examples will be appreciated.
Starting in Vista, the FileOpen/FileSave dialogs are now "Common Item Dialogs" of which IFileOpenDialog & IFileSaveDialog are the two published implementations.
Since they're just COM objects with known CLSIDs you might get away with just replacing them by re-registering using their CLSIDs. Never tried something like that, might trip all sorts of alarm bells.
Pre-Vista file dialogs can be hooked in process, but I've never come across anything about global hooks or equivalent.
If you copy a file/folder to a dialog's filename field it usually pastes the full path anyway.
For example, if you have open both a program calling the standard open/save dialog box and also have a window open at the file or path that you want to work with (open from/save to), you can simply copy the file/folder from the explorer window, and then paste into the filename field of the dialog box, and it will insert the full path of the file/folder. No custom script is required!
Alternatively, for those programs that use custom dialog boxes where this step fails, copy the same file/folder in the window into the address bar of the same window (assuming it is visible). This will paste the full path, which you can copy again, and then paste this full path into the custom dialog box. I often use this when creating Office hyperlinks (Ctrl+K), because the Insert Hyperlink dialog does not work for the first method.
You can also use similar methods but paste into address bar fields and it works.

Resources