AutoHotkey Community

It is currently May 27th, 2012, 7:04 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 189 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6 ... 13  Next
Author Message
 Post subject:
PostPosted: March 14th, 2006, 12:46 am 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
I assume you tried the original (v. 1.05), and it worked correctly. It looks like I oversimplified the code, although it works for me on two different XP SP2 machines, so I cannot find the problem. Others: does it suck on your system, too?


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 14th, 2006, 1:25 am 
Offline

Joined: August 24th, 2005, 5:17 pm
Posts: 1237
Sorry, my fault, forgot I had commented out the "SetBatchLines -1" (was being cautious as an earlier version locked up a bit) - turns out that it can mess up both of the examples most of the time but fine when it's there. The SetBatchlines command should probably be inside of the CMDret_RunReturn function to make sure it doesn't get commented out or left off as it seems to be essential.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 14th, 2006, 1:57 am 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
Evl is right! Without " SetBatchLines -1 " the script does not work right. This is quite surprising. Can anyone explain it?

Accordingly, we need the following in the beginning of the function code
Code:
  BatchLines0 = %A_BatchLines%
  SetBatchLines -1
and in my shorthand version of Corrupt's code, the following one just before the Return line
Code:
  SetBatchLines %BatchLines0%
In the original there are multiple Return commands, each have to be preceded by this line.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 14th, 2006, 2:08 am 
Offline
User avatar

Joined: December 29th, 2004, 1:28 pm
Posts: 2545
Laszlo wrote:
It still works, almost perfectly (version 1.05). A few questions:
Good to hear :) . Thanks for testing :)
Laszlo wrote:
- What do you use the GLOBAL cmdretPID for? When the function returns, it is empty. Do you want to check its value in a timer routine?
In most cases I would likely start the function with a timer instead but, yes ,the general idea is to give the user a method of stopping the process if necessary. One of the features that a few people had asked for with the .DLL version was a way to abort if a button was pressed by accident, something went wrong, etc...
Laszlo wrote:
- StringTrimLeft, CMDout, CMDout, 2 cuts off the first two characters of the output. Did this instruction remain from an earlier version?
It was added to cut RR from the beginning of the string if Return output was chosen. Removing the initial R value would cause it to truncate the first 2 characters of data
Laszlo wrote:
- SetBatchLines, -1 in a function makes a global change. You probably want to save the old value beforehand and restore it before return, but it is easier to remove it, and let the user specify it outside of the function, if he needs that extra speed.
I had added it in for testing but forgot to remove it. Thanks for the reminder.
Laszlo wrote:
- Do you need VarSetCapacity(lpBuffer, 0)? This local variable is removed, when the function returns, anyway.
Good point.
Laszlo wrote:
- Do you need " OR bSize > 0" in the instruction IF (ErrorLevel OR bSize > 0)? The next line checks if bSize > 0, anyway.
Yes, this is currently necessary. This is how the function determines when to read data from the pipe and when to stop trying to read and quit. I'll try and explain a bit better after trying to answer your questions... :)
Laszlo wrote:
- To preserve any leading or trailing spaces, don't we need AutoTrim Off?
I haven't seen a need for it with the testing that I've done so far. Do you have an example that I could try to reproduce an issue?
Laszlo wrote:
Here is a variant, without the ByRef parameter and with changes according to the list above. I also made it more flat, such that there are fewer levels of nested if's (it is easier to find the matching braces). I made it for myself, to be able to understand the logic of the 1.05 code.

Thanks for sharing your modifications :) . I'll have a look. I likely won't change the structure of the code in the first post for a few more versions though. Although I definitely appreciate the time and effort taken to remove a lot of the unnecessary structural syntax, I prefer to have the code a bit more spread out while adding to the code and testing different ideas. It's more of a personal preference I guess :) . I'm starting to lean more toward the idea of returning the output as the Return value also. Maybe in the next version...


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 14th, 2006, 2:10 am 
Offline
User avatar

Joined: December 29th, 2004, 1:28 pm
Posts: 2545
Laszlo wrote:
Evl is right! Without " SetBatchLines -1 " the script does not work right. This is quite surprising. Can anyone explain it?

Although I haven't taken a close look yet I'm guessing that this is likely due to removing the second If statement in the read loop.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 14th, 2006, 2:48 am 
Offline
User avatar

