?
Solved

Window caption and instance handle - A follow up to Q_20555955.html (link inside question)

Posted on 2003-03-25
14
Medium Priority
?
268 Views
Last Modified: 2010-05-01
follow up to
http://www.experts-exchange.com/Programming/Programming_Languages/Visual_Basic/Q_20555955.html


Hi,

not sure if that link is going to work.

Ok, here is the situation:

I have a vbApp called Dps_nbd (if you know what that is, you are in the same building, just come over and talk to me :) )  It is used to hold a dde conversation with a 16-bit app called outside.exe.  That part works great.

The problem is, it is not conversing with the correct instance of outside.exe.  The dde link needs to be instituted like this:  

link.execute "ovw|macro"

which works fine, it communicates, but the documentation of outside.exe (outside view) says you can initiate a conversation with a specific instance of ovw if you include the "instance handle"

ie:

link.execute "ovw<instance handle>|macro"

--"macro" is required

the problem is, the instance handle is not the handle that is passed from the shell command

'*** begin code ***

new_handle = Shell(outside_path, vbNormalNoFocus)

link.execute "ovw" & new_handle & "|macro"
'alternate link.execute "ovw" & str(new_handle) & "|macro"

'*** end code ***
'*** no communication, it sits and spins forever ***

I have also tried hard coding -link.execute "ovw0|macro" and "ovw1|macro" when I knew only one instance of the program was running, thinking it may enumerate the windows that way, but no soap.

The actual example from the documentation is a dde conversation with excel, as follows:

<quote>

To use Outside View as a server, connect to OVW (or OVW with the instance handle appended if you are running more than one copy of Outside View). Open the connection with the topic MACRO.
An example of the Excel call noted above is:

OV1 = EXEC("outside.exe async",2)
channel = INITIATE("OVW"&OV1,"MACRO")

</quote>

so, the questions are:

Does the shell command return the same file handle as enumerating the process using api's would?
Does anyone have a clue what instance handle described above is?
How do I get said instance handle if I have the window caption?  (I dictate the window caption, so that is known)
Does anyone have a clue what I am asking?
Am I a fool?  (extra points for getting that one right <grin>)

thanks,

80083r
0
Comment
Question by:80083r
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 6
14 Comments
 
LVL 3

Accepted Solution

by:
Jonyv earned 560 total points
ID: 8208989
Hi

The Shell command returns what's called the Process ID, this can be used with various API functions, but it's not what you want.

If it's really the instance handle you need then there is a way to get hold of that, and yes in this case it DOES help to know the window caption.

First you need to get a handle to the application window using the FindWindow API (se code below), that handle can the be used with the GetWindowLong function to get the instance handle.
Another way migth be to use the outdated WinExec function instead of Shell, WinExec is in some places (not MSDN though) reported to return the instance handle. When i tried it with Notepad it returned the same value for every instance and it was a different value from waht you get with the previous method, but perhaps the behaviour is different for true 16-bit applications.

Anyway, try this code:

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Const GWL_HINSTANCE = (-6)

Dim hWnd as Long
Dim hInstance as Long

Shell(outside_path, vbNormalNoFocus)

hWnd = FindWindow(vbNullString, <WINDOW TITLE>)
hInstance = GetWindowLong(hWnd, GWL_HINSTANCE) ' hInstance is your instance handle


Alternate method using WinExec:

Private Declare Function WinExec Lib "kernel32" (ByVal lpCmdLine As String, ByVal nCmdShow As VbAppWinStyle) As Long

Dim hInstance as Long

hInstance = WinExec(outside_path, vbNormalFocus)


And NO, you're probably not a fool, unless you are doing this for free in your spare time, in which case you should be put in a straightjacket and locked up somewhere  ;-)
0
 
LVL 3

Expert Comment

by:Jonyv
ID: 8209016
Oh, just one note about WinExec. If the path to outside.exe contains spaces you must put "" around the path, otherwise it won't work...
0
 

Author Comment

by:80083r
ID: 8209893
Ok,

that sounds good.  I'm already using the findwindow() api to make sure the program is open - so that should be easy to test.

I'll give it a try tonight and see (points are yours if it even gets me close)

Not quite for free, and definitely during time I'm supposed to be working...

Thanks,

80083r
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:80083r
ID: 8216198
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Const GWL_HINSTANCE = (-6)

hInstance = GetWindowLong(GetWindowLong(hWnd, GWL_HINSTANCE), GWL_HINSTANCE) ' hInstance is your instance handle

just in case you want to nest like crazy :)

Worked like a charm!

Points are yours, Grade A stuff!
0
 

Author Comment

