Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

pcANYWHERE OLE code for VB 19

Status
Not open for further replies.

fwadmin

IS-IT--Management
Jun 23, 2005
6
0
0
US
I have a bunch of pcANYWHERE script files written to do various automatic transfers. It seems that Symantec's newer versions of pcANYWHERE no longer support the script files and now use OLE for integration into other applications. The documentation for this completely stinks in that they give no VB examples of invoking transfers.

Anyone out there have any VB code with pcAYNWHERE they can share?

Thanks.
 
Hi RoverBone,

Unfortunately the interface does not expose a Show function - I think they intended this method of connecting to be used only for automated tasks and not for launching an interactive session, a big oversight in my opinion!

Anyway, it is possible with a few api calls, I'm using .NET, but it's not hard to change it back to VB6...

I've included here the API declarations I use and my ShowWindow function, that should get you started - I use a timer in my complete solution, to track the state of the ConnectionStatus property, so I can detect dropped connections etc and act accordingly.

'**** API Declarations
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
Private Declare Function ShowWindow Lib "user32.dll" (ByVal hwnd As Integer, ByVal nCmdShow As Integer) As Integer
Private Const SW_SHOWMAXIMIZED As Integer = 3

'**** Show Window Function
Private Function Pcaw_ShowWindow() As Boolean
Dim tempHwnd As Integer ' Temp handle to any window
Dim buffer As String ' Holds caption of Window
Dim numChars As Short ' Count of bytes returned

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

Application.DoEvents()

' Loop through all current window handles
Do Until tempHwnd = 0
' Check the title caption of the window
If tempHwnd <> 0 Then
' Initialise buffer
buffer = Space(128)
' Get caption of window
numChars = GetWindowText(tempHwnd, buffer, Len(buffer))
If numChars <> 0 Then
If buffer.Trim.ToLower.IndexOf(" - pcanywhere") > -1 Then
Application.DoEvents()

lblMsg.Text = ShowWindow(tempHwnd, SW_SHOWMAXIMIZED).ToString
Pcaw_ShowWindow = True
Exit Function
End If
End If
End If

' Get the next window handle (parameter 2)
tempHwnd = GetWindow(tempHwnd, 2)
Loop
Pcaw_ShowWindow = False

lblMsg.Text = "Show Window Failed!"
Application.DoEvents()
End Function

Hope this helps, Dave.
 
Thanks Dave, very helpful - have a star.
I've converted it to VB6 and now able to get an interactive remote session (of sorts). The only time the connection dropped on me was after a file transfer. Also I couldn't close it by clicking the normal 'End Session' menu icon.
Basically what I think is that the connection is made in 'File Transfer Mode' hence not showing the screen. There doesn't seem to be a property to set this true/false - It seems a huge oversight by Symantec.
So I've resorted to creating a remote object with the required settings as shown before but to make the remote connection I'm calling awrem32.exe passing the name of the .chf file via the shell object and monitoring the process ID returned. This gives full remote session capabilities.
 
I had done a lot of hunting prior to posting this message and before I start I want to thank everyone who contributed to this thread over the past couple of YEARS.

For this reason, I want to do my part by sharing what Ive learned in addition to asking my question. For those who feel they know enough of PCA & OLE, please continue to the bottom of those post where you will see --------- MY QUESTION ----------


If you are reading this thread in order to answer your own PCA questions, refer to what ive learned in "For Beginners"


------------------- FOR BEGINNERS ---------------------------

I have built PCA file-xfer routines into a project that is already utilizing a "push" method whereby 100+ locations transfer data to my central server using FTP.

In the cases where that method is unsuccessful, my new backup PCA "pull" method is automating the task a tech-support guy would have to endure manually; signing into each of the computers that did not transmit their data through PC Anywhere, transferring files, etc etc..

In a way to help others who have stumbled across this thread and now want to start building their own PCA app, let me summarize my experience over the past 8 hours with this --- If anybody wants to correct what I have come to understand as "the way it is" for some of these statements, please do so...



1) There are 3 objects to be used within VB to modify/execute PCA. The WINAWSVR.REMOTEDATAMANAGER and AWREM32.APPLICATION and WINAWSVR.HOSTDATAMANAGER.

While one or more of the projects and quotes from this forum point out the 2 PC Anywhere References (AWXFERUI & something else) - it appears they are completely irrelevant to your VB6 project.

