|
And Here:
Calling a Salford FTN95 DLL from Microsoft Visual Basic
This applies to:
Salford FTN95 Win32
Summary
Calling routines in a dynamic link library created with Salford FTN95 from a Microsoft Visual Basic application.
Solution
An FTN95 DLL that is called by an executable that uses the STDCALL calling convention (e.g. one created using Win32 Visual Basic) must use F_STDCALL in the declaration of all exported subprograms. For example,
F_STDCALL FUNCTION F(X)
INTEGER F,X
F=X
END
Such a function could make calls to Windows API functions provided an interface is provided via, for example, "USE MSWIN" or "INCLUDE <windows.ins>". Alternatively an interface for each API function can be given explicitly. For example,
STDCALL SENDMESSAGE 'SendMessageA' (VAL,VAL,VAL,VAL):INTEGER*4
A call is automatically made to a DLL function called LIBMAIN when the DLL is loaded. If you do not provide a definition of LIBMAIN then SLINK will provide a default for you. LIBMAIN is used to initialise global data. It takes the following form.
F_STDCALL INTEGER FUNCTION LIBMAIN(hInst,ul,lpR)
INTEGER hInst,ul,lpR
!***** Initialise global data here
LIBMAIN=1
END
A simple SLINK script would take the form:
dll
lo f95.obj
exportall
file c:\windows\f95.dll
A Visual Basic program can use calls to the API functions LoadLibrary and FreeLibrary in order to ensure that the DLL does not unload whilst a Visual Basic form is loaded. Here is some sample code for this purpose.
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal s As String) As Long
Private Declare Function FreeLibrary Lib "kernel32" (h As Long) As Long
Dim hLibModule As Long
Private Sub Form_Load()
hLibModule = LoadLibrary("f95.dll")
End Sub
Private Sub Form_Unload(Cancel As Integer)
i& = FreeLibrary(hLibModule)
End Sub
--------------------------------------------------------------------------------
THE INFORMATION IN THIS DOCUMENT IS PROVIDED ON AN AS-IS BASIS WITHOUT WARRANTY OF ANY KIND. PROVIDER SPECIFICALLY DISCLAIMS ANY OTHER WARRANTY, EXPRESS OR IMPLIED, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL PROVIDER BE LIABLE FOR ANY CONSEQUENTIAL, INDIRECT, SPECIAL OR INCIDENTAL DAMAGES, EVEN IF PROVIDER HAS BEEN ADVISED BY USER OF THE POSSIBILITY OF SUCH POTENTIAL LOSS OR DAMAGE. USER AGREES TO HOLD PROVIDER HARMLESS FROM AND AGAINST ANY AND ALL CLAIMS, LOSSES, LIABILITIES AND EXPENSES.
Document ID: SKB0169
Published on: 19 Feb 2004
|
|
|
|
|
I have been struggling with several of the winmm.dll API's. One of them is the waveOutGetDevCaps function. The arguments aren't complicated but despite every attempt I can't get it to work properly. I have tried searching for on-line documentation and there are multitudes of them but they all use the function passing the same parameters receiving the same successful results. I can't figure this out. Can anyone help me with this.
<snippet of="" code="">
Public Const MAXPNAMELEN = 32
Public Structure WAVEOUTCAPS
Dim wMid As Short
Dim wPid As Short
Dim vDriverVersion As Integer
Dim szPname As String
Dim dwFormats As Integer
Dim wChannels As Short
Dim dwSupport As Integer
End Structure
Public Declare Function waveOutGetDevCaps Lib "winmm.dll" Alias "waveOutGetDevCapsA"
(ByVal uDeviceID As Integer, _
ByRef lpCaps As WAVEOUTCAPS, ByVal uSize As Integer) As Integer
Dim caps As New WAVEOUTCAPS
Dim dev, hWaveOut, hwnd As Integer
Dim buffer As String = (MAXPNAMELEN)
dev = waveOutGetDevCaps(0, caps, Len(caps))
'the string value produced here is evaluated as null as well as any of the other members which produce 0. I have tried switching the ByRef and ByVal keywords around but this hasn't proven to be a resolution.
txtCaps.Text = "Channels = " & caps.szPname
Any help would be appreciated.
Thanks!
"For God so loved the world...." John 3:16
I only have one boss, J.C.
|
|
|
|
|
What does dev contain when the function returns? The results your getting would suggest that one or more parameters that your passing in are incorrect. Also, we're missing the code that defines the structure WAVEOUTCAPS. It would appear that an attribute is missing that properly defines the structure so it can be marshalled correctly.
RageInTheMachine9532
"...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome
|
|
|
|
|
dev returns a value of 0 which from my understanding would indicate that there wasn't a problem passing the function. As documented per MSDN as
Public Const MMSYSERR_NOERROR = 0
However, the value can also be 0 if the last parameter passed which would be evaluated as the size of the WAVEOUTCAPS structure, is determined to be zero as well, then nothing would be copied and the function returns zero also.
So I am uncertain if the 0 value means success or a bad pass of a parameter.
As for the missing attribute, what would that be and where is it documented? Microsoft isn't making it obvious.
Thanks
"For God so loved the world...." John 3:16
I only have one boss, J.C.
|
|
|
|
|
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
This is why I asked for the code that declared the structure. This line makes sure that the structure members get packed together, in memory, in the order that they are declared and, if you follow the Win32 API documentation, the order that the API expects them in.
Without this line, the memory image of the structure can be anything in managed memory. This means that the structure can be moved at any time and can even be spread out and fragmented over a much larger block of memory.
Putting the LayoutKind.Sequential attribute in there makes sure that the structure is arranged in memory properly. ALL structure definitions being marshalled to the API require this attribute, otherwise you'll run into problems like the one you had with this one, and/or you can run into intermittant problems that you just can't figure out why it worked one time and not another...
RageInTheMachine9532
"...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome
|
|
|
|
|
Okay Dave,
This is a very useful piece of information that I was previously unaware of and I now understand what you meant with your previous inquiry concerning the structure. This was apparently a new requirement for the .NET framework since I don't recall such a requirement under VB6 for structures or what was then termed as "types".
I also noticed the additional line of code that was:
MarshalAs(UnmanagedType.ByValTStr, SizeConst:=MAXPNAMELEN)
Seemingly this is the only way to allocate the string buffer within the structure for the returned value in VB.NET that would be the equivalent for VB6 as:
szPname As String * 32
What about the structure members after the "MashalAs" parameter specified for the string member? Will they require anything additional to ensure that the returned values are properly packed in memory before a return also or does the StructLayout parameter apply for the entire structure as I would assume.
Thanks Dave
"For God so loved the world...." John 3:16
I only have one boss, J.C.
|
|
|
|
|
The primitive types after the String, and MarshalAs, are known types with fixed sizes and are automatically Marshaled as the proper types. Typically, the only thing you have to watch out for is the structure member packing, which by default is on 8-byte boundries. Sometimes you'll com acrossed a structure where you have to specify a smaller pack size, typically 4.
RageInTheMachine9532
"...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome
|
|
|
|
|
mivey4 wrote:
As for the missing attribute, what would that be and where is it documented? Microsoft isn't making it obvious.
Your actually just scratching the surface of a very BIG topic, call Interop. The documentation starts here[^] with Interoperating with Managed Code. It assumes you already know how the functions your calling work and what their requirements are, like for WaveOutGetDevCaps.
RageInTheMachine9532
"...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome
|
|
|
|
|
mivey4, try this:
Imports System.Runtime.InteropServices
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code removed here"
Public Const MAXPNAMELEN = 32
<structlayout(layoutkind.sequential, charset:="CharSet.Auto)"> _
Structure WAVEOUTCAPS
Public wMid As Short
Public wPid As Short
Public vDriverVersion As Integer
<marshalas(unmanagedtype.byvaltstr, sizeconst:="MAXPNAMELEN)"> _
Public szPname As String
Public dwFormats As Integer
Public wChannel As Short
Public wReserved1 As Short
Public dwSupport As Integer
End Structure
Declare Auto Function waveOutGetDevCaps Lib "winmm.dll" _
(ByVal uDeviceID As Integer, _
ByRef lpCaps As WAVEOUTCAPS, _
ByVal uSize As Integer) As Integer
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim caps As New WAVEOUTCAPS
Dim dev, hWaveOut, hwnd As Integer
Dim buffer As String = (MAXPNAMELEN)
dev = waveOutGetDevCaps(0, caps, Len(caps))
TextBox1.Text = "Device = " & caps.szPname
TextBox2.Text = "Driver Version = " & caps.vDriverVersion
TextBox3.Text = "Channel = " & caps.wChannel
End Sub
End Class
|
|
|
|
|
sorry, CP messed up the struct:
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Structure WAVEOUTCAPS
Public wMid As Short
Public wPid As Short
Public vDriverVersion As Integer
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=MAXPNAMELEN)> _
Public szPname As String
Public dwFormats As Integer
Public wChannel As Short
Public wReserved1 As Short
Public dwSupport As Integer
End Structure
|
|
|
|
|
Okay! That nipped the problem in the bud.
Now for enlightenment for the initial issue. The additional lines of code that obviously made all the difference between success and failure were:
a. Imports System.Runtime.InteropServices
b. StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)
c. MarshalAs(UnmanagedType.ByValTStr, SizeConst:=MAXPNAMELEN)
Why must these additional parameters be set in order for the API function to properly work but there isn't any direct or immediately obvious documentation for it? I have used other API structures and passed them receiving the expected results without addition of these parameters. Are there any resources available for VB.NET programmers that provide a good sound source of information for implementing API calls?
My apologies for the oversight of an additional member of the WAVEOUTCAPS structure that was mentioned earlier to me.
----> Public wReserved1 As Short
I use an API Generator utility to generate the Declarations and constants and apparently this additional member wasn't added until after the release of the utility. But I do realize the importance of providing the API calls with everything they expect or there will be problems.
Thanks
"For God so loved the world...." John 3:16
I only have one boss, J.C.
|
|
|
|
|
Here is is a reference:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcn7/html/vaconStructuresAndClasses.asp
|
|
|
|
|
And Here:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemRuntimeInteropServicesStructLayoutAttributeClassTopic.asp
|
|
|
|
|
Last one:
I like MSDN but it is hard to get around until you get used to it.
Microsoft Win32 to Microsoft .NET Framework API Map
Microsoft .NET Framework and Microsoft Visual Studio User Education Teams
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/win32map.asp
I hope all this help's but I gotta go back to work.
|
|
|
|
|
Thanks Anonymous,
All the references will most definitely be invaluable bookmarks that will more carefully review. I appreciate all the help and thanks for taking time to provide the assistance.
"For God so loved the world...." John 3:16
I only have one boss, J.C.
|
|
|
|
|
Hello all,
First post here and I'll start by saying that, while I've done a few basic VB projects, I am very much a newbie to VB. Anyway, I need to write a VB app that is called from an HMI application and will bring a second application, already running, to the foreground. Once this occurs, the VB form needs to stay on top of this second application allowing a button for switching back to the original HMI. When this "return button" is pressed, the form/VB app should exit/quit/unload(?).
I have experimenting with the AppActivate command, but there seems to be problems with it performing everytime.
Any help anyone could offer would be greatly appreciated!
Walt Hucks
|
|
|
|
|
Try this API code:
-------- 8< paste on a module 8< ------------------------------------------
Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, y, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Const HWND_TOPMOST = -1
Private Const HWND_NOTOPMOST = -2
Private Const SWP_NOMOVE = &H2
Private Const SWP_NOSIZE = &H1
Private Const TOPMOST_FLAGS = SWP_NOMOVE Or SWP_NOSIZE
Public Sub MakeNormal(hwnd As Long)
SetWindowPos hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS
End Sub
Public Sub MakeTopMost(hwnd As Long)
SetWindowPos hwnd, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS
End Sub
-------- 8< paste on a module 8< ------------------------------------------
now, whenever you need it, call MakeTopMost(frmMain.hWnd), and if you need to 'free' the window, not being 'Always on top' anymore, call
MakeNormal(frmMain.hWnd), that´s it!
btw, if you close the app, and you never free-ed the window, nothing happens, in case you are wondering...
Pablo.Ar
PS: I got this code from someone else, of course. Glad to have a chance to pass it along.
|
|
|
|
|
Thanks much for the info! The question I have now though is, where can I find the hwnd for the two different applications? In other words, I assume that you have to reference the handle of the application that you wish to place on top. If I don't have access to the source code, how do I find out what this handle is?
Thanks again for your help!
Walt Hucks
|
|
|
|
|
Never mind my reply to your post... I guess that you meant for that code to be used for my VB form and not necessarily the other two applications that I'm switching between.
But now I would like to know what is the proper way to terminate my VB form/application. The event prompting the closure would be another button click that returns the VB form to "Normal" (or not on top all the time), switches to another application and then closes.
Once again, I appreciate all help.
Walt Hucks
|
|
|
|
|
well, I really don´t follow you that much on what you are trying to achieve, but as much as I understood, I can suggest try coding on this section of the main form:
Form_Terminate()
or
Form_QueryUnload()
those two events are the safest ways to end an app, giving you space to code the final process of the program´s 'normal' termination.
Pablo.Ar
ps:I hope this one helped enough, but I encourage you to re-post with a more specific description of the steps in the problem solving...
|
|
|
|
|
I have a couple sprocs that I wanted to enclose in a transaction. The transaction only has to assure that if one fails they all fail, I don't need to prevent updates or anything of the like, but that is somewhat irrelevant I guess.
The problem is, is that as soon as the trans was put into place it always threw exceptions on the first sproc. I think I will just combine the sprocs together in sql, but I am curious to what I am doing wrong.
Here is the code
<br />
Public Function UpdateFieldErrors(ByRef conn As SqlConnection, ByRef dt As DataTable) As Integer<br />
<br />
'counter of the number of records updated<br />
Dim counter As Integer = 0<br />
Dim corrected_fl As String<br />
Dim trans As SqlClient.SqlTransaction<br />
<br />
'submit all the corrected values and the comments to the database<br />
For Each row As DataRow In dt.Rows<br />
'ensure that the columns that were not corrected were not submitted<br />
Try<br />
'only require a transaction that will allow all to rollback if required<br />
'since there is a lock on the image other users updating or querying<br />
'the data is of no concern<br />
trans = conn.BeginTransaction(IsolationLevel.ReadCommitted)<br />
<br />
Dim cmd As New SqlCommand("dbo.mySproc", conn)<br />
cmd.CommandType = CommandType.StoredProcedure<br />
cmd.Parameters.Add("@err_id", row.Item("err_id"))<br />
cmd.Parameters.Add("@new_value", row.Item("new_value"))<br />
cmd.Parameters.Add("@comments", row.Item("comments"))<br />
<br />
'only set the error to corrected if there is user input in the newvalue field<br />
If row.Item("new_value") = "" Or row.Item("new_value") Is DBNull.Value Then<br />
cmd.Parameters.Add("@corrected_fl", "N")<br />
Else<br />
cmd.Parameters.Add("@corrected_fl", "Y")<br />
End If<br />
<br />
cmd.ExecuteNonQuery()<br />
<br />
'update the answer string containing all the students answers<br />
DbAnswerUpdate.UpdateAnswerString(conn, row)<br />
trans.Commit()<br />
<br />
counter += 1<br />
Catch ex As Exception<br />
trans.Rollback()<br />
MessageBox.Show("Exception occured when inserting one of the updated rows.")<br />
End Try<br />
Next<br />
<br />
dt.AcceptChanges()<br />
<br />
Return counter<br />
<br />
End Function<br />
Thanks for the help
|
|
|
|
|
You forgot to tell us what the Exceptions are and on what lines they are occuring.
RageInTheMachine9532
"...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome
|
|
|
|
|
oops I will get those up in a bit, but right now some other changes have to get worked out first. thx
|
|
|
|
|
how can I code the datagrid to reload it every time when the submit button is clicked?
button1_click
???how can I code something in here to tell function results to reload every time when the submit button is clicked?????
results()
end sub
public function results()
Try
objConn.Open()
objDA.SelectCommand = New OleDbCommand
objDA.SelectCommand.Connection = objConn
objDA.SelectCommand.CommandText = "SELECT * from XXX"
objDA.SelectCommand.CommandType = CommandType.Text
objDA.SelectCommand.ExecuteNonQuery()
objDA.Fill(objDS, "XXX")
objConn.Close()
Catch ex As Exception
MessageBox.Show("fail connection")
End Try
grdResults.DataSource = objDS
grdResults.DataMember = "XXX"
end function
Lisa
|
|
|
|
|
I'm using a network stream to send data but don't how to recieve it efficently. Reading data from the stream assumes knowing data is there. How do I know when data is waiting to be read?? Is a event triggered when data is able to be recieved??
Thanks
|
|
|
|
|