I have to import a few functions of a dll written in C into a VB6 project. I have an example written in C# but I don't really know how to do the same thing in VB6.
In C# it goes like this:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int someCallback(IntPtr ch, uint chL, IntPtr cbData);
[DllImport("someDLL.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int someFunction(IntPtr con, someCallback callback, IntPtr cbData);
Everything works fine in the example when calling someFunction.
The documentation of the dll just gives me this:
typedef int(SOMEAPI_CALL * someCallback)(const unsigned char *ch,
unsigned int chL,
void *cbData)
SOMEAPI_CALL someFunction(Con* con,
someCallback callback,
void* cbData)
There should be a way to do the same in VB6 but I don't have that much experience with this language. Searched the web for a good time but didn't find anything that could help me.
I know how to declare functions from that dll in my project but thats that. How to convert this UnmanagedFunctionPointer thingy into VB6 code, I just don't know.
VB6 has no attributes in the way VB.NET (and C#) does, and the annotation would be unnecessary anyway. You can just pass a function pointer to a C API function via the AddressOf operator:
Declare Function someFunction Lib "someDLL" ( _
ByVal con As Long, _
ByVal callback As Long, _
ByVal data As Long _
) As Long
…
Call someFunction(con, AddressOf SomeCallback, data)
But even that won’t work since VB6 does not support native interop using the cdecl calling convention, it only supports stdcall. You will either need to recompile your DLL using the stdcall calling convention, or create a wrapper in C or IDL (there are some hacks using inline assembly to wrap individual cdecl calls but I wouldn’t recommend using these).
Related
I've started working on a legacy code (i.e. no unit tests) Windows Forms app written in VB.Net and I've been asked to start introducing unit tests as I make changes. I have not done much unit testing before and I am unsure how to test a recurring pattern I see in the methods. Here is my attempt to outline a simplified typical example:
Private Sub cmdButton_Click(ByVal eventSender As Object, ByVal eventArgs As EventArgs) Handles cmdAprv.Click
'The event is Private and it then calls multiple other private methods
'but I will simplify drastically for this example:
If <conditions> Then
InsertEmployee()
End If
End Sub
Private Function InsertEmployee() As Integer
'Typically, the functions are quite long with lot of code initializing
'variables, but I will simplify drastically for this example:
Dim _name As String = "[]"
Dim _departmenmt As String = "Engineering"
Dim _salary As Double = 2000
'Then at the end there may be multiple database updates like this one:
Dim connectionString As String = "<Call a Function to get ConnectionString details>"
Using conn As New SqlConnection(connectionString)
Using cmd As New SqlCommand("INSERT INTO Employees (Name, Department, Salary) VALUES (#Name, #Department, #Salary)", conn)
cmd.CommandType = CommandType.Text
cmd.Parameters.AddWithValue("#Name", _name)
cmd.Parameters.AddWithValue("#City", _departmenmt)
cmd.Parameters.AddWithValue("#City", _salary)
conn.Open()
Dim i As Integer = cmd.ExecuteNonQuery()
conn.Close()
Return i
End Using
End Using
End Function
There is a lot of code in Private methods like this. To make these methods accessible to the testing project, I reckon I can downgrade the Function's accessibility protection from Private to Friend (VB.Net “Friend” = C# “internal” access modifier) and then use InternalsVisibleTo Attribute to mark the unit testing assembly as a friend assembly.
But I’m really not sure what to do with the Database INSERT or UPDATE code to make the function testable? One requirement I have is that the Unit Tests must not actually modify the database.
Can anyone show me a good example of refactoring a method like this for unit testing?
This is of course opinion-based. But here is what I do with legacy un-testable methods.
In your tested project, as you said, introduce InternalsVisibleTo
In your tested project introduce unit test - specific methods that will be only available for DEBUG configuration
#If DEBUG Then
Friend Function InsertEmployee_UT() As Integer
' call your method here
End Function
#End If
This is the principle. In fact, wrap your InternalVisibleTo with #If DEBUG Then
Build and perform your unit tests only in DEBUG configuration, and call the UT-functions that will not exist in RELEASE/Production code
Now Lets talk about breaking from the database. While calling DB can be a different sort of test, like Functional Test, you're right. Preferably, you can run your unit test without DB connection. What to do
Separate db calls into a single provider and pass Interface into the method. Yes, you need slight method change
Friend Function InsertEmployee(provider As IEmployeeData) As Integer
With this, in your unit test you can mock your provider and then examine. You can actually set this provider during construction or a property, then you don't even need to pass it to each method.
You can pass a callback As Function(Of . . ) or callback As Action(Of . . )
This way you also can separate functionality of retrieving data and calling for it.
These changes are not very intensive and can be done relatively quickly. And you will be able to do your testing. Changing private methods is safe, you can do it in any form or shape.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I have to "translate" / up-date a program that was written in C about 20 years ago to VB.net due to its old SQL connection style that isn't compatible anymore. However, I have minimal experience with C and even less with the winAPI(which the C application uses)... I was wondering, can the same functions from the API be use in VB.net?
I have been able to add a declaration like this:
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Public Shared Function SetWindowText(hWnd As IntPtr, lpString As String) As Boolean
End Function
to get a window Handle as IntPtr ( in vb.net). However the C program uses functions such as:
BOOL NEAR GoModal( HINSTANCE hInstance, LPCSTR lpszTemplate,HWND hWnd, DLGPROC lpDlgProc, LPARAM lParam )
By importing the user32.dll I can't get the hWnd handle but I can get the IntPtr ( If I understood well, is a point to a window as an integer right? Kinda similar to hWnd --> I could be TOTALLY wrong, but this is what I understood)
As I go to the definition of each type (i.e: NEAR , HINSTANCE, LPCSTR, etc...) I try to find an equivalent call in VB but ... its useless. For instance, I was looking at NEAR and I guess it was to decide if two pointers were close in memory ? ( again might be wrong, it's just what I gathered).
Ultimately, my question is, would such call exist in vb.net / even be useful with the more modern framework and such?
Let's break down the parameters in the function call:
BOOL NEAR GoModal(HINSTANCE hInstance,
LPCSTR lpszTemplate,
HWND hWnd,
DLGPROC lpDlgProc,
LPARAM lParam )
BOOL is a 32 bit integer. You can use the System.Boolean type in your code, but it needs the MarshalAsAttribute applied to it, specifying the type as UnmanagedType.Bool
NEAR specifies information to the compiler. When translating to .net, you can ignore it.
HINSTANCE is a Handle to an Instance. Translating to .net, handles are typically defined as IntPtr values. This doesn't mean that it's a pointer to memory. (ie- Marshal.Read can't be used.)
LPCSTR is a Long Pointer to a C style STRing. This is an ANSI string, so it means that the parameter needs the MarshalAsAttribute with UnmanagedType.LPStr. If this is was an out parameter, things would be more complicated, and you'd either need to pass a StringBuilder or use Marshal.AllocHGlobal/Marshal.AllocCoTaskMem to get unmanaged memory allocated.
HWND is a Handle to a Window. Like the HINSTANCE it is typically marshalled as an IntPtr
DLGPROC is a bit more complex, so I'll address it below.
LPARAM is a Long Parameter. The standard implementation that Microsoft used for this type when they created the Message class, is IntPtr. You should follow suit.
As I said above DLGPROC is more complex. It is actually a pointer (reference) to a function. Specifically one with the signature:
INT_PTR CALLBACK DialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
We've already seen HWND and LPARAM, so let's take a quick look at the other things in this signature.
INT_PTR is an Integer Pointer. If that sounds familiar, it should. It's just an IntPtr.
CALLBACK is another bit of information that the compiler uses to determine how the function should be compiled, and how people using it should send their parameters to the function. By default the .net marshal handles this, so no additional configuration is needed.
WPARAM stands for Word Param. In this case, it's old terminology, and you will want to use IntPtr to receive the value.
To marshal a pointer to a DLGPROC, you will need to create a delegate with the appropriate signature:
Delegate Function DLGPROC(ByVal hWnd As IntPtr,
ByVal uMsg As UInt32,
ByVal wParam As IntPtr,
ByVal lParam As IntPtr) As IntPtr
You then need to create a function somewhere in your code, with the same signature, to receive the call from the native code. Something like:
Private Function MyDialogProc(ByVal hWnd As IntPtr,
ByVal uMsg As UInt32,
ByVal wParam As IntPtr,
ByVal lParam As IntPtr) As IntPtr
Return IntPtr.Zero ' Put the appropriate code here.
End Function
You then can add a class member to hold that delegate:
Private DialogProc As DLGPROC = New DLGPROC(AddressOf Me.MyDialogProc)
After all of that, you're finally ready to import the GoModal function prototype. (YAY!) That looks like:
<DllImport("DLL_NAME")>
Private Shared Function GoModal(ByVal hInstance As IntPtr,
<MarshalAs(UnmanagedType.LPStr)> ByVal lpszTemplate As String,
ByVal hWnd As IntPtr,
ByVal lpDlgProc As IntPtr, ' More on this below
ByVal lParam As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
We can now call the function from our code:
Dim dialogProcedure As IntPtr = Marshal.GetFunctionPointerForDelegate(Me.DialogProc)
Dim result As Boolean = GoModal(IntPtr.Zero,
"Template",
Me.Handle,
dialogProcedure,
New IntPtr(100))
Two notes about the function call:
IntPtr.Zero is the same as NULL
New IntPtr(100) creates an IntPtr with the specified value. (Sometimes the LPARAM is just a number)
And if you made it this far, Congratulations! There may be a couple bugs in the code, but this should get you going. For other Windows API types, you can find a lot of information at pinvoke.net.
If you have a lot of interop to do, it would be easier to just add a C++/CLI dll to your project and call these functions natively. It's much, much easier, and you can define the functions exactly how you want them. In addition, C++/CLI works with any of the .net languages.
I have an application in Visual Basic.Net and need to find all elements within an array which meet a certain condition.
Dim result As my_obj() = Array.FindAll(lstData, HasToBeSent)
Where the function HasToBeSent is defined like this:
Private Function HasToBeSent(ByVal cta As my_obj) As Boolean
Return cta.IsSent
End Function
However this doesn't compile, it says I haven't specified an argument for the parameter cta in Private Function HasToBeSent(ByVal cta As my_obj) As Boolean
I am using Visual Studio 2005, therefore I have VB.Net 8.0. I am guessing the suggested answer is for higher versions of VB.Net. Because when I replace the previous code with
Dim result As my_obj() = Array.FindAll(lstData, Function(cta) HasToBeSent(cta))
It says: "expression expected"
How can I solve this?
Keep your HasToBeSent definition but add the Shared keyword to it to make it static (actually this is probably optional, but since this code doesn't rely on anything else in your class, it's probably a good design decision anyway).
Private Shared Function HasToBeSent(ByVal cta As my_obj) As Boolean
Return cta.IsSent
End Function
And then in Array.FindAll(), give it the "address of" your function:
Array.FindAll(lstData, AddressOf HasToBeSent)
If you upgrade to a newer version of VB, then you can inline a delegate:
Array.FindAll(lstData, Function(cta) cta.IsSent)
To keep the HasToBeSent function, you can simply call that instead:
Array.FindAll(lstData, Function(cta) HasToBeSent(cta))
Reader C# project need to persists ~POCO to file. But we are at our debut and changes occurs quite often. Our soft is already used (persisted) by few customers.
I prefer to use XML over anything for many reasons.
I checked many many xml serialization libs.
Many libs stores the specific type and version. I don’t need that.
Many libs do not give us the possibility to serialize by ourself: ie we need an interface to custom load/save data (I see many advantages **)
Some libs forces us to have empty constructor
Some libs only manage public properties
Some libs have many limitations on types (do not support Dictionary, …)
** (advantages of an interface to load/save data)
Easier to manage many versions
Enable to do hardcoded conversion if required (class x -> class y, … )
Easier to not retain old code
I strongly think that for my needs we would better served by using the old way: a bit like deserializing in C++. I think we would be better served by something that would enable us to just add fields and fields name manually instead of using Attributes.
Kind of:
void XmlDeserialize(XmlReader xmlReader)
{
xmlReader.Load((n)=>Version(n)); // or just: _version = xmlReader.LoadInt("Version");
xmlReader.Load((n)=>Name(n));
xmlReader.Load((n)=>EmployeeId(n));
if (Version ==2)
…
If (version == 3)
…
The closest I have found to fit my needs was: DataContractSerializer that supports IExtensibleDataObject, but it is a pain and ass to use.
I question myself if I’m not wrong everywhere? It’s impossible I’m the only one with that need (or this vision). Why is nobody writing any lib for that, and did I miss something somewhere ?
What I think wrongly ? What do you recommend ?
Do you have to use XML reader.load for this? It is WAY easier to create the business objects that represent your XML data, and then deserialize the object, like below (sorry I only found my vb.net version of this):
Public Shared Function ReadFromString(ByVal theString As String, ByVal encoding As System.Text.Encoding, ByVal prohibitDTD As Boolean) As T
Dim theReturn As T = Nothing
Dim s As System.Xml.Serialization.XmlSerializer
s = New System.Xml.Serialization.XmlSerializer(GetType(T))
Dim theBytes As Byte() = encoding.GetBytes(theString)
Using ms As New IO.MemoryStream(theBytes)
Using sTr As New StreamReader(ms, encoding)
Dim sttng As New XmlReaderSettings
'sttng.ProhibitDtd = prohibitDTD
If Not prohibitDTD Then
sttng.DtdProcessing = DtdProcessing.Ignore
sttng.XmlResolver = Nothing
Else
sttng.DtdProcessing = DtdProcessing.Prohibit
End If
Using r As XmlReader = XmlReader.Create(sTr, sttng)
theReturn = CType(s.Deserialize(r), T)
End Using
End Using
End Using
Return theReturn
End Function
You can event get rid of the xmlreadersettings and the encoding if you like. But this way you could keep different business objects for each version you have? Additionally, if you're only adding (and not changing/deleting) objects, you can still use the most recent business object for all versions, and just ignore the missing fields.
I finally decided to use XmlSerialization like this
usage but I hate to be forced to create default constructor and not being able to serialize members (private or public).
I also decided to use ProtoContract when very high speed is necessary.
But my preferred one is DataContractSerializer where it offer xml format (easier to debug), no default constructor needed and can serialize any members.
Hi after refering to http://www.mono-project.com/Embedding_Mono
i can call methods from managed code by using mono_runtime_invoke.
Now i want to call a method in the managed code with a function pointer (or at least some pointer) as argument from native c code
managed code
public delegate void MyDelegate ();
//method i want to call from native code
public static MyDelegate mono_method(MyDelegate c_ptr)
{
//...do sth
return c_ptr;
}
native code
typedef void (*FUNC_PTR)();
FUNC_PTR my_fct_ptr = some_c_function;
//calling the managed method
MonoObject *result_of_mono_method =
mono_runtime_invoke(mono_method, NULL, my_fct_ptr, NULL);
edit: to point out the problem
how can i call
public static unsafe int* mono_method(int *c_ptr)
from native c code, without using dllImport.
You have several options.
One is to add an internal call that takes a IntPtr (the function pointer) and the arguments: you will then cast the pointer to the function pointer type and call it normally from C code.
Using something like libffi can help to overcome the limitation of having just one function pointer type, it depends how many you need, you didn't specify.
Another option is to use Reflection.Emit to build a dynamic method: in it you will use the calli IL instruction to invoke the function pointer directly.
I'm not exactly sure what you're trying to ask here, but this is the easiest way to do a call back.