VBA: SendKeys "^c" seems to be copying to a different clipboard - vba

I have code that copies a code from excel and pastes it into and application. If the code succeeds the cursor in the application automatically highlights text 0. I then have the keyboard do "ctrl-c", which copies it correctly in the fact that I can paste 0 anywhere I choose by manually using my keyboard. But within the macro, using the paste function or directly accessing the clipboard doesn't give back this value, but other values copied in the macro at a prior line. Surprisingly enough, if I run my macro with a stop (big red dot) in the middle, after the "ctrl-c" command, it works fine, but then I have to run it in two steps.
Here's the code:
Public Sub CopyUPCtoRMS()
Dim UPC As String
Dim SomeInRMS As Boolean
Dim i As Integer
Dim sht As Worksheet
Set sht = Worksheets(1)
i = 2
'While Not IsEmpty(Cells(i, 5))
UPC = sht.Cells(i, 5).Copy
AppActivate "Retek - prd"
SendKeys "%r" & "{tab}{tab}{tab}", True 'reset the form
SendKeys "^v" & "{ENTER}", True 'paste UPC into retek
SendKeys "^c", True 'Copies '0' to a global clipboard.
'**I put a stop here and run the code in 2 portions as "Microsoft Visual Basic" lets you, and it works, but in two parts...
sht.Range("F10").Value = ClipBoard_GetText '<--- Pastes the UPC, not '0'
'Wend
End Sub
I've tried replacing the SendKeys with a function that does something similar to the same results (I can post that code if needed), to no avail. Anyway, that's all I can think of for now, it took several hours to figure out what was even wrong...

