Text from UIAutomation property value truncated to 4k - ui-automation

I'm using UIAutomation from a 32-bit C++ application on Windows 7 to get the text content of windows of other processes. I noticed that the API always returns strings truncated to exactly 4096 characters if the text in the windows is longer than that. This happens both with the GetCachedPropertyValue() and the GetCurrentPropertyValue() calls, for both the UIA_ValueValuePropertyId and UIA_LegacyIAccessibleValuePropertyId property Ids.
Tested, among others, against 32- and 64-bit Notepad.
When I retrieve the text using SendMessage and the WM_GETTEXTLENGTH and WM_GETTEXT messages, the complete, untruncated text is returned. (This I currently use as a workaround.)
Looking through the documentation, I can nowhere find any mention of this limitation or how to get around it, which I would expect if truncation was by design.
I found a similar question on stackoverflow but there truncation was apparently due to the Visual Studio debugger, not to the UIAutomation API. However, this question makes it clear that UIAutomation should be able to return very long texts.
Googling the issue leads to another question on stackoverflow that also mentions the 4096 character limit, but unfortunately that question and any possible answer is deleted.
Perhaps the properties UIA_ValueValuePropertyId or UIA_LegacyIAccessibleValuePropertyId are not the correct one to use, but I failed to identify a better one.
Can anyone point me out what I'm doing wrong, or have suggestions for what I could try? Pointers to pieces of documentation that I obviously missed are welcome, too.
TIA

The exposition of the value is here for convenience but has limited capabilities. Instead, you must use TextPattern and it's DocumentRange property. This is explicitly specified here.
From it you can use the GetText(-1) method to retrieve your data.
You can code it like that :
string GetText(AutomationElement ae)
{
return (ae.GetCurrentPattern(TextPattern.Pattern) as TextPattern)?.DocumentRange.GetText(-1);
}

Related

Possibility of a multilanguage 'source' name with Twincat Eventlogger

Roald has written an excellent guide for the Twincat Eventlogger.
https://roald87.github.io/twincat/2020/11/03/twincat-eventlogger-plc-part.html
https://roald87.github.io/twincat/2021/01/20/twincat-eventlogger-hmi-part.html
For us this is exactly what we want, there is however 1 thing I haven't figured out. How to get the sourcename of the alarm in multiple languages in the HMI. params::sourceName gives the path in the software (example: MAIN.fbConveyor1.Cylinder1) This path can be customized when initializing the alarm (as Roald has shown). This doesn't work in my case, since I would like to define a generic alarm (example: "Cilinder not retracted within maximum time") that is instantiated multiple times.
I was thinking of using the source as a way to show the operator where the alarm occurs. We use this way (path) already for saving machine settings among other things. The machines we build are installed all over the world, so multilanguage is a must.
Beckhoff does support multilanguage alarm names (when defined), but the source is not defined, but dynamically generated.
Anyone have an idea how this problem can be solved?
If I understand your question correctly, then being able to parameterize the event text with information of the source of the problem should help you out.
If you define the event text as Cylinder {0} has not retracted in time. then you can add the arguments of that text during runtime.
IF bRaiseAlarm THEN
bRaiseAlarm := FALSE;
fbAlarm.ipArguments.Clear().AddString('Alice');
fbAlarm.Raise(0);
END_IF
However, since this also stated in the articles you mentioned, I am unsure if this would solve your problem.
'Alice' in this example, can be hard to localize. The following options come to my mind.
The string can be based on an ENUM. Enums can have textlist support, so if you add your translations there, that should allow multilingual output. However... this does require a lot of setup, placing translations inside your code, and making sure the PLC application is aware of the language that the parameter should use.
Use tags to mark the source device, as tags can be language invariant. It is not the most user-friendly method, but it could work for you. It would become something like: "Cylinder 'AA.1123' did not retract in time.". 'AA.1123' as a tag would have to be stored inside your PLC code as a string. You will have to trust that your operator can relate the tag back to the actual source.
Hopefully, this helped, or else please help me understand the problem better.

How do I Call SMSFormatMessageCtl.FormatModuleMessage?

I'm attempting to query the server for particular status messages and build the string format of them. The status message data doesn't contain the translated strings. They appear to be stored in srvmsgs.dll in the install directory for the console.
I see some "documentation" (proof that it exists, not help for using it) about the FormatModuleMessage method of SMSFormatMessageCtl. Sadly, there are no examples that I can find. This guy mentions that he has gotten it to work, but he doesn't provide details. In fact, I cannot even find the DLL referenced (FormatMessageCtl.dll) on my computer. StatView.EXE (the status message viewer app that comes with the client) exists, but running the dependency walker on it doesn't reveal any overt reference the desired .DLL.
Can this be done in VBScript or, preferably, PowerShell? I'm actually using Perl, but this is probably less common and nearly impossible to find meaningful code examples for. A working VBScript or PowerShell example would be a good place to start.
“About Configuration Manager Component Status Messages” has an example, but I think it’s in C# or C++.
Any suggestions on how to accomplish this?
I'm that guy. It's been 2 years, but I think the way I did it was that first I did a regsvr32.exe for the dll to register it, and then I just created an SMSFormatMessageCtl object through COM
For PowerShell that would be
New-Object -COMObject SMSFormatMessageCTL
For Perl, it's been even longer, but if I recall correctly, that would be
Win32::OLE->DispatchEx('SMSFormatMessageCtl');
Once you have the object you can call the FormatModuleMessage method, and don't forget the part about doing a bitwise OR of the Severity and MessageID from the WMI objects.

