4

I have written a macro in vba, which opens a text file with notepad, selects all txt and copies it to Excel. I have to process about 100 files daily in this way and I want to spare the flashing images that I observe. The code is working but the problem is that the command

Application.Screenupdating = False

Is not working with the notepad application. I can only use the normal focus, otherwise the code is not working. How can I execute the code below without observing that the notepad file is opened and processed?

My code is:

Sub GetTextFile()
Application.ScreenUpdating = False
Dim MyPath As String
Dim MyFile As String

MyPath = "C:\Users\bgyona02\Desktop\OLAttachments\"

MyFile = Dir(MyPath & "*.txt", vbNormal)    

Do While Len(MyFile) > 0
  MyFile = Dir
Loop

Debug.Print GetTextFileContent(" C:\Users\bgyona02\Desktop\OLAttachments\" & MyFile)
    'MyFile = Shell("C:\WINDOWS\notepad.exe` C:\Users\bgyona02\Desktop\OLAttachments\" & MyFile, vbNormalFocus)
    'SendKeys "^a", True  '^A selects everything already in the pdf file.
    'SendKeys "^c", True
    'SendKeys "%fx", True
End Sub

I could not find any working solution about this.

Community
  • 1
  • 1
Badan
  • 248
  • 1
  • 10
  • *When I do something totally foolish like misuse Notepad and the clipboard instead of doing things the right way, it causes problems. Can someone tell me how to kludge even more to hide those problems?* is known as an XY Problem. (You wouldn't need to solve X if you solved Y correctly in the first place.) The clipboard belongs to the user, and you don't need Notepad to open and read text from VBA. – Ken White Dec 10 '16 at 01:49

2 Answers2

3

There's a quick answer how to run Notepad but hide the window and that it is to use vbHide instead of vbNormalFocus in your Shell command:

Dim strCmd = "C:\WINDOWS\notepad.exe C:\Users\bgyona02\Desktop\OLAttachments\" & LatestFile
MyFile = Shell(strCmd, vbHide)

But I very much doubt that SendKeys would then work on an invisible window....

So, this is not an answer to the question but have you considered using the FileSystemObject and simply read the file without actually opening Notepad.exe ?

Option Explicit

Const FOR_READING = 1

Sub LoadTextFile()
    Dim varTxtContent As Variant
    Dim intLine As Integer

    'Debug.Print GetTextFileContent("D:\temp.txt")

    varTxtContent = Split(GetTextFileContent("D:\temp.txt"), vbCr, -1, vbBinaryCompare)
    For intLine = 0 To UBound(varTxtContent) - 1
        ThisWorkbook.Worksheets("Sheet1").Range("B" & intLine + 1).Value = varTxtContent(intLine)
    Next intLine


End Sub

Function GetTextFileContent(strPath As String) As String
    Dim strContent As String
    Dim objFso As Object
    Dim objFile As Object
    Dim objStream As Object

    strContent = ""
    On Error GoTo CleanUp:

    Set objFso = CreateObject("Scripting.FileSystemObject")
    Set objFile = objFso.GetFile(strPath)
    Set objStream = objFile.OpenAsTextStream(FOR_READING, 0)

    With objStream
        strContent = .ReadAll
        .Close
    End With

CleanUp:
    Set objStream = Nothing
    Set objFile = Nothing
    Set objFso = Nothing
    GetTextFileContent = strContent

End Function

The code will work with accented characters e.g. my test text file is:

â, î or ô
foo
bar foo
baz bar foo

As far as I know, Application.ScreenUpdating will only apply to your Excel session and not other programs running in Windows. So, to actually stop those windows appearing - but still be able to read the content of the window - you would have to do something reasonably complex with the Windows API. Using FileSystemObject is a lot, lot simpler.

HTH.

Robin Mackenzie
  • 18,801
  • 7
  • 38
  • 56
  • 1
    Hi Robin, thank you for your answer. I tried opening the text file from excel but I have a problem with the accented characters. When I open the text file through notepad all the characters are correctly displayed. That is why I am looking for a solution with txt editor – Badan Dec 09 '16 at 11:09
  • Can you give an example of the type of text you are working with? – Robin Mackenzie Dec 09 '16 at 11:15
  • I suppose the Debug.Print function should copy the text file content?. I tried to add your function to my code but nothing happens. Please check, I included the full code in my question. Thank you in advance! – Badan Dec 09 '16 at 13:02
  • Please add some sample text to your question. Is the text in your file of European origin? Or Russian, Arabic, or Chinese? – Robin Mackenzie Dec 09 '16 at 13:23
  • Yes, they can be in French, so i have problems with the "é" characters but sometimes i also have content with â, î or ô and they are not correctly dispayed in Excel – Badan Dec 09 '16 at 13:27
  • So in your updated code - can you just try a *simple* example where you hard-code the name of the file you want to test. You should remove the code that tests for \ in the path and also the test for the latest file. We want a minimum and complete example. – Robin Mackenzie Dec 09 '16 at 13:31
  • 1
    Can you invoke an un-hidden notepad and size it to be 1x1 pixels (or something small enough to be inconspicuous? – B540Glenn Dec 09 '16 at 13:49
  • Robin, I simplified the code now. I am not very familiar with the debug print function, though. How can i use an alternative to the send keys, so i can copy and paste the data? – Badan Dec 09 '16 at 13:51
  • B540Glenn, this can be done with Excel but I am not sure whether this can be implemented in Notepad? – Badan Dec 09 '16 at 15:07
  • I removed use of `Debug.Print` (which you can check in the Immediate Window in the VB Editor) and replaced it with code that outputs to `Sheet1` of your workbook - so it should be clear if it is working for you or not. – Robin Mackenzie Dec 10 '16 at 01:44
  • Thank you Robin. Unfortunately I was not able to get this work for me. However, I used the alternative approach suggested by B540Gleen. B540Glenn, thank you so much for this idea that you gave me to look for a way to make the screen one pixel. The topic is now resolved. Thank you all for the collaboration. – Badan Dec 12 '16 at 08:41
0

I finally found a very elegant solution that can handle external applications. All the credit should go for Robert Schutt for writing this masterpiece code. This makes the notepad window 1 pixel, so no flashing images are observed. It looks rather complicated for me but it saved my day:

Option Explicit

Private Declare Function MoveWindow Lib "user32" (ByVal hwnd As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal bRepaint As Long) As Long

Public Const GW_HWNDNEXT As Long = 2
Public Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
Public Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwprocessid As Long) As Long

Function ProcIDFromWnd(ByVal hwnd As Long) As Long
   Dim idProc As Long

   ' Get PID for this HWnd
   GetWindowThreadProcessId hwnd, idProc
   ProcIDFromWnd = idProc
End Function

Function GetWinHandle(hInstance As Long) As Long
   Dim tempHwnd As Long

   ' Grab the first window handle that Windows finds:
   tempHwnd = FindWindow(vbNullString, vbNullString)

   ' Loop until you find a match or there are no more window handles:
   Do Until tempHwnd = 0
      ' Check if no parent for this window
      If GetParent(tempHwnd) = 0 Then
         ' Check for PID match
         If hInstance = ProcIDFromWnd(tempHwnd) Then
            ' Return found handle
            GetWinHandle = tempHwnd
            ' Exit search loop
            Exit Do
         End If
      End If

      ' Get the next window handle
      tempHwnd = GetWindow(tempHwnd, GW_HWNDNEXT)
   Loop
End Function

Sub MinimizeNotepad()
    Dim retval As Long, np_retval As Long
    np_retval = Shell("C:\notepad.exe", vbNormalFocus)
    retval = MoveWindow(GetWinHandle(np_retval), 1, 1, 1, 1, 1) ' Application.hwnd
End Sub
Badan
  • 248
  • 1
  • 10