• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 277
  • Last Modified:

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

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
80083r
Asked:
80083r
  • 8
  • 6
1 Solution
 
JonyvCommented:
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
 
JonyvCommented:
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
 
80083rAuthor Commented:
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
Independent Software Vendors: 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!

 
80083rAuthor Commented:
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
 
80083rAuthor Commented:
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
 
80083rAuthor Commented:
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
 
JonyvCommented:
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
 
80083rAuthor Commented:
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
 
JonyvCommented:
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
 
JonyvCommented:
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
 
80083rAuthor Commented:
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
 
80083rAuthor Commented:
postmessage looks promising.

I'll give it a shot tonight when all the managers leave and I'm allowed to work :)
0
 
JonyvCommented:
>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
 
80083rAuthor Commented:
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

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!

  • 8
  • 6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now