Using HIDAPI, how can you query the raw report descriptor?

I'd like to deconstruct the raw reports received from the hid_read function of hidapi.
As I understand, this can be achieved using the information from the device's report descriptors. But when trying to query for those descriptors, I get lost somewhere between the HID Spec and using the methods available in hidapi.
I would love to see a concrete C or node-hidapi based example that queries and enumerates all the report descriptors for a device — perhaps a mouse to keep things simple?
I asked Alan Ott by email about this, and he responded with no as follows:
HIDAPI does not provide functions for getting or parsing the report
descriptor. Since HIDAPI is for talking to a custom devices, these
devices will likely contain all or mostly vendor-defined report items
anyway.
This isn't exactly what you're looking for, but it will get the same job done. I highly recommend you use libusbx over any other hid library. If you are willing to do so, here is a very blatant example of device enumeration.
Edit:
It appears that libusbx has been merged back into libusb. This is awesome! As the above link is broken, here is the new link.
I had success with using both https://github.com/Orochimarufan/HIDRAW/tree/master/HIDRAW_test (that is hopefully the C code example that you asked about) and RDD! USB HID Report Descriptor Decoder for more descriptive output.

G-WAN: how to get rid of the "?" in URL and how to set default language?

In G-WAN the default URL is in the form mydomain.com/?hello.c
I want to get rid of the ? to have URLs that look like mydomain.com/hello
The user manual mentions substituting a different character such as ' for ?. In that case the URL would look like mydomain.com/'hello.c
But I don't want to use a different character, I want to get rid of the special character completely. Is that possible?
The default language for G-WAN is C. So mydomain.com/?hello means mydomain.com/?hello.c
How do I change the default to a different language, say Java, so that mydomain.com/?hello now means mydomain.com/?hello.java
Can I set different default languages for different virtual hosts?
Finally, how do I change the URL format for passing parameters? According to the user manual the default format is:
mydomain.com/?hello.c&name=Eva
I want to change it to:
mydomain.com/hello?name=Eva
Is that possible?
This has already been asked many times, and a few solutions are found here:
G-WAN handler rewriting solution
You should note, however, that the way you mean to pass arguments as ?something=answer instead of & only applies to the first argument passed. You can't do ?this=that?somethingelse=this because only the first can be ? and the rest must be &. In fact you can ignore using ? completely and only use & with virtually unlimited arguments so it's in fact better to stick to only using &.
It's important to note for future reference to anyone asking similar questions, G-WAN gives you the entire headers through multiple steps of the HTTP transaction and being that you can modify them with c/c++, you can change anything at all that you want before the requests are handled by the server or sent back to the client. The only limitation is your knowledge and imagination.

Xcode (10.7) -- clGetProgramBinaries results unreadable

I have an OpenCL kernel that runs well but I want to look at the intermediate code. I use getprograminfo to pull out the binary and save it to a text file. I've tried this with nVidia, AMD, an i7 and a Xeon.
In all of these cases the binary is unreadable.
I understand that on OS X the chunk of data returned is actually a binary plist. I've found instructions for using plutil to convert it to xml, and they work.
It's still unreadable ... though I've seen instructions online that this is where you find the PTX code (in the case of my AMD 5870). There's the expected clBinaryData key but the data under that key is still one big chunk of stuff, not readable IL instructions in text form.
I'd really like to examine the intermediate language to assess inefficiencies in my use of the gpu. Is this simply not possible under Xcode? Or, what am I doing wrong?
Thanks for any information!...
If you run your program with following environmental variable set you should see .IL and .ISA files in your directory.
$ GPU_DUMP_DEVICE_KERNEL=3 ./my-program
Another way is to use AMD APP Kernel Analyzer (which comes along with AMD APP SDK) to look at the Intermediate file i.e IL and ISA.
(I am not sure whether AMD APP SDK available for MAC or not).
One more option according to APP SDK documentation, put the below in your host code.
putenv("GPU_DUMP_DEVICE_KERNEL=3");
References
AMD OpenCL Programming Guide
AMD Devgurus forum
(Making this a top-level answer so I can do some formatting.)
ocluser's answer was very helpful, in that it was enlightening and caused great learning, though it did not, alas, solve the problem.
I've verified that the environment variable described is being set, and is available to my application when run from within xcode. However, it does not have (under OSX) the highly desirable effect it has under Linux.
But, I now know how to set environment variables in 7 of 8 different ways. I also set "tracer" envars to tell me which methods are effective within the scope of my application. From the below, you can see that both the method of "edit scheme" to add arguments works, as does the "putenv" suggested by ocluser. What didn't set it in that scope: ~/.MACOS/environment.plist, app-specific plist, .profile, and adding a build phase to run a custom script (I found at least one other way within xcode to set one but forgot what I called the tracer and can't find it now; maybe it's on another machine....)
GPU_DUMP_DEVICE_KERNEL is 3
GPU_DUMP_TRK_ENVPLIST is (null)
GPU_DUMP_TRK_APPPLIST is (null)
GPU_DUMP_TRK_DOTPROFILE is (null)
GPU_DUMP_TRK_RUNSCRIPT is (null)
GPU_DUMP_TRK_SCHARGS is 1
GPU_DUMP_TRK_PUTENV is 1
... so, no this doesn't really answer the question, but expands on it a bit. Sorry if poor form. Thanks!
Have not given up and shall provide an actual problem-solver if I find one.