I've written an automation program like it seems you've done and have had similar issues. I think your last SendKeys call and the Clipboard_GetText call are happening in a timing where the copy function is not having time to complete before the next call executes. How I solved this in my application is grabbing the Sleep function from kernel32.dll (there is an article about it here: http://www.exceltrick.com/formulas_macros/vba-wait-and-sleep-functions/ - have to declare it differently for 64 bit systems) by placing this declaration in a place your code can see it (same module should be fine - all the way at the top prior to any functions or subs):
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
And then after each SendKeys call, you can force your code to pause a bit; since time is in milliseconds, 1000 is one second. So, for example, you can call
Sleep 500
and there will be a half second pause between the next line of code being run. I think this may work for you, because when you put a breakpoint (the red dot), have the code stop, and run it again manually, it works, apparently. So I think it may be a timing issue that Sleep can help you out with. If that's the issue, play with the sleep time to keep the operation time to a minimum. Good luck.

Related

Runtime Error 4605 Excel VBA Copying multiple ranges to word document [duplicate]

In researching this error I've come to the conclusion that it has to do with the clipboard not clearing like it should which wasn't an issue when we were using 2003 but is now that we are using 2010. (I also inherited this code from someone who doesn't work here anymore)
Run-Time error "4605":
This method or property is not available because the clipboard is empty or not valid.
This is my code:
Worksheets("Exec Sum").Range("B140:I186").Copy
With myDoc.Bookmarks
.Item("b3").Range.PasteSpecial Link:=True, DataType:=wdPasteMetafilePicture, Placement:=bmark, DisplayAsIcon:=False
End With
' Clears Clipboard
Application.CutCopyMode = False
I've tried sendkeys ("^C") with selecting an empty cell first but no luck. Is there any way that I could either not use the copy/paste method to do this or a different way to clear the clipboard?
I started getting this error when I upgraded from 2003 to 2010, but the macro still worked in 2003.
The tables were there, but I noticed that sometimes the copying didn't work. As this didn't ever happen in debug mode, I added 5 secs waiting time right before the copying.
This makes the macro slower, but at least it works.
I'm still testing my solution but it's different than the suggestions made and so far has worked flawlessly. Just a different approach:
I add a label and surround my attempt to copy with an error handler...
Pg1CopyAttempt:
DoEvents
shSomeSheet.Range("A1:G30").Copy
On Error GoTo Pg1PasteFail
WordApp.Selection.PasteExcelTable False, False, False
On Error goto 0 'disable the error handler
I call the label "Pg1CopyAttempt" because I know that Excel, through no fault of my own, may fail to copy it to the clipboard. If Excel does let me down, I won't know until I try to paste. When I do try I get thrown to the error Handler (Pg1PasteFail) when the paste method fails. This sits at the bottom of my routine (after a straight exit sub or an exit routine).
Pg1PasteFail:
If Err.Number = 4605 Then ' clipboard is empty or not valid.
DoEvents
Resume Pg1CopyAttempt
End If
It would be better to test for an empty clipboard programatically than to rely on an error handler but the idea here is to force a loop so that it keeps trying to copy until it succeeds. The simpler loop with programatic testing of the clipboard could exploit Sean's ClipboardEmpty Function (above). DoEvents is still exploited but even with DoEvents the routines can fail and are just instructed to keep trying.
This is the code I use:
Private Declare Function apiOpenClipboard Lib "user32" Alias "OpenClipboard" (ByVal hWnd As Long) As Long
Private Declare Function apiEmptyClipboard Lib "user32" Alias "EmptyClipboard" () As Long
Private Declare Function apiCloseClipboard Lib "user32" Alias "CloseClipboard" () As Long
Private Declare Function CountClipboardFormats Lib "user32" () As Long
Function ClipboardEmpty() As Boolean
ClipboardEmpty = (CountClipboardFormats() = 0)
End Function
Sub EmptyClipboard()
If apiOpenClipboard(0&) <> 0 Then
Call apiEmptyClipboard
Call apiCloseClipboard
End If
End Sub
the function ClipboardEmpty is a test. e.g. if clipboardempty then
The sub EmptyClipboard will simply clear the clipboard
I haven't confirmed this as a final solution, but the hang up seems to be when copying - The copied data never makes it onto the clipboard, so the code fails when attempting to paste. Clearing the clipboard of any previously copied data before initiating the next copy command seemed to help. I still am using the wait time shown above, but I seem to be able to get away with a shorter wait time using the following function to clear the clipboard:
Application.CutCopyMode = False

VBA program stops to refresh the worksheet

I'm making my own Conway's Game of Life on VBA where the current state is displayed on a worksheet.
Because I'm not skilled, the implementation is probably not very efficient (I use 2 boolean matrices to model the current state and the next one).
To display the result at each step, I've sub display() that took the matrix_currentand color each cell in black or white. To make the whole process smoother, I've wrapped Application.ScreenUpdating = Falseand Application.ScreenUpdating = True . Short story long, it looks like that :
Private Sub display()
Application.ScreenUpdating = False
For i = 0 To sizeGrid
For j = 0 To sizeGrid
If matrix_curr(i, j) Then
Cells(i + xmin, j + ymin).Interior.ColorIndex = 1
Else
Cells(i + xmin, j + ymin).Interior.ColorIndex = 2
End If
Next
Next
Application.ScreenUpdating = True
End Sub
Before each Call display() I call the method Sleep() to let enought time to watch each step.
So, here is my issue:
The display on the worksheet often stops after a number of steps. However, the programm is still running and finally shows the last state. So basically, I can monitor the beginning, then nothing change until the last step that are displayed.
Everything happen as if the worksheet suddenly stop to be refreshed.
Do you have any idea to solve this issue.
I thank you in advance for your help (and hope that I make myself understood
despite my poor english)
My problem is that after a number of steps, nothing more happen on the screen (as if it was freeze).
That's because Excel is essentially running out of breath - it's basically not keeping up with all the ScreenUpdating toggles.
When you toggle Application.ScreenUpdating back on once, Excel happily responds by repainting itself.
When you're running a busy loop, it's prioritizing execution of the VBA code and the Excel UI goes:
(not responding)
This is normal: there's a lot of things to process, so it's processing them - updating the UI, raising worksheet events, responding to user actions, calculating cells, all these things "drop priority", until the VBA code completes.
Try adding a DoEvents instruction immediately after toggling Application.ScreenUpdating back on; this explicitly tells Excel "okay, go ahead, process whatever other stuff you've got, then come back here when you're ready". I'd warmly recommend leaving Application.EnableEvents off and Application.Calculation set to xlCalculationManual until the code completely executed.

Excel running slowly when Excel the active window

I couldn't find the answer to this issue anywhere, so I do hope you guys can help me. My excel macro goes through a couple iterations of data. It autofilters a source file, takes out information, works with the data, and does so again for about 50 times - once per person. Here's some code of what I mean, all the individual submethods work just fine and are pretty damn fast:
For j = 1 To names.Count
'filter the source by name, generate sheet
FilterName names(j)
'prepare data with the necessary dates
FillMasterDates dates(), j
Dim i As Long
Dim ending As Long
ending = Sheets("Daten").Rows.End(xlDown).Row
Dim cellvalue As String
'check dates, etc
For i = 1 To ending
cellvalue = Sheets("Daten").Cells(i, 1)
If cellvalue = "" Then
Exit For
End If
ColorCell (i)
FilterDate CStr(dates(i)), names(j)
Next i
'user data has been successfully gathered, copy over to final sheet
FillColumns j
Next j
The whole code takes about 4~ seconds to run (given that I have about 2000 rows and I create a new sheet for 50~ people), which is fine. The baffling thing is that when Excel stays my active window despite using Application.ScreenUpdating = False (earlier in the macro, but still active at this point), the necessary time to run the macro goes up to a staggering 25~ seconds. Same input, same output. So to put it simply - run macro, tab out of excel - macro needs about 4-5 seconds to run. run macro but stay in excel and wait - 25 seconds.
I've tried Application.WindowState = Application.WindowState, ActiveWindow.SmallScroll, DoEvents, Application.CalculateFull(). I tried different calculation settings, but I do not really use any of the formula calculations innate to Excel - I have to use Excel as an interface because the source file is an *.xls file and the final output has to remain in this format.
If you need me to provide more code snippets to make sense of it, ask away. I've been stumped for a good two days now.
You could always try a couple more lines to disable the calculations and alerts etc.
Application.ScreenUpdating = false
Application.Calculations = xlManual
Application.DisplayAlerts = False
However if you really want to bypass all the background nonsense excel seems to go through dont access the sheet directly through a loop, this concept maybe tricky if your not used to it but its worth every bit, and will speed up your code so fast you will wonder why you never did it in the first place.
I dont have your code so ill just give an example of how it works
Dim RangeArray as Variant 'This will store your range as a values array
RangeArray = Sheet1.Range("A1:G100000").Value 'this will put the entire ranges values into the array
If Not IsArray(RangeArray) Then ExitSub 'If your range is only 1 cell it will not create an array so be careful, handle this as needed
'This Array always starts lowerbound 1, RangeArray(1,1) = First Cell
Now with this you can loop through your data and manipulate and modify the array just like you would with a cell or a range except there is no overhead, its just values and not objects .
Once you have done what you need all you need to do then is put the values back into the sheets range
Sheet1.Range("A1:G100000").value = RangeArray
And thats it, very simple and very effective, and this transfer from array to range is immediate no matter how big it is.
Just let me know if this helps
Thanks
Paul S
---------------NEW MESSAGE-------------------
You could try something which maybe a little excessive and risky, if your only getting this problem while the window is active and displayed how about making it invisible, the problem is if your code fails and you fail to trap an error it will remain invisible until you goto taskmanager and close it there.
Application.Visible = false
This should deactivate the window too (although i have never tested that)
this should simulate you hiding the window and just bring it back when your code has finished..
---------------NEW MESSAGE-------------------
Application.Windowstate = xlMinimized
This should do the trick :D, should have mentioned this first haha
I also just saw that you tried something similar, but the code is incorrect there, try this one

VBA While Loop freezing data uplink, need to run Sub once a second

I'm needing to run a sub once a second while also receiving data from a feed. The function looks at the data in the cells, determines if conditions are right, and if so sends a command to the trade server (where my data feed is coming in). This issue is once I run the loop, the While Loop freezes my cells in excel, making the program execute without updating.
Dim timeremaining As Integer
timeremaining = Range("E7").Value
Application.Calculation = xlCalculationAutomatic
Do While timeremaining > 5
Endowment
Sleep 1000
Loop
I've tried the setting a timer (OnTime) approach, and creating a function to run it a set number of times, yet both functions freeze my data feed.
Thank you.
Try using the wait method in VBA
For example:
Application.Wait(Now + TimeValue("0:00:10"))

Error with copy/paste in excel 2010 VBA when trying to insert charts, ranges etc into word

In researching this error I've come to the conclusion that it has to do with the clipboard not clearing like it should which wasn't an issue when we were using 2003 but is now that we are using 2010. (I also inherited this code from someone who doesn't work here anymore)
Run-Time error "4605":
This method or property is not available because the clipboard is empty or not valid.
This is my code:
Worksheets("Exec Sum").Range("B140:I186").Copy
With myDoc.Bookmarks
.Item("b3").Range.PasteSpecial Link:=True, DataType:=wdPasteMetafilePicture, Placement:=bmark, DisplayAsIcon:=False
End With
' Clears Clipboard
Application.CutCopyMode = False
I've tried sendkeys ("^C") with selecting an empty cell first but no luck. Is there any way that I could either not use the copy/paste method to do this or a different way to clear the clipboard?
I started getting this error when I upgraded from 2003 to 2010, but the macro still worked in 2003.
The tables were there, but I noticed that sometimes the copying didn't work. As this didn't ever happen in debug mode, I added 5 secs waiting time right before the copying.
This makes the macro slower, but at least it works.
I'm still testing my solution but it's different than the suggestions made and so far has worked flawlessly. Just a different approach:
I add a label and surround my attempt to copy with an error handler...
Pg1CopyAttempt:
DoEvents
shSomeSheet.Range("A1:G30").Copy
On Error GoTo Pg1PasteFail
WordApp.Selection.PasteExcelTable False, False, False
On Error goto 0 'disable the error handler
I call the label "Pg1CopyAttempt" because I know that Excel, through no fault of my own, may fail to copy it to the clipboard. If Excel does let me down, I won't know until I try to paste. When I do try I get thrown to the error Handler (Pg1PasteFail) when the paste method fails. This sits at the bottom of my routine (after a straight exit sub or an exit routine).
Pg1PasteFail:
If Err.Number = 4605 Then ' clipboard is empty or not valid.
DoEvents
Resume Pg1CopyAttempt
End If
It would be better to test for an empty clipboard programatically than to rely on an error handler but the idea here is to force a loop so that it keeps trying to copy until it succeeds. The simpler loop with programatic testing of the clipboard could exploit Sean's ClipboardEmpty Function (above). DoEvents is still exploited but even with DoEvents the routines can fail and are just instructed to keep trying.
This is the code I use:
Private Declare Function apiOpenClipboard Lib "user32" Alias "OpenClipboard" (ByVal hWnd As Long) As Long
Private Declare Function apiEmptyClipboard Lib "user32" Alias "EmptyClipboard" () As Long
Private Declare Function apiCloseClipboard Lib "user32" Alias "CloseClipboard" () As Long
Private Declare Function CountClipboardFormats Lib "user32" () As Long
Function ClipboardEmpty() As Boolean
ClipboardEmpty = (CountClipboardFormats() = 0)
End Function
Sub EmptyClipboard()
If apiOpenClipboard(0&) <> 0 Then
Call apiEmptyClipboard
Call apiCloseClipboard
End If
End Sub
the function ClipboardEmpty is a test. e.g. if clipboardempty then
The sub EmptyClipboard will simply clear the clipboard
I haven't confirmed this as a final solution, but the hang up seems to be when copying - The copied data never makes it onto the clipboard, so the code fails when attempting to paste. Clearing the clipboard of any previously copied data before initiating the next copy command seemed to help. I still am using the wait time shown above, but I seem to be able to get away with a shorter wait time using the following function to clear the clipboard:
Application.CutCopyMode = False