This means you don't need to have them checked as References and that you must use late binding for your PCA Objects.

yourPCAOBJECT = CreateObject( data manager or file xfer control )

2) The RemoteDataManager object allows you to view or modify characteristics of a PCA .CHF file.

FYI - By setting a auto login username or auto password, you are thereby ENABLING Auto-Login for that site.

There are extreme limitations with the Remote Data Object, or somebody is holding secrets.

IE - Cannot alter the TCP/IP URL or IP Address, but you can modify a phone number?

Unless all of your sites are dial-up, this ends up being a pain-in-the-ass. It would be nice to dynamically generate connections for which the IP address can be modified.


3) Functions or Subroutines to be executed with both objects typically require the full .CHF file path so store this information somewhere.



4) The AWREM32 object is the nearly the same as right-clicking on a connection in the PC Anywhere window and selecting FILE XFER, except that you do not get the GUI.


5) The AWREM32 object takes a while to do its thing. A window will pop up momentarily once you've initiated the connection with

returnSUCCESS = pcaOBJECT.awconnect (chf file)

An annoying characteristic is the fact that your application won't be able to do much of anything while PCA fires up its connection. The window disappears and you will eventually receive a TRUE/FALSE in "returnSUCCESS"

As others have pointed out, you cannot continue on at this point as if everything is groovy--- if you do then you will end up with a DLL chewing away 100% of your CPU as you stack too many commands onto the pcaOBJECT.

My solution - which turns out to be close to the solution of others in this forum (i wish i had read them first) - was to include a timer and initiate a "watch" on the pcaOBJECT.ConnectionStatus property.

Timer code - interval 500 milliseconds// increments integer variable "duration" each time a consistent "Connected" or "Failed" result is received from pcaxfer object.

Private sub Timer1_Timer()
If watchPCA = False Then Exit Sub

' do nothing unless WATCH is issued (watch issued by 'firing a PCA connection via awconnect)

dim a$

a$ = Label1(1).Caption
On Error GoTo errorcatch:

DoEvents
If pcaXFER.connectionstatus = 1 Then Label1(1).Caption = "PCA Connected" Else Label1(1).Caption = "Connection Failed"
If a$ = Label1(1).Caption Then duration = duration + 1
DoEvents
errorcatch:
End Sub



So firing the connection looks like this..

watchPCA = True: duration = 0 'turning watch on and setting duration integer to 0
Label1(0) = userN 'the username

Label1(1).Caption = "Trying to Connect"
success = pcaXFER.awconnect(currPCA.chf) 'currpca.chf is the string filepath of this user's pcanywhere connection

Do Until duration > 10 ' this will wait 5 seconds for pca to decide if it is online or offline
DoEvents
Loop


If pcaXFER.connectionstatus < 1 Then GoTo errorcatch ')


--------------------------------

At this point it is safe to start transferring files.


By forcing PC Anywhere to provide a CONSISTENT FAILED or CONNECTED response before progressing with your code ensures you wont get caught up in the problems of issuing commands when PCA isnt ready, etc etc



6) The AWREM32 object for VB is not documented very well and, like the other objects, is lacking in big ways. The documentation in this thread is so much more helpful than the PCA documentation. So we should continue helping each other as web searches for this sort of thing dont produce too many results.

Example..

Page 57 of the PCA OLE PDF file gives a supposed example of creating "a Remote object, set connection for TCP/IP, computer name "Host1," and then launch it. The code shows how instantiate the Remote Data Manager object, assign a Remote Data Object equal to of its CHF files, and how to change a few basic properties. You never see code to launch it - it cant be done with this object. What they also dont point out in this example is that while you can set the COnnection Type for TCP/IP, you cant designate an IP address. Running the CHF file associated with this code would bring up a window where the local network is browsed for listening hosts.




-----------------------------------------------------------MY QUESTION---------------------------------




The end result of this post ends up being my question.. What I have is working great - Im learning not to expect much - but I have a need to transfer files with wildcards.

The instructions specify that you can use wildcards when doing transfers, but I cannot seem to make it work.



FOR EXAMPLE...

These do not work:

