How to add attribute "CallingConvention" to Declare statement when calling dll? - vb.net

In VB.NET, to import a method from DLL file can be written in:
DllImport statement - new method introduced for .net
Declare statement - old method since VB6
For the first one, the code looks like:
Imports System.Runtime.InteropServices
<DllImport("library_name.dll", EntryPoint:="entry_point", CallingConvention:=CallingConvention.Cdecl)> Public Function method_name(...) AS ...
End Function
And the above code works fine, I just wonder how to convert the code into the older way using Declare keyword as following:
Declare Function method_name Lib "library_name.dll" Alias "entry_point" (...) As ...
To make the question more specific, where can I add the CallingConvention attribute into the Declare statement?

The legavy Declare syntax is limited to stdcall. Use p/invoke.

Related

Declare variable for shared procedure inside procedure instead Imports statement

I'm using an imports statement to access shared constants and shared procedures just to shorten things a bit.
Imports vList = Helper.Stores.Departments.FruitList
But what I'd really like to do is declare it inside the procedure:
Dim vList as Helper.Stores.Departments.FruitList
Of course I get the warning: Access of shared member, constant member, enum member or nested type through an instance; qualifying expression will not be evaluated. when I try to use it like that.
Is there a way to do something like this inside the procedure without using the imports statement?
As far as I know you can only create an alias of this kind with an import statement as you already done.
The thing that you can do inside a procedure is creating variables using the fully qualified name for the class.
Take a look at the MSDN documentation about Namespaces for more information.

How to use the variable declared in one module to be used in other module function access vba

Is there any way that we can use variable declared in one module and use that variable in a function defined in other module?
Yes. Declare a variable at module level like this:
Public myvar As String
It can then be accessed from other modules.
Note, however, that global variables like this are almost never a good idea.

C# DLLImport converted to VB.NET DLLImport...what am I missing?