Joined: December 29th, 2004, 1:28 pm
Posts: 2545
Although it might not be necessary at this point, I thought I'd take a minute and try and explain a bit of what the current code is doing before working on the next version. Here's the basic idea (significant parts):

1) Create a pipe. Retrieve Read and Write handles. This is used to redirect the output from the console and to buffer the data.

2) Create a process by executing a console based program and set the output to use the write end of the pipe

3) Start a loop that Peeks at the contents in the pipe.

4) Next we need to know 2 details. When the process has finished executing and when we have read all of the data from the pipe. When both of these are true we want to close our read and write handles and return the results.

4a)If the process is still running we need to keep checking the pipe to see if it has placed any output in the pipe. If it has we need to read the data from the pipe and add it to our output variable.

4b)If the process has finished we need to check the pipe for data. If there is still data in the pipe we need to read this data and add it to our output variable before leaving the function.

4c)If the process is still running but the pipe is empty we want to try and slow things down a bit to prevent the script from acting as if it is in an endless loop and using up our processor's precious time. This is the reason for the sleep value in the loop.

4d)If something goes wrong and the process is hung we want to provide a method of aborting and returning the output so far. A global variable is currently provided that contains the PID of the running process so that various methods can be used to force the function to quit without having to kill the script.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 14th, 2006, 5:29 am 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
corrupt wrote:
Laszlo wrote:
Without " SetBatchLines -1 " the script does not work right...
Although I haven't taken a close look yet I'm guessing that this is likely due to removing the second If statement in the read loop.
Adding the condition back, by
Code:
        If (ErrorLevel = 0 and bsize = 0)
          break
insted of
Code:
        IfEqual ErrorLevel,0, break
does not completely fix the problem. Occasionally, the directory is shown empty, but the original 1.05 code seems to be always OK. I shall stop shortening these codes, before something really bad happens...


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 14th, 2006, 7:12 am 
Offline

Joined: September 25th, 2005, 4:31 pm
Posts: 610
Try replacing:

Code:
VarSetCapacity(lpBuffer, bSize)


with

Code:
VarSetCapacity( lpBuffer, bSize, 0 )


The data read from the pipe is not necessarily null-terminated...

and remove:

Code:
DllCall("lstrcpyn", "UInt", &lpBuffer, "UInt", &lpBuffer, "Int", bRead)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 14th, 2006, 5:34 pm 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
Thanks, Shimanov! (I did not want to hijack this thread, but...) your suggestions did not help. Without SetBatchLines -1, once in every half a dozen runs one of the outputs are still shown as empty. I moved the Sleep 0 command BEFORE the IF...Continue, and it improved the error rate to one in 50 runs. Not surprising! It did not slow down the loop before. Increasing the Sleep time to 10 gave a slight further improvement. With Sleep 50 I did not experience this error any more (tried over 1000 runs). Here is the code. I suspect, there is still something fishy in there. With SetBatchLines -1, Sleep 0 is enough.
Code:
AutoTrim Off         ; needed for leading/trailing spaces returned
MsgBox 48, CMDret test - Environment Vars, % CMDret_RunReturn("cmd /c set")
MsgBox 48, CMDret test – Directory Listing,% CMDret_RunReturn("cmd /c dir c:\")

CMDret_RunReturn(CMDin)
{
  Global cmdretPID   ; for external abort
  VarSetCapacity(lpBuffer,1024)
  VarSetCapacity(sui,68, 0)
  VarSetCapacity(pi, 16, 0)
  VarSetCapacity(pa, 12, 0)
  InsertInteger( 12, pa, 0)
  InsertInteger( 1,  pa, 8)

  IF (DllCall("CreatePipe", "UInt*",hRead, "UInt*",hWrite, UInt,&pa, Int,0) <> 0) {
    InsertInteger(68,    sui, 0 )
    DllCall("GetStartupInfo", "UInt", &sui)
    InsertInteger(0x101, sui, 44)
    InsertInteger(0,     sui, 48)
    InsertInteger(hWrite,sui, 60)
    InsertInteger(hWrite,sui, 64)

    IF (DllCall("CreateProcess",Int,0,Str,CMDin,Int,0,Int,0,Int,1,UInt,0,Int,0,Int,0,UInt,&sui,UInt,&pi)<>0) {
      cmdretPID := ExtractUInt(pi, 8)
      Loop {
        IF DllCall("PeekNamedPipe",uint,hRead, uint,0, uint,0, uint,0, "UInt*",bSize, uint,0) = 0
          break
        Process Exist, %cmdretPID%
        If (ErrorLevel = 0 and bsize = 0)
          break
        Sleep 50
        IfEqual bSize,0, Continue
        VarSetCapacity(lpBuffer, bSize, 0)
        IF (DllCall("ReadFile",UInt,hRead, Str,lpBuffer, Int,bSize, "UInt*",bRead, Int,0) > 0) {
          IFEqual bRead,0, Continue
          CMDout = %CMDout%%lpBuffer%
          }
      } ; Loop
    } ; IF CreateProcess

    DllCall("CloseHandle", UInt, hWrite)
    DllCall("CloseHandle", UInt, hRead)
  } ; IF CreatePipe

  cmdretPID =
  Return CMDout
}

InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4) {
   Loop %pSize%
      DllCall("RtlFillMemory", UInt,&pDest+pOffset+A_Index-1, UInt,1, UChar,pInteger >> 8*A_Index-8)
}

