How open an external application and simulate file on side? - winapi

I want to open an external program to my project. okay. The folder it is this:
...
Externalapp.exe
But for the Externalapp.exe work, its need a file called key.lua that can not be visible to the user (for security reasons).
So I thought I'd include this file in the dynamically call from my Externalapp.exe for him to think that the key.lua is on your side.
Is it possible?

First a few words about security:
As others have already mentioned in comments storing any data regarding the security in LUA files is terrible idea. Why? LUA files are textual files so any user can see the contents of it. Now you can try hiding this file by putting it into some not so obvious folder but there is still risk that the user may stumble upon it somehow.
If you can change your ExternalApp athleast give it the ability to load the encrypted LUA file and encrypt your LUA file acordingly.
And now to the posible answer to your question:
It might be posible to convince your ExternalApp to load LUA file that is not in same directory as the ExternalApp is by setting the working directoy to be different from your ExternalApp location.
Here is a Delphi code example that uses both ShellExecute and ShellExecuteEx API calls.
procedure TForm2.Button1Click(Sender: TObject);
var SEInfo: TShellExecuteInfo;
ExitCode: DWORD;
begin
//Using ShellExecute
ShellExecute(Handle,'open','C:\ExternalApp.exe',nil,'D:\',SW_SHOWNORMAL);
//Using ShellExecuteEx
FillChar(SEInfo, SizeOf(SEInfo), 0);
SEInfo.cbSize := SizeOf(TShellExecuteInfo);
SEInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
SEInfo.Wnd := Application.Handle;
SEInfo.lpFile := PChar('C:\ExternalApp.exe');
SEInfo.lpDirectory := PCHAR('D:\');
SEInfo.nShow := SW_SHOWNORMAL;
if ShellExecuteEx(#SEInfo) then
begin
repeat
Application.ProcessMessages;
GetExitCodeProcess(SEInfo.hProcess, ExitCode) ;
until (ExitCode <> STILL_ACTIVE) or Application.Terminated;
ShowMessage('External application terminated') ;
end
else
ShowMessage('Error starting External application!') ;
end;
NOTE: This will only work if your ExternalApp is trying to find the LUA file by using GetCurrentDirectory or GetWorkDirectory cals to get the path location of LUA file.
But it will not work if your ExternalApp is getting this path by extracting path location of its executable.

Related

Get system folder paths in Go?

Is it possible to get the path of system folders in Go, in a cross-platform way? eg. temp folders, "document" folders, etc.
I found ioutil.TempFolder/File but they do something different. Any idea?
There's currently no way to access standard system folders in a cross-platform way. The Home directory though can be access using the user package:
u, _ := user.Current()
fmt.Println(u.HomeDir)
In the year 2020, I am trying to get similar things, but only for temporary directory cross-platform. When I found this thread and read some answers, I almost make a conclusion that it is not possible.
But after a few further research, I found that go already have it. Just like pointed by the accepted answer, it stands inside os package. Based on this documentation: https://golang.org/pkg/os/#TempDir, we can get it by calling: TempDir() function.
If someone trying to look at another OS system directories path, and stumbled upon in this thread, my suggestion, please just try to have a few further research. Looks like currently go have more complete functions regarding OS system directories.
A built-in option doesn't exist yet. Your best bet is to open an issue and submit a feature request.
In the meantime you can add support yourself by using platform specific +build flags. With that you have a couple of options:
Use the os package to get the information for each system, possibly through the shell.
Use cgo with existing C / C++ methods. See this answer, which explains how to get this information using C++ for Windows.
It may also be helpful to read the source code of the os package to see how platform-specific information is obtained. This could help you devise a way to get this information, and perhaps submit a patch to be included.
For the OS's temp directory, as stated by Bayu, there is a built-in function os.TempDir() string to get the os specific temp directory:
// TempDir returns the default directory to use for temporary files.
//
// On Unix systems, it returns $TMPDIR if non-empty, else /tmp.
// On Windows, it uses GetTempPath, returning the first non-empty
// value from %TMP%, %TEMP%, %USERPROFILE%, or the Windows directory.
// On Plan 9, it returns /tmp.
//
// The directory is neither guaranteed to exist nor have accessible
// permissions.
func TempDir() string {
return tempDir()
}
which is actually used by the ioutil.TempDir(dir, pattern string) (string, error) function if you provide an empty string for the dir parameter. Check out the 5th and 6th lines:
// TempDir creates a new temporary directory in the directory dir.
// The directory name is generated by taking pattern and applying a
// random string to the end. If pattern includes a "*", the random string
// replaces the last "*". TempDir returns the name of the new directory.
// If dir is the empty string, TempDir uses the
// default directory for temporary files (see os.TempDir).
// Multiple programs calling TempDir simultaneously
// will not choose the same directory. It is the caller's responsibility
// to remove the directory when no longer needed.
func TempDir(dir, pattern string) (name string, err error) {
Besides the methods Luke mentioned, on Windows you can get some of the paths from environment variables. Same applies, to some extent, to Unix ($HOME, etc.).

Is it possible to read and write from/to file opening it only once?

is it possible to read and write from/to file using only 1 assign()?
I mean something like:
assign(fl, 'file.txt');
reset(fl)
// I know, that when I use reset - I have only read permission,
// but is there any other option to read and write opening the file only once?
read(fl, variable);
write(fl, 'asdf);
close(fl);
Reset does not give you only read access; the default is read/write (FileMode = 2), at least in Delphi's Pascal, and FP is pretty compatible with it.
From the help topic on FileMode (emphasis mine):
Indicates the access mode on typed and untyped files opened by the Reset procedure.
In Delphi code, FileMode determines the access mode to use when typed and untyped files (not text files) are opened using the Reset procedure.
The file open modes that can be assigned to the FileMode variable are defined in the Constants list on System.SysUtils. The default FileMode is 2 (Read/Write access). Assigning another value to FileMode causes all subsequent Resets to use that mode.
As your question was general, you didn't say what kind of data would be stored in the file. If you define your file as 'file of TRecord' (you'd have to define your record type first), then first you 'reset' the file to open it; afterwards, you can use the predefined procedure 'seek' to find a specific record within the file, read the data into a local variable of type TRecord, alter that record then write it back to the file. The file's current location will be that of the record that you have just read.
Reading and writing text files is more tricky - there exists the predefined procedure 'append', which allows one to add text to the end of the file (but not in the middle).
Thirty years ago, I used to use such a system in order to create my own databases; fortunately, database programming is much simpler now.

Getting safe temp folder in Windows

I need to get a safe temp folder where I could store temporary files for my application, but so far my research has lead me to conclusion that all approaches I've found are flawed.
The first idea was to use GetTempPath function, but that causes two problems:
The folder might not exist, so I would have to truncate folders one by one up to root, and recreate them if they do not exist back to full path (error prone, tedious)
From "Larry Osterman's WebLog" click it seems that GetTempPath might fallback to USERPROFILE or Windows directory and extract whole lot of files right in there, which is SUPER BAD(TM)!
In the same post, there is a suggestion to use GetEnvironmentVariable, but this seems a dangerous function to me (missing TMP & TEMP envvars for instance).
Is there a cleaner function I could use? Seems that SHGetKnownFolderPath has no clue what temp folder is.
Your program is probably not the only one to rely on GetTempPath, so it's reasonable to expect it to return a proper writable path. Especially since Windows automatically initializes the TMP and TEMP environment variables for you; someone would have to go to some trouble to override them, and it would be their responsibility to make sure the change did not mess up their system.
I would go ahead and assume GetTempPath works properly, and worry about failures when you try to create the temporary file - there are other errors that might occur at that time that you need to check for anyway.
An idea would be to get the path where your application is (GetModuleFileNameEx combined with GetModuleHandle(NULL) and GetCurrentProcess) since this directory cannot be deleted under windows as long as your application is running from it (maybe I'm wrong ...some years ago I couldn't do this :) ) and in this directory create a temporary directory.
Your first bullet point is the solution. Wrap it up in a method so that you don't duplicate code.
According to this answer, Boost's Filesystem library can be used for this.

How can I get the Name of the Program associated with a file extension using Delphi?

I need to get the name of the program currently associated with a file extension for the current user. If you right-click on a file and select properties, then what I need is the program name that is to the right of the "Opens with" line.
e.g. For ".xls", I want to be able to get the answer "Microsoft Office Excel", or whatever program the user has as their default program to open .xls files.
I have determined it's not as easy as just going into HKEY_CLASSES_ROOT and picking it out, since it may also be specified in HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER or HKEY_USERS.
Maybe all I need to know is the pecking order used by Windows to determine this and how to get to each of the locations. Of course, a Windows API call to do this would be ideal.
This is a similar question to:
How to get icon and description from file extension using Delphi? but that question only answered how to get the description of the extension and the icon of the associated program. I couldn't find a way to extend that to also get the name of the associated program.
I'm using Delphi 2009 and need a solution that works on Windows XP, Vista and 7.
Thank you all for your answers.
It appears my belief that the name of the executable is not in the Registry after all. And after looking around extensively for a Windows API that will give the name, I could not find one.
I think Mef's answer then is the best. To get the name of the executable from the information included in the program's executable.
Followup: I found David Hefferman's answer to "How do I open a file with the default text editor?" gives an excellent solution for opening one program using the default program for a different extension.
Don't go spelunking in the registry when there are API functions designed to do what you need.
In your case, you want AssocQueryString. You can give it the file-name extension, and it will tell your the program registered to handle that extension (AssocStr_Executable). If you're planning on running that program to open a document, then you'll really want the command string instead of just the executable; AssocQueryString can give you that, too (AssocStr_Command). It can also tell you the document type like what's displayed in Windows Explorer, like "Text Document" or "Zip Archive" (AssocStr_FriendlyDocName).
That API function is a wrapper for the IQueryAssociations interface. If you're looking for programs from many file types, or lots of strings associated with a single type, you may wish to instantiate that interface and re-use it instead of calling the API function over and over.
Delphi comes with a unit ShellApi.pas that is used in the sample code below. The file has to exist.
Here's how to use it:
function MyShellFindExecutable(const aFileName: string): string;
var
Buffer: array[0..WINDOWS.MAX_PATH] of Char;
begin
Result := '';
FillChar(Buffer, SizeOf(Buffer), #0);
if (SHELLAPI.FindExecutable(PChar(aFileName), nil, Buffer) > 32) then
Result := Buffer;
end;
Step 1
Get the executable which is assigned to a file extension, for instance with the following function:
uses Registry, Windows, SysUtils;
function GetAssociation(const DocFileName: string): string;
var
FileClass: string;
Reg: TRegistry;
begin
Result := '';
Reg := TRegistry.Create(KEY_EXECUTE);
Reg.RootKey := HKEY_CLASSES_ROOT;
FileClass := '';
if Reg.OpenKeyReadOnly(ExtractFileExt(DocFileName)) then
begin
FileClass := Reg.ReadString('');
Reg.CloseKey;
end;
if FileClass <> '' then begin
if Reg.OpenKeyReadOnly(FileClass + '\Shell\Open\Command') then
begin
Result := Reg.ReadString('');
Reg.CloseKey;
end;
end;
Reg.Free;
end;
(See here, or marc_s' anwser to this question :-)
Step 2
Now you can read out the name of the program from the version information of this executable! The easiest way is using the TVersionInfo class you can find via Google, for instance here.
var VersionInfo: TVersionInfo;
VersionInfo := TVersionInfo.Create('PathToExe\name.exe');
s := VersionInfo.KeyValue['Description'];
However, you have to be aware that some programs use the description key therefore (like RAD Studio itself or MS Excel), while others use the product name key...
I think that you need to combine Mef's and Rob Kennedy's answers.
Take Rob Kennedy's answer and take step 2 from Mef's answer. Reading registry directly isn't good thing to do, so you should throw away his part 1.
But I'm not looking for the friendly name of the file type.
AssocQueryString returns not only friendly name for file type (ASSOCSTR_FRIENDLYDOCNAME), but also it can return the name of executable to open file (ASSOCSTR_EXECUTABLE) - that is what you need.
Even more than that: I'm not sure, but may be ASSOCSTR_FRIENDLYAPPNAME will match your needs. In that case, you may use only Rob Kennedy's answer.
The problem with reading registry directly is that it may return wrong info. That's because you read system settings - that is what application registered. But user may override this. For example, he may right click on .xls and select "Open with..." -> "Other app." -> "OpenOffice" -> "Use this app always". Registration info for .xls type will not be altered (user preferences are saved in separate place, so apps can't mess with them), so your code (which reads registry directly) will continue to produce "MS Excel", even though when user double-clicks on file - OpenOffice will be launched.
How about this article here: Determining the associated application
In the concrete case of Excel, you will find the .xls extension under HKEY_CLASSES_ROOT - the default value of that entry is Excel.Sheet.8.
When you go search for Excel.Sheet.8 again in HKEY_CLASSES_ROOT, you'll find an entry with a default value of Microsoft Office Excel 97-2003 Worksheet - that's probably as good as it gets.
If the user says "use this app always" for .xls-files the info ist stored in
HK_CU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.xls
The key has an entry "Application" containing the Application name (e.g. "soffice.exe"). It's correlated to an Applcication key in HK_CR, e.g. HK_CR\Applications\soffice.exe\

Browser and external app communication? (Chrome's current url and referrer on Windows?)

How might an external program communicate with a browser? Hopefully this will be of some use to others: I'm listing off a number of options I've seen or tried while unsuccessfully getting this to work. If you know of others, please post them.
If Mac, use AppleScript (info/solution at q.263741, try this search)
Use or create an extension for Firefox (iMacros?, q.410411), Chrome (?)
Use a WebBrowser Control to host an IE instance (some tips at q.1143187)
If you own the site, this can be done with a background ajax script
My question: how can I get the current foreground browser's (Chrome, specifcally) URL and referrer from an external windows app, without modifying the browser?
I've tried using User32's GetWindowText, which grabs the title (using jNative for Java). This often lets me guess the server. It may be possible to write a local proxy that will map titles to URLs, but this is much work. I've written a FireFox extension to rig the window title with this information, but it became outdated, and I need this for Chrome now anyway. I'd prefer not to add junk to the browser, unless broadly useful. Perhaps I could file a feature request for an applescript-like api for chrome on windows. AHK Window Info 1.7 manages to grab the URL (but not referrer) under visible/hidden text, but I have no idea how to port the code it uses.
(Some info for FF/C# at q.990409 & here, some IE info at q.823755 (redirects to q.352236). No info at q.1107978.
Ignore this: Related questions: How can I control firefox with a macro? How can I get browser information? How can I get current browser URL? How can I get chrome's current URL from an external app?)
Ideas, code samples, pointers to potentially relevant questions, and answers to my specific question are all appreciated.
Quick and dirty solution (you can convert it from Delphi to your language):
var
h : HWND;
pCh : array [0..255] of char;
begin
Result := '';
h := GetForegroundWindow; // or pass main Chrome window here
if h = 0 then exit;
h := GetWindow(h,GW_CHILD);
if h = 0 then exit;
h := GetWindow(h,GW_HWNDNEXT);
if h = 0 then exit;
SendMessage(h, WM_GETTEXT, SizeOf(pCh), integer(#pCh)) ;
Result := pCh; // <-- URL is here!
end;
Thanks for the question ;) - just added to our WorkTime - time tracking software

Resources