by:80083r
ID: 8216210
ummm... whups?  posted a following followup, but it never made it.

hInstance = GetWindowLong(FindWindow(vbNullString, <WINDOW TITLE>), GWL_HINSTANCE)

' hInstance is your instance handle
0
 

Author Comment

by:80083r
ID: 8216932
crap!

for some reason it does not return the proper instance handle for a 16-bit app under windows 2k.  I assume it is returning the instance of wowexec.

Anyone still reading this have any ideas?  I'm out of points :(

thanks!
0
 
LVL 3

Expert Comment

by:Jonyv
ID: 8217205
Damn, why does the simple solutions never work?...  :-)

Anyway: I really don't know anything about DDE, but a quick look in MSDN tells me that it seems to work through standard windows messages, if this is the case then you might still have a chance. You could try and do the DDE stuff manually with the SendMessage or PostMessage API, since you already know the windowhandle of the instance you want to communicate with you can make sure that the messages goes to the right window. Have a look at the WM_DDE_EXECUTE message in MSDN.

I will look at this some more and see if I can come up with something more concrete...

Good Luck!
0
 

Author Comment

by:80083r
ID: 8217732
How about enumerating running processes under wowexec and grabbing the hWnd from there? would that work...?  I was trying to avoid enumerating processes, just because the code is huge, but it's getting huge anyway, and if it would work, I guess I could give it a shot.

80083r  :(
0
 
LVL 3

Expert Comment

by:Jonyv
ID: 8217850
I don't think that would work. When you enumerating processes, the best you can get is a processhandle or processID, and the only way to get a window handle from a processID is to enumerate all windows and call GetWindowProcessID() for comparison and that would probably give you the same value as FindWindow()
0
 
LVL 3

Expert Comment

by:Jonyv
ID: 8218127
Ok, I have looked into this a bit more and I think it's defintively possible to to the DDE stuff by hand, but it won't be easy... Since the communication has to go both ways you would have to do some subclassing to get access to the response messages. It also involves some low level memory managment (which can be done in VB, but it's always a bit scary :-)  )

Tell me if you want me to look into this any more or if you would like to explore this in your own (or just give it up...)
0
 

Author Comment

by:80083r
ID: 8218366
I don't actually need to get responses from the 16-bit app.

the only thing i need dde for is to tell it to start a macro.

link.execute "get_nfo.ovx"

the macro creates a file called mcro_1.dat when it's done and vb sits and spins until that file is created.

If the macro call fails, that's fine.

as long as I know that the window i need is open, and I am sending info to the correct window, I'm happy.

and if it doesn't work... well, I'll just let it use the first instance it comes too.

Thanks for the effort.
0
 

Author Comment

by:80083r
ID: 8218413
postmessage looks promising.

I'll give it a shot tonight when all the managers leave and I'm allowed to work :)
0
 
LVL 3

Expert Comment

by:Jonyv
ID: 8220870
>I don't actually need to get responses from the 16-bit app.
Yes you do. At least if you want to be sure that your commands are really executed (I could be wrong, but I don't think so...)

From what I have read about DDE, the client (your app) should start by sending a WM_DDE_INITIATE message to the server, this message includes a handle to the window doing the communication. The server will then reply with a WM_DDE_ACK message that includes a handle to a window were all future messages should be sent, and this window doesn't have to be the main window (I guess it could be, but it doesn't have to).
So to be sure that your WM_DDE_EXECUTE message is really processed you need to get the correct windowhandle from the WM_DDE_ACK messages that the server sends back to you.
0
 

Author Comment

by:80083r
ID: 8222197
argh.   I'm going to stop writing responses in the morning after work.  Of course you are right.  I need to know the conversation is initiated, and where.  Well, I'm going in the right direction now, I think, I'll read up and see what I can find.  I'll do some tests tonight and see what I can see.

The problem is, the win2k box where the damn thing has to run, I do not have admin rights, so I can't install VB, so I have to program on a 98 box in the next cube, and then test the .exe.  Silly huh?
0

Featured Post

On Demand Webinar: Networking for the Cloud Era

Ready to improve network connectivity? Watch this webinar to learn how SD-WANs and a one-click instant connect tool can boost provisions, deployment, and management of your cloud connection.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

I’ve seen a number of people looking for examples of how to access web services from VB6.  I’ve been using a test harness I built in VB6 (using many resources I found online) that I use for small projects to work out how to communicate with web serv…
Background What I'm presenting in this article is the result of 2 conditions in my work area: We have a SQL Server production environment but no development or test environment; andWe have an MS Access front end using tables in SQL Server but we a…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
Suggested Courses
Course of the Month9 days, 19 hours left to enroll

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question