ExtractUInt(ByRef pSource, pOffset = 0, pSize = 4) {
   Loop %pSize%
      result += *(&pSource+pOffset+A_Index-1) << 8*A_Index-8
   Return result
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 14th, 2006, 8:27 pm 
Offline

Joined: September 25th, 2005, 4:31 pm
Posts: 610
Laszlo wrote:
your suggestions did not help


To each their own. I have not experienced any problems with the code.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 14th, 2006, 8:33 pm 
Offline

Joined: January 31st, 2005, 9:50 am
Posts: 3910
Location: Bremen, Germany
If I want to get the list of files from a directory that has spaces in its path, how do I call RunReturn() and pass the needed ""?

Edit: Found it:

Code:
RunReturn("cmd /c dir " """" "C:\Dokumente und Einstellungen\toralf" """")

_________________
Ciao
toralf
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 14th, 2006, 10:47 pm 
Offline

Joined: September 25th, 2005, 4:31 pm
Posts: 610
Here is another function, which may improve the reliability of reading from the pipe:

Code:
}
success := DllCall( "FlushFileBuffers", "uint", hWrite )
DllCall( "PeekNamedPipe", "uint", hRead, "uint", 0, "uint", 0, "uint", 0, "uint*", bSize, "uint", 0 )
if ( bSize > 0 ) {
  DllCall("ReadFile", "UInt",hRead, "Str", lpBuffer, "Int",bSize, "UInt*",bRead, "Int",0)
  CMDout = %CMDout% %lpBuffer%
}
cmdretPID=


The most likely source of failure occurs when the child process terminates, but the final write operation has not been completed. This condition can be verified on systems where this issue is evident, by inserting the following code:

Code:
}
Sleep, 10000
;success := DllCall( "FlushFileBuffers", "uint", hWrite )
DllCall( "PeekNamedPipe", "uint", hRead, "uint", 0, "uint", 0, "uint", 0, "uint*", bSize, "uint", 0 )
if ( bSize > 0 )
  MsgBox, pipe is not empty
cmdretPID=


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 15th, 2006, 12:24 am 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
" DllCall( "FlushFileBuffers", "uint", hWrite ) " freezes the function, I can kill it only with the Task Manager. If I use instead " DllCall("FlushFileBuffers", "uint", hRead) ", it does not solve the problem, sometimes the return value is empty (No SetBatchLines, Sleep 0). I tested it with
Code:
Loop 1000
{
   If StrLen(CMDret_RunReturn("cmd /c set")) < 100
      MsgBox ERROR
   If StrLen(CMDret_RunReturn("cmd /c dir c:\")) < 100
      MsgBox ERROR
   TrayTip,,%A_Index%
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 15th, 2006, 4:09 am 
Offline

Joined: September 25th, 2005, 4:31 pm
Posts: 610
Laszlo wrote:
" DllCall( "FlushFileBuffers", "uint", hWrite ) " freezes the function


You really have some system-specific issues. I cannot reproduce any of the problems you have described.

It is left to you to deduce the cause and solution.

Quote:
" DllCall("FlushFileBuffers", "uint", hRead) "


This should have no effect, since the function affects write buffers. Although, I noticed that your variant of corrupt's code differs in the placement of key function calls. Namely, the calls to CloseHandle occur before clearing "cmdretPID".


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 15th, 2006, 4:19 am 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
shimanov wrote:
It is left to you to deduce the cause and solution.
:cry:


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 189 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6 ... 13  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: Stigg and 19 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group