03-16-2016 03:27 PM
@rolfk wrote:Juast a little bug:
In Power Create Request.vi, you create a memory pointer to pass an unicode string to the PowerCreateRequest() Windows API. After that API returns this pointer should be deallocated with DSDisposePtr() to avoid a memory leak.
Alternatively you could leave away that pointer creation altogether by using the MoveBlock call to retrieve the actual pointer value from the LabVIEW array handle returned from the second MultibyteToWideChar function. In fact the whole string handling in that VI is a bit murky. You should really use the return value of the MultibyteToWideChar() as length indicator, if <=0 the function failed, otherwise it indicates the number of 16 bit character code points including the terminating NULL character. Using that you could at least leave away the entire Byte Swap, Typecast and String Length nodes.
Also a HANDLE in Windows is technically always pointer sized so you should configure the Call Library Nodes accordingly and make the handle control an U64.
Changing the Conditional Disable Structure to "TARGET_TYPE==Windows" will make it also work when used outside a project.
Note that the passing of the 64bit "Pointer" in the structure like this only works by the virtue of several conditions here. Most importantly because it's the last element in the cluster. On 32 Bit LabVIEW this pointer is really just a 32 bit value. Since this runs on an Intel x86 CPU which uses Little Endian or LSB (Least Signficant Byte) first, the excessive 32 bits from the LabVIEW 64 bit pointer just trail over the end of the data structure as the function sees it. If other eleemnts would follow in the structure one would need to create two distinct structures, one for LabVIEW 32 bit and one for LabVIEW 64 bit, as otherwise the offsets of the element after that pointer wouldn't be correct anymore on one of the platforms. Another lucky feature of this structure is that the layout doesn't cause alignment issues either since the two elements in front of the string pointer add up to 64 bits, so that the pointer is always properly aligned to 64 bit,
Rolf,
Thanks for your in-depth knowledge of Windows internals. I'll work on this in the next few days. I'll update the git source and the NI Document when I've worked my way through it.
—Ben
03-18-2016 05:55 PM
@rolfk wrote:Juast a little bug:
In Power Create Request.vi, you create a memory pointer to pass an unicode string to the PowerCreateRequest() Windows API. After that API returns this pointer should be deallocated with DSDisposePtr() to avoid a memory leak.
Alternatively you could leave away that pointer creation altogether by using the MoveBlock call to retrieve the actual pointer value from the LabVIEW array handle returned from the second MultibyteToWideChar function. In fact the whole string handling in that VI is a bit murky. You should really use the return value of the MultibyteToWideChar() as length indicator, if <=0 the function failed, otherwise it indicates the number of 16 bit character code points including the terminating NULL character. Using that you could at least leave away the entire Byte Swap, Typecast and String Length nodes.
Also a HANDLE in Windows is technically always pointer sized so you should configure the Call Library Nodes accordingly and make the handle control an U64.
Changing the Conditional Disable Structure to "TARGET_TYPE==Windows" will make it also work when used outside a project.
Note that the passing of the 64bit "Pointer" in the structure like this only works by the virtue of several conditions here. Most importantly because it's the last element in the cluster. On 32 Bit LabVIEW this pointer is really just a 32 bit value. Since this runs on an Intel x86 CPU which uses Little Endian or LSB (Least Signficant Byte) first, the excessive 32 bits from the LabVIEW 64 bit pointer just trail over the end of the data structure as the function sees it. If other eleemnts would follow in the structure one would need to create two distinct structures, one for LabVIEW 32 bit and one for LabVIEW 64 bit, as otherwise the offsets of the element after that pointer wouldn't be correct anymore on one of the platforms. Another lucky feature of this structure is that the layout doesn't cause alignment issues either since the two elements in front of the string pointer add up to 64 bits, so that the pointer is always properly aligned to 64 bit,
Rolf,
I've made several changes per your suggestions.
I've disposed of the pointer after I call PowerCreatRequest.
I changed the handle type to a Signed pointer. You suggested a unsigned pointer but from the power create request documentation it will return a -1 if it fails. This implies that it must be a signed integer.
I changed the conditional disable structure so the functions ca be used outside of a LabVIEW project.
Your suggestions about removing the byte swap, type cast and length counting. I can do all this and it does return a valid pointer. The problem is that the 'powercfg /requests' no longer shows the Simple Reason String but just random garbage I left my code as it is, it may be opaque but it does in fact work.
I've updated the NI Document and the code on GitHub.
Thanks for all your help,
--Ben
03-19-2016 06:06 AM - edited 03-19-2016 06:07 AM
@Ben_Manthey wrote:Your suggestions about removing the byte swap, type cast and length counting. I can do all this and it does return a valid pointer. The problem is that the 'powercfg /requests' no longer shows the Simple Reason String but just random garbage I left my code as it is, it may be opaque but it does in fact work.
Well the byteswap can be fully removed anyways. Technically a string and and array are both LabVIEW handles and if you just are interested in the content of the data pointer inside that handle as you do with the MoveBlock function you can simply pass the u16 array to that function instead of going through hoops and loops to convert the buffer into a string.
The removal of the whole DSNewPtr() is a bit more complilcated. I wasn't really sure and just did it quickly without going in depth to check that things are correct. Thinking a bit more about this you would have to do two MoveBlock() operations. The first copies the intermediate handle pointer out of the handle and the second dereferences that pointer to get the actual data pointer. It's all a bit involved and your creation of an intermediate data pointer to copy the handle contents into, is more straightforward albeit an extra memory copy operation.
03-21-2016 10:59 AM - edited 03-21-2016 11:00 AM
Not sure what kind of policies you are running, but can you just run this EXE that runs in your system tray?
http://www.symantec.com/connect/downloads/readynosleepexe-prevents-screensaver-and-pc-locking
The source is an AutoIt3 EXE and is included, it looks like it just moves your mouse one pixel, then moves it back every 30 seconds. Maybe this could be ran on startup of the PC.
In my environment test PCs aren't on the domain, and aren't IT controlled for reasons like this, (and random Windows update reboots)
Unofficial Forum Rules and Guidelines
Get going with G! - LabVIEW Wiki.
17 Part Blog on Automotive CAN bus. - Hooovahh - LabVIEW Overlord
03-21-2016 11:48 AM
@Hooovahh wrote:Not sure what kind of policies you are running, but can you just run this EXE that runs in your system tray?
http://www.symantec.com/connect/downloads/readynosleepexe-prevents-screensaver-and-pc-locking
The source is an AutoIt3 EXE and is included, it looks like it just moves your mouse one pixel, then moves it back every 30 seconds. Maybe this could be ran on startup of the PC.
In my environment test PCs aren't on the domain, and aren't IT controlled for reasons like this, (and random Windows update reboots)
Sadly we do have computers on the domain here. I need to be able to stream data to domain shares and anything plugged in to the network per policy needs to be on the domian. It also would be nice to be able to have the computer still able to go to sleep and lock correctly if you aren't running a program.
Also it is odd you should mention a little program that just runs in the system tray... I made one using these Vis. It was a 10 minute quickie that I could put on computers until I could update projects, but it does work.
03-21-2016 03:40 PM - edited 03-21-2016 03:43 PM
@BowenM wrote:
@Hooovahh wrote:Not sure what kind of policies you are running, but can you just run this EXE that runs in your system tray?
http://www.symantec.com/connect/downloads/readynosleepexe-prevents-screensaver-and-pc-locking
The source is an AutoIt3 EXE and is included, it looks like it just moves your mouse one pixel, then moves it back every 30 seconds. Maybe this could be ran on startup of the PC.
In my environment test PCs aren't on the domain, and aren't IT controlled for reasons like this, (and random Windows update reboots)
Sadly we do have computers on the domain here. I need to be able to stream data to domain shares and anything plugged in to the network per policy needs to be on the domian. It also would be nice to be able to have the computer still able to go to sleep and lock correctly if you aren't running a program.
Also it is odd you should mention a little program that just runs in the system tray... I made one using these Vis. It was a 10 minute quickie that I could put on computers until I could update projects, but it does work.
The problem I'm trying to solve with this code is based on two common problems.
1: IT departments that won't let users install programs or change sleep/hibernate/screen-saver settings.
2. The user of your LabVIEW program needing to remember to turn on and off some secondary program to keep the computer from sleeping.
This program uses the official Microsoft functions for prevent sleep, hibernate or screen shutoff/lock. Your user doesn't have to remember to do anything extra, if they're running the LabVIEW program it's not going to go to sleep or whatever else you've set it to do. When the program stops normal sleep (or whatever) behavior is restored.
Yes, this solution is more complex to implement, but I've done all that work for you .All you have to do is drop my code into your existing program.
I hope this has provided some insite into my motivation for making this, please let me know if this helped?
—Ben
03-21-2016 03:46 PM
@rolfk wrote:
@Ben_Manthey wrote:Your suggestions about removing the byte swap, type cast and length counting. I can do all this and it does return a valid pointer. The problem is that the 'powercfg /requests' no longer shows the Simple Reason String but just random garbage I left my code as it is, it may be opaque but it does in fact work.
Well the byteswap can be fully removed anyways. Technically a string and and array are both LabVIEW handles and if you just are interested in the content of the data pointer inside that handle as you do with the MoveBlock function you can simply pass the u16 array to that function instead of going through hoops and loops to convert the buffer into a string.
The removal of the whole DSNewPtr() is a bit more complilcated. I wasn't really sure and just did it quickly without going in depth to check that things are correct. Thinking a bit more about this you would have to do two MoveBlock() operations. The first copies the intermediate handle pointer out of the handle and the second dereferences that pointer to get the actual data pointer. It's all a bit involved and your creation of an intermediate data pointer to copy the handle contents into, is more straightforward albeit an extra memory copy operation.
Yes, just passing the array of U16's from the convert to unicode function to the Create Power request function does resulti n a valid handle being returned. But, it does not resuly in the unicode string being properly set in the power cfg request function. You can check this by typing powercfg /requests into an elevated command prompt.
03-21-2016 04:08 PM
Here is the method I've used to prevent PC's from sleeping, hibernating, or just going to a locking screen saver. I couldn't be sure if IT would institute some policy that would prevent a software solution from working.
The hardware solution is a mouse jiggler. http://www.amazon.com/CRU-DataPort-30200-0100-0011-WiebeTech-Mouse-Jiggler/dp/B000O3S0PK
Plug it into a USB port and the PC will recgonize it as a mouse which does the 1 pixel jiggle about every 20 seconds.
Of course it could be violating security policies that your company has in place because it could leave an unattended PC exposed to unauthorized access. Just remember to unplug it before your IT guy comes around to mess with your PC and questions what it is.
03-22-2016 02:33 AM - edited 03-22-2016 02:35 AM
@Ben_Manthey wrote:
Yes, just passing the array of U16's from the convert to unicode function to the Create Power request function does resulti n a valid handle being returned. But, it does not resuly in the unicode string being properly set in the power cfg request function. You can check this by typing powercfg /requests into an elevated command prompt.
That's not what I meant. My first suggestion was to get rid of the byteswap and typecast in your original code. It should not matter if you pass a pointer to a swapped and typecast backswapped string databuffer or directly the pointer to the array databuffer to your MoveBlock() function which copies the Unicode string into your allocated buffer.
The second suggestion is completely seperate to this by trying to get rid of the immediate data buffer pointer. For that to work you would need two MoveBlock() calls. With the first you copy (dereference) the intermediate master pointer out of handle and with the second you copy (dereference) the actual data pointer out of the master pointer. Last but not least you need to offset this pointer with 4 for the initial 32 bit length member in the array/string handle. Basically to get at the data pointer of a LabVIEW handle you wouuld write this in C (For strings you have the LHStrBuf() macro which hides away the involved syntax):
(*ptr)->elm which is equal to (**ptr).elm
Each star in front of the pointer is a pointer dereference, which the CPU has to copy out (dereference) the content of the address. The elm is the actual start of the data buffer which has an offset of 4 into the real data pointer for a 1D LabVIEW handle for the int32 length indicator.
But there are many complications with this for more generic use if you want to make sure that it works for 32 bit and 64 bit LabVIEW equally which are to involved to explain here all, so in hindisight the attempt to remove the intermediate data pointer is actually causing more potential troubles than its little performance gain is worth at all.