how to pass hwnd from VB6 code in VB.net library using Interop
I need to pass a window handle (long) from VB6 client to a library written in VB.Net for some processing (using interop). I don't know how to make use of the hwnd from VB6 and get the correct window handle in .Net.
Please help!
btw, Im on VS 2008 SP1 and .Net framework 3.5 SP1
Answers
- Hi Narsi,
We can fix this issue by PInvoke calling MessageBox in VB.NET component to implement same effect as VB6 API calling. The following is my modification to your code snippet. I tested it. It should satisfy your requirement.
Public Shadows Function MessageBoxU(ByVal OwnerHandle As Integer, ByVal Prompt As String, ByVal Title As String, ByVal buttons As Integer) As Integer
Try
Dim iPtr As IntPtr
iPtr = New IntPtr(OwnerHandle)
MessageBox.Show(OwnerHandle.ToString())
MessageBox.Show(iPtr.ToString)
'MessageBox.Show(New CWindowWrapper(iPtr), Prompt, Title, buttons)
NativeMethods.MessageBoxW(iPtr, Prompt, Title, buttons)
Catch
MsgBox(Err.Description)
End Try
End Function
Partial Public Class NativeMethods
'''Return Type: int
'''hWnd: HWND->HWND__*
'''lpText: LPCWSTR->WCHAR*
'''lpCaption: LPCWSTR->WCHAR*
'''uType: UINT->unsigned int
<System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint:="MessageBoxW")> _
Public Shared Function MessageBoxW(<System.Runtime.InteropServices.InAttribute()> ByVal hWnd As System.IntPtr, <System.Runtime.InteropServices.InAttribute(), System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)> ByVal lpText As String, <System.Runtime.InteropServices.InAttribute(), System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)> ByVal lpCaption As String, ByVal uType As UInteger) As Integer
End Function
End Class
Best regards,
Riquel
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.- Proposed As Answer byRiquel_DongModeratorFriday, November 06, 2009 5:59 AM
- Marked As Answer bynarsiCherukupalli Friday, November 06, 2009 2:23 PM
I should have checked for a unicode version of the API function call (MessageBoxIndirectW) which can be called directly from a VB 6.0 app.
http://www.vbforums.com/showthread.php?t=541220
Paul ~~~~ Microsoft MVP (Visual Basic)- Marked As Answer bynarsiCherukupalli Friday, November 06, 2009 2:23 PM
All Replies
- Maybe you could provide a little more detail as to what the .NET component needs to do with the hwnd. I don't see a problem with passing it from the VB 6.0 app to a .NET component function. Is it the interop process that you're not sure how to do?
Paul ~~~~ Microsoft MVP (Visual Basic) - Hi Paul
Thanks for the response. Here is what I am trying to do.
This is part of a project where we are adding Unicode support to a fairly complex VB6 application. We are doing Interop user controls to be used in VB6 forms. As part of this project we also have to wrap MessageBox function so that we can display unicode strings in the message box.
following are the two main objectives of the the Wrapper function for MessageBox
a) to handle Unicode Strings
b) take Window handle as parameter so that the message box can be set for a particular window.
now, when calling this function from VB6 I can pass the window handle of any form that I want to this function as Integer but don't know how to properly convert it to "Iwin32Window" type so that MessageBox function can understand it.
Thanks again. - See if the below link helps. It's written in C# but the example looks to be relatively simple and should be adaptable to Visual Basic:
http://ryanfarley.com/blog/archive/2004/03/23/465.aspx
Paul ~~~~ Microsoft MVP (Visual Basic) - Paul
I got this working by using a WrapperClass for IWin32Window. But I have a new problem now
When I pass the Window handle of an external window (not the VB6 Client from where I call this function) the message box displays modally on that window and my VB6 Form also stuck behind that same Message box.
I don't want it to be Modal to my VB6 Form when I pass a handle to another window.
Please help! I'm posting the code here so you can reproduce it very easily
VB.Net Imports System.Windows.Forms <ComClass(CTest.ClassId, CTest.InterfaceId, CTest.EventsId)> _ Public Class CTest #Region "COM GUIDs" ' These GUIDs provide the COM identity for this class ' and its COM interfaces. If you change them, existing ' clients will no longer be able to access the class. Public Const ClassId As String = "75bce494-cfa8-46fd-8f2e-550aee2ebd47" Public Const InterfaceId As String = "8c003cc9-e226-4f9e-87c4-54619a2b9482" Public Const EventsId As String = "bbbf2e72-74f9-4514-8970-5a73ec62d421" #End Region ' A creatable COM class must have a Public Sub New() ' with no parameters, otherwise, the class will not be ' registered in the COM registry and cannot be created ' via CreateObject. Public Sub New() MyBase.New() End Sub Public Shadows Function MessageBoxU(ByVal Prompt As String, Optional ByVal Title As String = "", Optional ByVal OwnerHandle As Integer = 0) As Integer Try Dim iPtr As IntPtr Dim oWindWrapper As CWindowWrapper If OwnerHandle > 0 Then iPtr = New IntPtr(OwnerHandle) oWindWrapper = New CWindowWrapper(iPtr) Return MessageBox.Show(oWindWrapper, Prompt, Title) Else Return MessageBox.Show(Prompt, Title) End If Catch End Try End Function End Class Imports System.Windows.Forms Class CWindowWrapper Implements IWin32Window Private _hwnd As IntPtr Public Sub New(ByVal handle As IntPtr) _hwnd = handle End Sub Public ReadOnly Property Handle() As IntPtr Implements IWin32Window.Handle Get Return _hwnd End Get End Property End Class ----------------------------------------------------------------- VB6 Client Code On a form add these three controls TextBox, CheckBox and Command Button and paste the following code Option Explicit Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long Private Declare Function MessageBox Lib "user32" Alias "MessageBoxA" _ (ByVal hWnd As Long, ByVal lpText As String, ByVal lpCaption As String, ByVal wType As Long) As Long Private Sub Command1_Click() Dim ot As New CTest Dim Whdl As Long 'Text1.Text is any Window Caption Whdl = FindWindow(vbNullString, Text1.Text) If Check1.Value = vbChecked Then 'use Win32 API MessageBox Whdl, "Hello on Window (" & Text1.Text & ")", "My Caption", vbInformation Else 'use .Net MessageBox If Whdl > 0 Then ot.MessageBoxU "Hello on Window (" & Text1.Text & ")", "My Caption", Whdl Else ot.MessageBoxU "Window Not Found (" & Text1.Text & ")", "My Caption" End If End If End Sub Example code converted to VB:
MessageBox.Show(New WindowWrapper(hwnd), "Hello World!") Public Class WindowWrapper Implements System.Windows.Forms.IWin32Window Public Sub New(ByVal handle As IntPtr) _hwnd = handle End Sub Public ReadOnly Property Handle() As IntPtr Implements System.Windows.Forms.IWin32Window.Handle Get Return _hwnd End Get End Property Private _hwnd As IntPtr End Class
Paul ~~~~ Microsoft MVP (Visual Basic)- It is still modal to both the windows!
I am trying to make the Message box appear modally on lets say Windows Explorer window by passing its hwnd, when I click the button on my
VB6 Form. But somehow it makes the displayed message box Modal to both my VB6 Form and Windows Explorer window.
If I use the win32 MessageBox API it works correctly. After I click the button I can proceed to work with my VB6 Form. Messagebox is only Modal to windows explorer.
Modified VB.Net code (based on ur sample above)
Public Shadows Function MessageBoxU(ByVal Prompt As String, Optional ByVal Title As String = "", Optional ByVal OwnerHandle As Integer = 0) As Integer
Dim iPtr As IntPtr
iPtr =
New IntPtr(OwnerHandle)
MessageBox.Show(
New CWindowWrapper(iPtr), Prompt, Title)
End Function
Modified VB6 Code
Private Sub Command1_Click()
Dim ot As New CTest
Dim Whdl As Long
'Text1.Text is any Window Caption
Whdl = FindWindow(vbNullString, Text1.Text)
If Check1.Value = vbChecked Then
'use Win32 API
MessageBox Whdl, "Hello on Window (" & Text1.Text & ")", "My Caption", vbInformation
Else
'use .Net MessageBox
ot.MessageBoxU "Hello on Window (" & Text1.Text & ")", "My Caption", Whdl
End Sub - The MessageBox method displays a modal window by design. I don't believe there is a parameter that will allow you to display a non-modal or mode-less window.
Can't you just use a Windows Form instead instead of a MessageBox?
Paul ~~~~ Microsoft MVP (Visual Basic) - I understand that Messagebox method is Modal and that is what I want it to be, but just to the Window whose handle I pass to it.
But it seems to become modal to both my VB6 Form (from where I call this method) and to the actual window whose handle I pass to this method. - The MessageBox method is just a .NET wrapper for the MessageBox API function. I don't know why both the parent window and calling app are blocked but it could be a threading restriction with respect to VB 6.0. I would be curious to see whether this would function differently under a .NET client.
I would use the API function call if it's providing the desired results. You could always create your own .NET MessageBox Class (wrapper) if you are looking for something that is easier to use than the API.
Paul ~~~~ Microsoft MVP (Visual Basic) - I tried it using a .Net client, its the same behavious with MessageBox.Show method. It becomes Modal on both, the form that this method is called from and the window whose handle is passed.
Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
Private Sub Command1_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Command1.Click
Dim handle As Integer
handle = FindWindow(vbNullString,
"VB6 Test")
MessageBox.Show(
New WindowWrapper(New IntPtr(handle)), "My Message: " & TextBox1.Text, "My Caption - " & TextBox1.Text)
'MessageBox(handle, "My Message: " & TextBox1.Text, "My Caption - " & TextBox1.Text, vbInformation)
End Sub
--------------------------
If I use the MessageBox API it behaves correctly in this scenario also. But the API is not able to display Unicode Text, which is kind of why I am trying to use .Net Message Box in the first place.
Declare Function MessageBox Lib "user32" Alias "MessageBoxA" (ByVal hWnd As Integer, ByVal lpText As String, ByVal lpCaption As String, ByVal wType As Integer) As Integer
- Let me check to see if I can get an explanation for this behavior.
Paul ~~~~ Microsoft MVP (Visual Basic) - Hi ,
Could you send your VB.NET project and VB6 project to me so that I can reproduce your scenario for further discussion? If you can, please send it via email(you can find it in my profile). Thanks.
Best regards,
Riquel
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Welcome to the All-In-One Code Framework! If you have any feedback, please tell us. - Hi Riquel
I had just sent the Code to you in via email. subject line
Ref: "how to pass hwnd from VB6 code in VB.net library using Interop"
Hope you can see what I am doing wrong here.
Thank you in advance. - Hi Narsi,
We can fix this issue by PInvoke calling MessageBox in VB.NET component to implement same effect as VB6 API calling. The following is my modification to your code snippet. I tested it. It should satisfy your requirement.
Public Shadows Function MessageBoxU(ByVal OwnerHandle As Integer, ByVal Prompt As String, ByVal Title As String, ByVal buttons As Integer) As Integer
Try
Dim iPtr As IntPtr
iPtr = New IntPtr(OwnerHandle)
MessageBox.Show(OwnerHandle.ToString())
MessageBox.Show(iPtr.ToString)
'MessageBox.Show(New CWindowWrapper(iPtr), Prompt, Title, buttons)
NativeMethods.MessageBoxW(iPtr, Prompt, Title, buttons)
Catch
MsgBox(Err.Description)
End Try
End Function
Partial Public Class NativeMethods
'''Return Type: int
'''hWnd: HWND->HWND__*
'''lpText: LPCWSTR->WCHAR*
'''lpCaption: LPCWSTR->WCHAR*
'''uType: UINT->unsigned int
<System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint:="MessageBoxW")> _
Public Shared Function MessageBoxW(<System.Runtime.InteropServices.InAttribute()> ByVal hWnd As System.IntPtr, <System.Runtime.InteropServices.InAttribute(), System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)> ByVal lpText As String, <System.Runtime.InteropServices.InAttribute(), System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)> ByVal lpCaption As String, ByVal uType As UInteger) As Integer
End Function
End Class
Best regards,
Riquel
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.- Proposed As Answer byRiquel_DongModeratorFriday, November 06, 2009 5:59 AM
- Marked As Answer bynarsiCherukupalli Friday, November 06, 2009 2:23 PM
I should have checked for a unicode version of the API function call (MessageBoxIndirectW) which can be called directly from a VB 6.0 app.
http://www.vbforums.com/showthread.php?t=541220
Paul ~~~~ Microsoft MVP (Visual Basic)- Marked As Answer bynarsiCherukupalli Friday, November 06, 2009 2:23 PM
Riquel
This worked! Thank you so much for your help. The solution Paul gave below is also good and works for me. Now I have a choice!
Thank you for your help, I appreciate it very much.
NarsiPaul
This worked! Thank you so much for your help. Riquel's solution above is also works. Now I have a choice!
Thank you for your help, I appreciate it very much.
Narsi


