You are about to read many grammatical mistakes, sorry, I am not native to English language.
Hello, I am developing a simple software that counts the time you spend on applications, at the begin wasn't complicated, but now they request me to identify when the application is a navigator like Chrome, Firefox or IE. Then it has to identify what URL is currently in use to start count how much the user waste on all the open pages, but I don't know how to identify if is a navigator, obviously which URL is on it.
OUTPUT EXAMPLE (output.txt)
Process Used:
netbeans 00:04:43 <- Done
calc 00:23:12 <- Done
chrome(www.facebook.com) 00:01:02 <- Dont know how
chrome(www.9gag.com) 00:17:23 <- Dont know how
Global
[DllImport("user32.dll")]
public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out uint ProcessId);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
This is the way i get the current process name that is in use
GetWindowThreadProcessId(hwnd, out pid);
System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById((int)pid);
String NOMBRE = p.ProcessName.ToString();
Hope some can help me. Thanks!
Really no easy answers. "Navigators" are called web browsers, to help you in searching.
For the OS, they are regular programs, nothing special. In particular, the OS has no idea about the URL currently shown. That's a good thing, btw - the introduction of tabbed browsing means that you often have multiple tabs and thus multiple URLs open at the same time. If the OS knew about "the URL" of a webbrowser, it would have had major issues with tabbed browsing.
A good idea is to compare the URL in a webbrowser with the current score in a game. Both are simple variables, conceptually, but the OS doesn't try to track game scores either.
You can of course implement such a thing per type of webbrowser, but it takes work.
Related
I am looking at some old MetaEditor4 / MQL4 code, where a local variable was declared twice:
......
1 int start()
2 {
3 if (1==2)
4 {
5 double myVar = 1;
6 } else
7 {
8 double myVar = 2;
9 }
10 return;
11 }
.......
The compilation process in MetaEditor, version 5.00, build 1601, fails with:
'myVar' - variable already defined in line 8.
If I remove the line 8, the compilation goes well.
My questions are:
1. Is there any option in MetaEditor that tolerates the multiple declaration of a local variable?
2. In previous versions of MetaTrader Terminal 4 / MetaEditor and .MQ4 code: was it possible to declare a local variable more than once in such a situation?
3. The MetaEditor has the version 5.00, build 1601, but the extension of the code is .mq4 and it was installed together with the MetaTrader Terminal software MetaTrader4 ( from FXCM ). Therefore I assume I can still use .MQ4 code with it. Is there any chance to get a pure MQL4 installation from somewhere?
Whenever I install mt4 ( from e.g.: mt4 download), it ends up
with the mt5 installer.
Prologue:
The worlds of MQL4 evolve. One may try to circumvent this fact, but finally, at one's own disappointment, attempts to avoid evolution will sooner or later go in vain.
Having been thrown into a need to re-engineer code-base spanning a few man*decades in size, I can tell you many stories about what worked and what did not.
An "Old code" v/s a New-MQL4.56789
If just one thing ought be taken from this, never try to "circumvent" New-MQL4, but rather review the code and refactor the "Old code" - this is a way safer way to survive ( way longer ).
Yes, there are chances ( zero warrants, just a few chances left temporarily on the table ) the new compiler version will remain able to generate an executable version of the code, but given a new set of rules have already come in the city, the game will not last long.
Ad 1 + 2 )Compiler still tolerates multiple declarations, but not in one scope
If new version of a compiler defined that any variable is declared only relative to it's scope of validity, the serious programmer ought take this as a general principle. The code above actually has other problem, right nailed to the scope-of-validity:
2 ...
3 if ( 1 == 2 ) {
4 ...
5 double myVar = 1; // myVar declared & known |since HERE >
6 ... // masking any other,|known HERE :
7 ... // |known HERE :
8 } else // |till HERE . Undef further
9 {
10 ...
11 double myVar = 2; // myVar declared & known |since HERE >
12 // masking any other,|known HERE :
13 ... // |known HERE :
14 } // |till HERE . Undef further
so, if there were any _global_ scope'd variable with the same name myVar, it will not be "visible" during an existence of locally declared variable, wearing the same name.
Finally, having the code-execution escaped from any of the lines 8 or 14 further, the locally there declared variable double myVar simply ceased to exist anymore and this behaviour is principally correct ( and the "older" compiler releases were tolerating a sort of dangerous habit of side-effects, during years of tolerating scope-of-validity spillover(s), so it was the high time to clean the rules, so as to meet a fair level of C/S standards.
Ad 3) language receives a lot from MQL5, even if not used in MQL4
Yes, MetaEditor will correctly compile a MQL4 code into .mq4 code-execution format, no problem here. Even an auto-update process started to go independently from MT4 Terminal platform (auto-)updates ( so you will quite often see new Help file coming and enforced re-compilation of all your localhost visible .MQ4 assets into updated .EX4 format, so "Do not panic."
Better never install a Broker-agnostic MT4, always go to your Broker's Support and get installation package & help from your Broker. This is business relation you have signed in a contract, so keep these strings as you are going to trade your money on a table they operate under the set Terms & Conditions. Some Brokers have means of platform customisations, so rather benefit from their custom settings that will match their Server-side automation.
It is more a question of economy of R&D efforts. ( May read a lot about language components injected from the MQL5 domain in the IDE Editor MQL4 Help ). This is a natural will of the product design strategy, not to double efforts on a dual-line. Without doubts, there are many details the Help file could be improved and better maintained, the common sense here is to live with the facts and re-learn what newly introduced features remain neutral for the MQL4 code base and what new things may actually help one a lot in aspects, where older compilers were short in powers.
If one objects that some compiler / platform re-design steps were bad, I would agree on a single-thread, platform-critical, potentially blocking, concentration of executing all the CustomIndicator-s in just one SPoF-thread.
But C'est La Vie, until system architects will not review this SPoF, the platform will remain susceptible to crashes from this feature, but the ball is on the other side of the court and a change will have to be implemented there.
the code might be run with 'strict' or non-strict mode.
strict means that variable must be declared within its scope, non-strict - all the mess that you have now.
so put #property strict at the beginning of the file
open a demo account somewhere and install mt4 there. demo can be valid for 30 days only with registration via web-site of a broker or with unlimited and demo opened from mt4 (example - Alpari)
I'm trying to create my own custom drilldown functionality, where a URL dynamics://0?myfunction_123456 will launch my own code.
In C\SysStartupCmd\construct, this base code:
case 'viewalert':
sysStartupCmd = new SysStartUpCmdViewAlert(s,parm);
break;
case 'drilldown':
sysStartupCmd = new SysStartUpCmdDrillDown(s,parm);
break;
case 'viewalertrule':
sysStartupCmd = new SysStartUpCmdViewAlertRule(s,parm);
break;
I've tested and these all get fired with these URLs:
dynamics://0/?DrillDown_382576
dynamics://0/?ViewAlert_382576
dynamics://0/?ViewAlertRule_382576
However, if I add my own case, leaving all other code the same, I can't get the URL to fire:
case 'myFunction':
sysStartupCmd = new SysStartUpCmdDrillDown(s,parm);
break;
I've dug all over the system and can't figure out what causes the dynamics:// URL to only fire for those three cases. Is there a registry entry or something? I've found C\EventDrillDownPoller which appears to create a PipeServer to maybe handle what's incoming?
Of course, I figure out my own answer every time I type up a stackoverflow question, but I think the information is really useful.
This stack question led me to find out that C:\Program Files (x86)\Microsoft Dynamics AX\50\Client\Bin\AxHLink.exe %1 handles Dynamics:// URLs.
Which led me to Microsoft's community forums where somebody else was facing a similar problem as me.
So the solution would be to either:
Create custom a URI handler with C# or some other language to communicate to AX (Similar to this)
Hi-jack one of the 3 handled existing cases with some custom X++ code to try and fork off of it. Perhaps by changing the drilldown target in the URL and handling that way, or appending some special characters to the string.
Call "c:\Program Files (x86)\Microsoft Dynamics AX\50\Client\Bin\Ax32.exe" -startupcmd=myfunction_myParams and make that a clickable link.
You have answered your own question, but it is quite easy (if you know how) to hook on the standard DrillDown code to customize AX to start a specific form like:
Starts AX on item 03310511 in company XXX
start dynamics://TEST/?DrillDown_0?table=InventTable&field=itemId&value=03310511&company=XXX
It will assume reasonable defaults.
start dynamics://TEST/?DrillDown_0?table=CustTable&value=113545
And AX can be called from a HTML e-mail, assuming the receiver has an AX client!
113545
You find my customization in my pastebin.
One of my users at a large university (with, I imagine, the aggressive security settings that university IT departments general have on their computers) is getting an empty string returned by Windows XP for CSIDL_COMMON_APPDATA or CSIDL_PERSONAL. (I'm not sure which of these is returning the empty string, because I haven't yet examined his computer to see how he's installed the software, but I'm pretty sure it's the COMMON_APPDATA...)
Has anyone encountered this or have suggestions on how to deal with this?
Here's the Delphi code I'm using to retrieve the value:
Function GetSpecialFolder( FolderID: Integer):String;
var
PIDL: PItemIDList;
Path: array[0..MAX_PATH] of Char;
begin
SHGetSpecialFolderLocation(Application.Handle, FolderID, PIDL);
SHGetPathFromIDList(PIDL, Path);
Result := Path;
end; { GetSpecialFolder }
ShowMessage(GetSpecialFolder(CSIDL_COMMON_APPDATA)); <--- This is an empty string
Edit:
Figuring out this API made me feel like I was chasing my tail - I went in circles trying to find the right call. This method and others similar to it are said to be deprecated by Microsoft (as well as by a earlier poster to this question (#TLama?) who subsequently deleted the post.) But, it seems like most of us, including me, regularly and safely ignore that status.
In my searches, I found a good answer here on SO from some time ago, including sample code for the non-deprecated way of doing this: what causes this error 'Unable to write to application file.ini'.
If you want to find out why an API call is failing you need to check the return values. That's what is missing in this code.
You need to treat each function on its own merits. Read the documentation on MSDN. In the case of SHGetSpecialFolderLocation, the return value is an HRESULT. For SHGetPathFromIDList you get back a BOOL. If that is FALSE then the call failed.
The likely culprit here is SHGetSpecialFolderLocation, the code that receives the CSIDL, but you must check for errors whenever you call Windows API functions.
Taking a look at the documentation for CSIDL we see this:
CSIDL_COMMON_APPDATA
Version 5.0. The file system directory that contains application data for all users. A typical path is C:\Documents and Settings\All
Users\Application Data. This folder is used for application data that
is not user specific. For example, an application can store a
spell-check dictionary, a database of clip art, or a log file in the
CSIDL_COMMON_APPDATA folder. This information will not roam and is
available to anyone using the computer.
If the machine has a shell version lower than 5.0, then this CSIDL value is not supported. That's the only documented failure mode for this CSIDL value. I don't think that applies to your situation, so you'll just have to see what the HRESULT status code has to say.
I developed an application of controlling other window using WindowsMessage. It works successfully with my sample application, which is build by C#.
However, then I tried to configure my controlling application with the legacy window, which is developed by VB6.0. Here I got 2 issues,
1) The following method returns false and textfield was not updated.
IntPtr wParam = IntPtr.Zero;
IntPtr lParam = Marshal.StringToHGlobalAuto(text);
bool retVal = Convert.ToBoolean(SendMessage(handle, WM_SETTEXT, wParam, lParam));
Can anybody help me to figure it out ?
2) When I scanned the sub-controllers in legacy application (using the window messaging),I found some controllers that their class names are ThunderRT6FormDC, ThunderRT6UserControlDC. What are these controllers ?
2) The ThunderRT6FormDC and ThunderRT6UserControlDC are Visual Basic specific class names: VB sprang from an original project called Thunder and so the name stuck with a lot of the bits and pieces of VB code. Many VB window classes have Thunder in the name, including the 2 you saw.
1) My expectation is that the handle you fetched is not pointing at the right window: are you using Spy++ or a similar tool to look at the VB6 window and determine the proper text window, or are you setting the focus to the text window before sending the WM_SETTEXT message?
As far as I've been able to find out, Windows doesn't offer an API function to tell what application has registered a global hotkey (via RegisterHotkey). I can only find out that a hotkey is registered if RegisterHotkey returns false, but not who "owns" the hotkey.
In the absence of a direct API, could there be a roundabout way? Windows maintains the handle associated with each registred hotkey - it's a little maddening that there should be no way of getting at this information.
Example of something that likely wouldn't work: send (simulate) a registered hotkey, then intercept the hotkey message Windows will send to the process that registered it. First, I don't think intercepting the message would reveal the destination window handle. Second, even if it were possible, it would be a bad thing to do, since sending hotkeys would trigger all sorts of potentially unwanted activity from various programs.
It's nothing critical, but I've seen frequent requests for such functionality, and have myself been a victim of applications that register hotkeys without even disclosing it anywhere in the UI or docs.
(Working in Delphi, and no more than an apprentice at WinAPI, please be kind.)
One possible way is to use the Visual Studio tool Spy++.
Give this a try:
Run the tool (for me, it's at C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\spyxx_amd64.exe or you can download it). Note: there is spyxx.exe (32-bit version) and spyxx_amd64.exe (64-bit version) - if you don't see anything in 64-bit use the 32-bit version (ie.catches messages only in same architecture)
In the menu bar, select Spy -> Log messages... (or hit Ctrl + M)
Check All Windows in System in the Additional Windows frame
Switch to the Messages tab
Click the Clear All button
Select WM_HOTKEY in the listbox, or check Keyboard in Message Groups (if you're OK with more potential noise)
Click the OK button
Press the hotkey in question (Win + R, for example)
Select the WM_HOTKEY line in the Messages (All Windows) window, right click, and select Properties... in the context menu
In the Message Properties dialog, click the Window Handle link (this will be the handle for the window that received the message)
Click the Synchronize button on the Window Properties dialog. This will show the window in the main Spy++ window treeview (if it's windows itself or some popup application it shows nothing).
On the Window Properties dialog, select the Process tab
Click the Process ID link. This will show you the process (In my Win + R case: EXPLORER)
Your question piqued my interest, so I've done a bit of digging and while, unfortunately I don't have a proper answer for you, I thought I'd share what I have.
I found this example of creating keyboard hook (in Delphi) written in 1998, but is compilable in Delphi 2007 with a couple of tweaks.
It's a DLL with a call to SetWindowsHookEx that passes through a callback function, which can then intercept key strokes: In this case, it's tinkering with them for fun, changing left cursor to right, etc. A simple app then calls the DLL and reports back its results based on a TTimer event. If you're interested I can post the Delphi 2007 based code.
It's well documented and commented and you potentially could use it as a basis of working out where a key press is going. If you could get the handle of the application that sent the key strokes, you could track it back that way. With that handle you'd be able to get the information you need quite easily.
Other apps have tried determining hotkeys by going through their Shortcuts since they can contain a Shortcut key, which is just another term for hotkey. However most applications don't tend to set this property so it might not return much. If you are interested in that route, Delphi has access to IShellLink COM interface which you could use to load a shortcut up from and get its hotkey:
uses ShlObj, ComObj, ShellAPI, ActiveX, CommCtrl;
procedure GetShellLinkHotKey;
var
LinkFile : WideString;
SL: IShellLink;
PF: IPersistFile;
HotKey : Word;
HotKeyMod: Byte;
HotKeyText : string;
begin
LinkFile := 'C:\Temp\Temp.lnk';
OleCheck(CoCreateInstance(CLSID_ShellLink, nil, CLSCTX_INPROC_SERVER, IShellLink, SL));
// The IShellLink implementer must also support the IPersistFile
// interface. Get an interface pointer to it.
PF := SL as IPersistFile;
// Load file into IPersistFile object
OleCheck(PF.Load(PWideChar(LinkFile), STGM_READ));
// Resolve the link by calling the Resolve interface function.
OleCheck(SL.Resolve(0, SLR_ANY_MATCH or SLR_NO_UI));
// Get hotkey info
OleCheck(SL.GetHotKey(HotKey));
// Extract the HotKey and Modifier properties.
HotKeyText := '';
HotKeyMod := Hi(HotKey);
if (HotKeyMod and HOTKEYF_ALT) = HOTKEYF_ALT then
HotKeyText := 'ALT+';
if (HotKeyMod and HOTKEYF_CONTROL) = HOTKEYF_CONTROL then
HotKeyText := HotKeyText + 'CTRL+';
if (HotKeyMod and HOTKEYF_SHIFT) = HOTKEYF_SHIFT then
HotKeyText := HotKeyText + 'SHIFT+';
if (HotKeyMod and HOTKEYF_EXT) = HOTKEYF_EXT then
HotKeyText := HotKeyText + 'Extended+';
HotKeyText := HotKeyText + Char(Lo(HotKey));
if (HotKeyText = '') or (HotKeyText = #0) then
HotKeyText := 'None';
ShowMessage('Shortcut Key - ' + HotKeyText);
end;
If you've got access to Safari Books Online, there is a good section about working with shortcuts / shell links in the Borland Delphi 6 Developer's Guide by Steve Teixeira and Xavier Pacheco. My example above is a butchered version from there and this site.
Hope that helps!
After some research, it appears that you'd need to get access to the internal structure that MS uses to store the hotkeys. ReactOS has a clean room implementation that implements the GetHotKey call by iterating an internal list and extracting the hotkey that matches the parameters to the call.
Depending on how close ReactOS' implementation is to the MS implementation, you may be able to poke around in memory to find the structure, but that's over my head...
BOOL FASTCALL
GetHotKey (UINT fsModifiers,
UINT vk,
struct _ETHREAD **Thread,
HWND *hWnd,
int *id)
{
PHOT_KEY_ITEM HotKeyItem;
LIST_FOR_EACH(HotKeyItem, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
{
if (HotKeyItem->fsModifiers == fsModifiers &&
HotKeyItem->vk == vk)
{
if (Thread != NULL)
*Thread = HotKeyItem->Thread;
if (hWnd != NULL)
*hWnd = HotKeyItem->hWnd;
if (id != NULL)
*id = HotKeyItem->id;
return TRUE;
}
}
return FALSE;
}
I presume this thread on sysinternals was asked by someone related to this question, but I thought I'd link to it anyway to keep the two together. The thread looks very intriguing, but I suspect that some deep dive spelunking would need to happen to figure this out without access to the MS internals.
Off the top of my head, you might try enumerating all windows with EnumWindows, then in the callback, send WM_GETHOTKEY to each window.
Edit: Apparrently I was wrong about that. MSDN has more information:
WM_HOTKEY is unrelated to the WM_GETHOTKEY and WM_SETHOTKEY hot keys. The WM_HOTKEY message is sent for generic hot keys while the WM_SETHOTKEY and WM_GETHOTKEY messages relate to window activation hot keys.
Note: Here is a program purporting to have the functionality you are looking for. You could try decompiling it.
Another thread mentions a global NT level keyboard hook:
Re-assign/override hotkey (Win + L) to lock windows
maybe you can get the handle of the process that called the hook that way, which you can then resolve to the process name
(disclaimer: I had it in my bookmarks, haven't really tried/tested)
I know you can intercept the stream of messages in any window within your own process - what we used to call subclassing in VB6. (Though I do not remember the function, perhaps SetWindowLong?) I am unsure if you can do this for windows outside your own process. But for the sake of this post lets assume you find a way to do that. Then you can simply intercept the messages for all top level windows, monitor for the WM_HOTKEY message. You wouldn't be able to know all the keys right off the bat, but as they were pressed you could easily figure out what application was using them. If you persisted your results to disk and reloaded each time your monitor application was run you could increase the performance of your application over time.
This doesn't exactly answer the part of the question that is about the Windows API, but it answers the part of the question that is about a list of global hotkeys and the applications that "own" them.
The free Hotkey Explorer at http://hkcmdr.anymania.com/ shows a list of all global hotkeys and the applications that own them. This just has helped me figure out why an application-specific shortcut key stopped working and how to fix it (by reconfiguring the registered global hotkey in the app that had it registered), within a few seconds.