Another reason it may be hanging is because VB6 is waiting for the database. Are the queries you're running on the database long-running, or is it the VB6 code that's taking a long time?
If the database queries cause the problem and you're using ADO, you can use an asynchronous database connection. The logic can be more complex to code then, because you have to set up callback methods to continue the processing after each database call has finished.
You can establish such a connection doing something like this:
Private WithEvents m_conn As ADODB.Connection
...
Set m_conn = New ADODB.Connection
Call m_conn.Open(connectionString, , , adAsyncConnect)
Execute a query / stored procedure like this - the main difference you'll notice here is that instead of hanging until the query completes, code execution continues as normal):
sql = "SELECT Col1 FROM etc. etc."
Call m_conn.Execute(sql, , adAsyncExecute)
Cancel a running query like this:
Call m_conn.cancel
And the all important callback for when the query completes:
Private Sub m_conn_ExecuteComplete(ByVal RecordsAffected As Long, ByVal pError As ADODB.Error, adStatus As ADODB.EventStatusEnum, ByVal pCommand As ADODB.Command, ByVal pRecordset As ADODB.Recordset, ByVal pConnection As ADODB.Connection)
... do more processing etc...
End Sub
You may find that the above is overkill for what you want; I only implemented that myself because the window was specifically designed to do long-running queries, and it was quite important that the window remain responsive, and allow queries to be cancelled partway through.
As far as I know, however, if you don't use the asynchronous query method, VB6 will remain unresponsive until your m_conn.Execute
method returns.
If the delay is occurring because of the VB6 code itself - for example in all the work you're doing creating temporary tables, then I'd agree with MarkJ's "classic" answer and use DoEvents - though seemingly a clumsy mechanism, it does work pretty well. Sprinkle a few of those throughout your procedure and you should notice some improvement. Though perhaps not perfection, it may be good enough.
e.g.
retrieve results
...
DoEvents
...
build temporary tables
...
DoEvents
Each time one of the DoEvents blocks is hit, if the user clicked the Cancel button that code should fire.
Note: You may also want to be a little bit wary about unloading a form while code is still running, I'm not convinced everything will unload properly. In that case you might want to have something like:
Private m_cancel as Boolean
Private Sub cmdCancel_Click()
m_cancel = True
End Sub
Private Sub cmdProcess_Click()
...
retrieve results
...
DoEvents
If Not m_cancel Then
... build temporary tables etc...
End if
If m_cancel Then Unload Me
End Sub