success = pcaxfer("f:\test\files*.html","f:\test\files*.html"

- success returns false



success = pcaxfer("f:\test\files*.html","f:\test\files.html"

- success returns TRUE, but this ends up saving a FOLDER in test called "files.html" I wish I was joking!!


success = pcaxfer("f:\test\files*.html","f:\test"

-success returns true, but nothing is saved


success = pcaxfer("f:\test\files*.html","f:\test\"

- success returns false

 
In case someone wants to point out what is obviously wrong with my examples, please know I simply forgot to include the function name for file xfer as well as an end-parentheses ")" ..

success=pcaxfer.filexferfromhost(sourcefile, destfile)

success=boolean/ pcaxfer=awrem32 object, filexferfromhost = PCA command to transfer file

In my post above I copied and pasted the sourcefile, destfiles but did not add the other details.. oops



So can anyone tell me how to make it work? If I specify the filenames precisely everything works fine - its just wildcards that cause a wrench.
 
omg i FINALLY found it



When using WILDCARDS -

Do not specify the extension

? pcaXFER.filexferfromhost("c:\files\files*.xls","c:\mypc\*.*)

Will not work...

HOWEVER...

? pcaXFER.filexferfromhost("c:\files\files*.*","c:\mypc\*.*)

DOES work!

Sigh

2 hours later.. what a pain in the #!!@@#^!@ !!

 
First off, Thank you all who contributed to this thread. It has helped me immensely. Thanks to this thread I now have a somewhat working VB app that will go through a database of clients, call each one, and tranfer a set of files.
My problem and question are with the FileXferFromHost . I need to be able to detect when the filxfr is finished, and if it doesn't finish then kill it and retry. Sometimes during the file transfer it will hang halfway through. It seems to not return control to my VB app until it finishes, so when it hangs my app just stops. When this happens I need to kill the file transfer and start it again. I already have the code to retry two times if the transfer is unsuccessful, but this is not executed when the transfer hangs because PCanywhere file transfer is stealing the control from my app to continue. Here's a snipet of the code:

Code:
bCheckTrnsfr = remote.FileXferFromHost(sHostFile, sRemoteFile)
    If bCheckTrnsfr = True And fso.FileExists(sRemoteFile) Then
        Print #1, "File transferred from host " & sHostID 
    Else
        If iRetryXfr < 2 Then
          iRetryXfr = iRetryXfr + 1
          GoTo UTransfer:
        End If
    End If

When the filetransfer doesn't hang the app works great, but I need it to recover from problems and move on. Thank you all!


 
I have found a solution to my previous post that I think will help some of you having the same problems. What I have done is launch a function in a separate thread that does nothing but monitor PCanywhere's status. I reference Threading.dll in my project and am able to create a simple function that loops throughout the life of the program while the main program goes on and does it's thing. Before each file transfer I flag a timer. The function running in a separate thread will react if the file transfer has taken too long by disconnecting PCAnywhere, killing the transfer. My main program sees that the connection is lost and reconnects to the host that it was on while it locked up and reattempts file transfer.

I found the threading DLL here:


These should be general declarations:
Code:
Dim t As Thread
Dim lStartTime As Long
Dim remote As Object

When the form loads it runs this code:
Code:
'**********************************************************************************
'Start Thread to check status of File Transfers.
'Multi Threading does not work in VB IDE.
'Compile to EXE for StatusCheck Thread to work
'or remark this section to run in VB IDE.
'Note that locked file transfers will not be detected if this is remarked.
'**********************************************************************************

    lStartTime = 0
    Set t = New Thread
    t.StartThread "CheckStatus", "none", Me

The CheckStatus Function looks like this
Code:
'**********************************************************************************
'CheckStatus is run in a separate thread. It monitors the time elapsed since each
'file transfer started and will kill PCanywhere if a file transfer locks up or
'does not complete within 30 seconds
'**********************************************************************************
Sub CheckStatus(dummy As Variant)
  
  Do
    If Timer > lStartTime + 30 And lStartTime <> 0 Then
        Set remote = CreateObject("Awrem32.Application")
        Call remote.awDisconnect
        Set remote = Nothing
        lStartTime = 0
    End If
  Loop
  
End Sub

Now before each file transfer set lStartTime = Timer and after the file transfer set lStartTime = 0. It should look like this:
Code:
lStartTime = Timer
bCheckTrnsfr = remote.FileXferFromHost(sHostFile, sRemoteFile)
lStartTime = 0

I also have code in the main program that check for a disconnection. You can handle this how you like. Mine looks like this:
Code:
'check to see if the connection was lost
'if it was, reconnect
    If remote.ConnectionStatus <> 1 Then
        iReconnect = iReconnect + 1
        Print #1, Format$(Now, "mm-dd hh:mm:ss") & " Lost connection. Attempting reconnect #" & iReconnect
        bWentOK = remote.awDisconnect()
        Set remote = Nothing
        GoTo Reconnect:
    End If
I check for a lost connection right before each file transfer.

Hope this helps someone!
 
Ok, Things get a little more complicated, but are still managable. I've found that the above code only works some of the time, but other times reinitializing the object and disconnecting doesn't kill the hung file transfer. Here are some additions that will forcefully end the file transfer. If anyone has a better solution please let me know.
First thing, these must be in General Declarations (in addition to anything already there):
Code:
' Used to find a windows handle
Private Const GW_HWNDFIRST = 0&
Private Const GW_HWNDLAST = 1&
Private Const GW_HWNDNEXT = 2&
Private Const GW_CHILD = 5&

Private Const GWL_EXSTYLE = -20&
Private Const GWL_HINSTANCE = -6&
Private Const GWL_HWNDPARENT = -8&
Private Const GWL_ID = -12&
Private Const GWL_STYLE = -16&
Private Const GWL_USERDATA = -21&
Private Const GWL_WNDPROC = -4&

' Used by OpenProcess function
Private Const PROCESS_ALL_ACCESS = &H1F0FFF

' API's used to get window info
Private Declare Function GetWindowText _
   Lib "user32" Alias "GetWindowTextA" _
   (ByVal hwnd As Long, ByVal lpString As String, _
    ByVal cch As Long) As Long
Private Declare Function GetWindow _
   Lib "user32" _
   (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function GetDesktopWindow _
   Lib "user32" () As Long
Private Declare Function DestroyWindow _
   Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function IsWindow _
   Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function OpenProcess _
   Lib "kernel32" _
   (ByVal dwDesiredAccess As Long, _
    ByVal bInheritHandle As Long, _
    ByVal dwProcessId As Long) As Long
Private Declare Function CloseHandle _
   Lib "kernel32" _
   (ByVal hObject As Long) As Long
Private Declare Function TerminateProcess _
   Lib "kernel32" _
   (ByVal hProcess As Long, _
    ByVal uExitCode As Long) As Long
Private Declare Function GetWindowThreadProcessId _
   Lib "user32" _
   (ByVal hwnd As Long, _
    lpdwProcessId As Long) As Long

Dim plngPID          As Long
   Dim plngRtn          As Long
   Dim plngWndHwnd      As Long
   Dim plngOpenProcHwnd As Long

I have added the KillProcess calls to the CheckStatus function that will forcefully kill the transfer. It should now look like this:
Code:
Sub CheckStatus(dummy As Variant)
  
  Do
    If Timer > lStartTime + 30 And lStartTime <> 0 Then
        Set remote = CreateObject("Awrem32.Application")
        Call remote.awDisconnect
        Set remote = Nothing
        KillProcess ("File Transfer Status") 'kills locked file transfer
        KillProcess ("Program Error") 'kill errors from AWREM32.EXE
        Pause (2)
        lStartTime = 0
    End If
  Loop
  
End Sub

Now we need to add a few functions to allow us to use KillProcess. Paste this code to allow you to use KillProcess from within CheckStatus (or wherever):
Code:
'*************************************************************
'Passed a partial or complete window title, forcefully kills it
'*************************************************************
Public Function KillProcess(PartialTitle As String)
   
   plngWndHwnd = GetWindowFromTitle(PartialTitle)
   plngRtn = GetWindowThreadProcessId(plngWndHwnd, plngPID)
   If plngPID > 0 Then
      plngOpenProcHwnd = OpenProcess(PROCESS_ALL_ACCESS, 0&, plngPID)
      
      If plngOpenProcHwnd <> 0 Then
         KillWindow plngWndHwnd, plngOpenProcHwnd
         plngRtn = CloseHandle(plngOpenProcHwnd)
      End If
   End If
   
End Function

'****************************************************
' Passed a partial or complete window title, return
'   the handle of the first title found matching
'   the passed string.
' NOTE: Case insensitive
'****************************************************
Public Function GetWindowFromTitle(xstrPartialTitle As String) As Long
   Dim pstrTitle        As String * 256
   Dim plngHwnd         As Long
   Dim plngRtn          As Long
   Dim pstrMatch        As String
   Dim pstrPassed       As String


   GetWindowFromTitle = 0
   
   'Make sure passed string is uppercase
   pstrPassed = UCase$(xstrPartialTitle)
   
   'The desktop is the highest window
   plngHwnd = GetDesktopWindow()
   
   'It's first child is the 1st top level window
   plngHwnd = GetWindow(plngHwnd, GW_CHILD)
   
   'Get the text of the window
   plngRtn = GetWindowText(plngHwnd, pstrTitle, Len(pstrTitle))
   On Error Resume Next
   If plngRtn = 0 Then
      pstrMatch = ""
   Else
      pstrMatch = UCase$(Mid$(pstrTitle, 1, plngRtn))
   End If

   'Check to see if first child contains the passed string
   If Len(pstrMatch) > 0 Then
      If InStr(pstrPassed, pstrMatch) > 0 Then
         GetWindowFromTitle = plngHwnd
         Exit Function
      End If
   End If
   On Error GoTo 0
   
   'Now check all the top level windows
   Do
      plngHwnd = GetWindow(plngHwnd, GW_HWNDNEXT)
   
      'Get the text of the window
      pstrTitle = ""
      plngRtn = GetWindowText(plngHwnd, pstrTitle, Len(pstrTitle))

      On Error Resume Next
      If plngRtn = 0 Then
         pstrMatch = ""
      Else
         pstrMatch = UCase$(Mid$(pstrTitle, 1, plngRtn))
      End If

      'Check to see if this window contains the passed string
      If Len(pstrMatch) > 0 Then
         If InStr(pstrMatch, pstrPassed) > 0 Then
            GetWindowFromTitle = plngHwnd
            Exit Function
         End If
      End If
      On Error GoTo 0

   Loop While plngHwnd <> 0

   GetWindowFromTitle = 0

End Function

'******************************************************
' Passed a Windows handle and a Process handle, kill it
'******************************************************
Public Sub KillWindow(xlngHwnd As Long, xlngProcessHwnd As Long)
   Dim plngRtn             As Long
   Dim plngProcessHwnd     As Long
   Dim plngThreadHwnd      As Long
   Dim plngExitCode        As Long
   
   plngExitCode = 0&
   
   If xlngHwnd <> 0 Then
      If IsWindow(xlngHwnd) <> 0 Then
         plngRtn = TerminateProcess _
                         (xlngProcessHwnd, _
                          plngExitCode)
         
         If plngRtn = 0 Then
            'MsgBox "Failed to destroy window: Error #" & _
                        Err.LastDllError & ", " & _
                        ReturnApiErrString(Err.LastDllError)
         Else
            'MsgBox "Destroyed window!"
         End If
      End If
   End If
   
End Sub

Now apply what I've said here to the code in the previous post to monitor from a separate thread and kill that damn PCA when need be.
Sorry for rambling on here with too much detail, but hope this helps some of you!
 
I am trying to transfer couple of files from one computer to another using PCAnywhere. I got version 8 of it. Please tell me which script shall I use and where this script file should be kept to be worked. Please send me the detail information about this.

Regards
Atif
 
Hi pggplc
I have an application where the remote pc has pcanywhere 8 which calls a dos host running pca 5. In pca 5 you can initiate a batch file according to the password, in the batch file I use AWSEND to transfer files between remote and host. For pca 10 on use OLE
 
AIRIK,

I tried your suggestion, but I recieve "Float-Point InExact" error when the code perform StartThread in Form Load.

Do you have any ideas???

I really need to resolve the transfer hangup problems.
I successfully transfer i site and fail on next with the hang up.

Should I be using 10.5 instead of 11.0???
 
ROVERBONE,

How exactly did you resolve the File Transfer hangups?

Thanks, appreciate your input...

 
Hi ZT1,
I wasn't doing any file transfers, I needed to gain an interactive remote control session but the API provided, connected in file transfer mode (although it didn't say that), so my problem was seeing the desktop screen that was hidden.
I haven't looked at the file transfer options, so sorry I can't help, but there is plenty of good information in this thread.
 
Marius and all,

Did you ever get a solution to the fact that executehostfile doesn't seem to work? Mine worked for years on Win98, but now is broken on my Win2K machine.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top