In C# I have this:
[DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
public static extern IntPtr GetDesktopWindow();
I tried to convert to VB.NET thus:
<DllImport("user32.dll", EntryPoint:="GetDesktopWindow")>
Function GetDesktopWindow() As IntPtr
End Function
But I am getting an error...
"Imports System.Runtime.InteropServices.DllImportAttribute cannot be applied to instance method."
Can some explain what I need to do to fix this, and even better, tell me WHY?
Thanks!
You forgot to convert the static keyword from the C# declaration to VB.NET. That's what the error message is telling you. Unless you have a static method, you're declaring an instance method, and the DllImportAttribute cannot be applied to an instance method.
The VB.NET equivalent of static is Shared. So your declaration should look like this:
<DllImport("user32.dll", EntryPoint:="GetDesktopWindow")>
Shared Function GetDesktopWindow() As IntPtr
End Function
I feel compelled to point out a couple of other things:
It's unnecessary to specify the EntryPoint when your function declaration has the same name. Not that it hurts anything to do so anyway, but I feel that it keeps down duplication and reduces the chances of error if you omit it.
P/Invoke declarations like this should generally go into a static class with a name like NativeMethods (StyleCop enforces this guideline). In VB.NET, static classes are called modules. So it would look like this:
Module NativeMethods
<DllImport("user32.dll")>
Shared Function GetDesktopWindow() As IntPtr
End Function
End Module
In older versions of VB (pre-VB 10, shipped with VS 2010), you needed line continuation characters in order to break up function declarations onto multiple lines. Those ugly warts make it look like this:
Module NativeMethods
<DllImport("user32.dll")> _
Shared Function GetDesktopWindow() As IntPtr
End Function
End Module
And finally, be very careful about how you use the desktop window returned by the GetDesktopWindow function! Lots of people abuse it, and most of the time when I see people trying to retrieve a handle to it, that's a sign that they're already doing it wrong. (Not saying you are, since I can't see the rest of your code, just something to be aware of!)

C++/CLI optional arguments

Why i cannot declare default arguments for member functions of a managed type or generic functions? C# 4.0 introduced Named and Optional Arguments; there is a similar thing for CLI?
I do not understand why is not possible to declare a method like this:
void Optional(int argument = 0);
And then when I call Optional(); the compiler does not translate this call into: Optional(0);.
It looks like the C++/CLI Compiler doesn't emit the correct IL directive for that. It doesn't emit the directive .param [1] = int32(0), which C# uses for recognizing default parameters. If you open the generated assembly in ILDasm, you'll see it.
A way that compiles would be to use the attributes Optional and DefaultParameterValue from the System::Runtime::InteropServices namespace, but C# doesn't use those for default parameters, so currently there's no easy way around creating an overload.
You can find the question asking about those Attributes here: https://stackoverflow.com/a/4974528/93652

DllImport vs Declare in VB.NET

I notice in the MSDN documentation that there are multiple ways to declare a reference to a function in an external DLL from within a VB.NET program.
The confusing thing is that MSDN claims that you can only use the DllImportAttribute class with Shared Function prototypes "in rare cases", but I couldn't find the explanation for this statement, while you can simply use the Declare keyword instead.
Why are these different, and where would I appropriately use each case?
Apparently the Declare and DllImport statements are basically the same. You can use whichever you prefer.
Following is a discussion of the few points that may work a little differently in each, which may influence a preference for one over the other:
I started with an article from MSDN regarding Visual Studio 2003 titled Using the DllImport Attribute. (A bit old, but since the DllImport statement seems to have originated in .NET, it seemed appropriate to go back to the beginning.)
Given an example DllImport statement of:
[DllImport("user32.dll", EntryPoint = "MessageBox", CharSet = Unicode)]
int MessageBox(void* hWnd, wchar_t* lpText, wchar_t* lpCaption, unsigned int uType);
It says that if the EntryPoint value is left out, the CLR will look for the name of the function (MessageBox, in this case) as a default. However, in this instance, since a CharSet of Unicode was specified, the CLR would FIRST look for a function called "MessageBoxW" - the 'W' indicating a Unicode return type. (The ANSI return type version would be "MessageBoxA".) If no "MessageBoxW" were found, THEN the CLR would look for an API function actually called "MessageBox".
Current specifics about the DllImportAttribute class can be found here, where I viewed the .NET Framework 4 version: DLLImportAttribute Class
A key comment in the Remarks section of this .NET Framework 4 page is that:
You apply this attribute directly to C# and C++ method definitions; however, the Visual Basic compiler emits this attribute when you use the Declare statement.
So, in VB.NET, using the Declare statement causes the compiler to generate a DLLImportAttribute.
There is also an important note in this page:
The DllImportAttribute does not support marshaling of generic types.
So, it would appear that if you want to use a generic type, you'd have to use a Declare statement.
Next, I headed to the Declare statement information. A Visual Studio 2010 version (Visual Basic statement info) was here: Declare Statement
A key item here was this note:
You can use Declare only at module level. This means the declaration context for an external reference must be a class, structure, or module, and cannot be a source file, namespace, interface, procedure, or block.
Apparently, if you want to set up an API call outside of a class, structure, or module, you'll have to use the DllImport statement instead of the Declare.
The example Declare statement on this page is:
Declare Function getUserName Lib "advapi32.dll" Alias "GetUserNameA" (
ByVal lpBuffer As String, ByRef nSize As Integer) As Integer
Following that example is this little tidbit of information:
The DllImportAttribute provides an alternative way of using functions in unmanaged code. The following example declares an imported function without using a Declare statement.
followed by, of course, an example of DllImport usage.
Regarding Unicode vs ANSI results, according to this Declare page, if you specify a CharSet value (available in Declare, but not shown in the example above) the CLR will do the same type of automatic name search that DllImport does - for either Unicode or ANSI.
If you do not specify a CharSet value in the Declare statement, then you must make sure that your function name in the Declare is the same as the function name in the actual API function's header file, OR you must specifiy an Alias value that matches the actual function name in the header file (as shown in the example above).
I was not able to find any specific Microsoft documentation stating that either DllImport or Declare were preferred, or even recommended, over one another in any situation other than those noted above.
My conclusion, therefore, is:
Unless you need to place your definition in one of the places a Declare statement cannot be used, either technique will work fine,
and
if you're using DllImport, make sure you specify the CharSet value you want (Unicode or ANSI), or you may get unexpected results.
Declare is really an attempt to maintain a P/Invoke syntax which would be more familiar to Visual Basic 6.0 users converting to VB.NET. It has many of the same features as P/Invoke but the marshalling of certain types, in particular strings, are very different and can cause a bit of confusion to people more familiar with DllImport rules.
I'm not entirely sure what the documentation is alluding to with the "rare" distinction. I use DllImport in my code frequently from both VB.NET and C# without issue.
In general, I would use DllImport over Declare unless you come from a Visual Basic 6.0 background. The documentation and samples for DllImport are much better and there are many tools aimed at generating DllImport declarations.
In my opinion, since this keyword doesn't look deprected, etc. from what I searched, simply use compile-time keywords rather than attributes.
Also, when you use the Declare, you don't need to write the End Function. The advantage of that is that you can create a whole module of declarations of function imports line by line, with no need to pulute your code with DllImports and End Functions.
When you declare using the Declare keyword, the compiler treats this function as Shared anyway, so it can be accessed via other extenal objects.
But I think in the current VB.NET they're both addressed to the same target and no performance difference - no warranty on this one.
So my conclusion is: Do use the Declare instead of DllImport, especially reading what you quoted that Microsoft stated that it should be used in rare cases.
If you need to set one of the following options, then use DllImportAttribute attribute, else use Declare. From https://msdn.microsoft.com/en-us/library/w4byd5y4.aspx
To apply the BestFitMapping, CallingConvention, ExactSpelling,
PreserveSig, SetLastError, or ThrowOnUnmappableChar fields to a
Microsoft Visual Basic 2005 declaration, you must use the
DllImportAttribute attribute instead of the Declare statement.
It is unclear from the above reference only whether this applies to only "Visual Basic 2005" or not, as the above reference is from a .NET 4.5 article. However, I also found this article (https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.dllimportattribute(v=vs.110).aspx ) which is specific to the DllImportAttribute class in .NET 4.5 :
the Visual Basic compiler emits this attribute when you use the
Declare statement. For complex method definitions that include
BestFitMapping, CallingConvention, ExactSpelling, PreserveSig,
SetLastError, or ThrowOnUnmappableChar fields, you apply this
attribute directly to Visual Basic method definitions.
This tells you that the Declare option is VB.net syntactical sugar which is converted to DllImportAttribute at compile time, and outlines the exact scenarios when using DllImportAttribute directly is recommended.