|
If they are static functions, then create a new Module (Project > Add Module...) and place them in there as Public Shared (Sub|Function) .
-Greg
|
|
|
|
|
Hi,
I'am updating and old VB6 project to VB.net 2008.
My old project uses a Win32 Dll and TLB file to shared types.
From VB6 a reference is created to TLB file and interop works fine.
From VB.net I can import TLB file successfully and types are accessibles, but not the functions.
Using 'Declare Function' sentences to import DLL methods, I can access to DLL functions.
My Win32 DLL has methods that uses LPSAFEARRAY pointer as input parameters.
This is the declaration of one of this functions on DLL:
extern NOMANGLE short CCONV EncenderLEDs(LPSAFEARRAY *CBLeds, bool Estado);
To reference this from VB.net I write
Public Declare Function EncenderLEDs Lib "MonAuto.dll" (<MarshalAs(UnmanagedType.SafeArray)> ByRef CBLeds() As CBTipo, ByVal Estado As Boolean) As Integer
CBTIPO is defined on DLL as:
typedef struct{
short Carta;
short Borna;
} CBTipo;
The type is correctly visible at VB.net after TLB is imported.
I test the function with next code:
Dim CBLeds() as CBTipo
Redim CBLeds(4)
CBLeds(0).Borna = 0
CBLeds(0).Carta = 0
EncenderLEDs(CBLeds, False)
An exception is reported:
(Exception of HRESULT: 0x8002802B (TYPE_E_ELEMENTNOTFOUND))
But if I use any single Type to create the array: Int32, Double, Single, byte, ... and modify the declaration function definition on Vb.net like:
Public Declare Function EncenderLEDs Lib "MonAuto.dll" (<MarshalAs(UnmanagedType.SafeArray)> ByRef CBLeds() As Integer, ByVal Estado As Boolean) As Integer
and modify the test in the same way:
<pre>Dim CBLeds() as Integer
Redim CBLeds(4)
CBLeds(0).Borna = 0
CBLeds(0).Carta = 0
EncenderLEDs(CBLeds, False)</pre>
Then the call is processed good.
The question is, How must be defined a DLL Win32 function on VB.net that uses a LPSAFEARRAY * as input parameter, to send a userdefined type array ?
I've tried:
Public Declare Function EncenderLEDs Lib "MonAuto.dll" (<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VarEnum.VT_USERDEFINED)> ByRef CBLeds() As CBTipo, ByVal Estado As Boolean) As Integer
and fails too.
Regards in advance
|
|
|
|
|
Very beautiful question.
LPSAFEARRAY is a pointer itself, so LPSAFEARRAY* is a pointer to pointer declaration. This is what I would try:
Public Declare Function EncenderLEDs Lib "MonAuto.dll" (cbLeds() As IntPtr, estado As Boolean) As Integer)
Your first array initialization is ok, but in order to pass it to that function, you should first pin the objects in the managed heap, create the IntPtr array with their addresses and pass this array. This is very similar to another question I answered in C# forum[^] some time ago, so let me bring it to you with some of the required changes. It is still C#. I will not convert it to VB becouse I do not feel comfortable enough with this language, and I could end up with a little mess.
GCHandle[] handleArray = new GCHandle[cbLeds.Length];
for (int i=0; i<cbLeds.Length; i++)
handleArray[i] = GCHandle.Alloc(cbLeds[i], GCHandleType.Pinned);
IntPtr[] pointers = (from GCHandle handle in handleArray select
handle.GetAddrOfPinnedObject()).ToArray();
int ret = EncenderLEDs(pointers, false)
foreach (GCHandle handle in handleArray)
handle.Free();
Please, let us know if it worked.
|
|
|
|
|
No good result.
The translated code to VB is:
Dim CBLeds(4) As CBTipo
CBLeds(0).Borna = 0
CBLeds(0).Carta = 0
Dim handleArray(4) As GCHandle
For i As Integer = 0 To CBLeds.Length - 1
handleArray(i) = GCHandle.Alloc(CBLeds(i), GCHandleType.Pinned)
Next i
Dim pointers() As IntPtr = (From handle As GCHandle In handleArray Select handle.AddrOfPinnedObject()).ToArray()
Dim ret As Integer = EncenderLEDs(pointers, False) ' Release the handlesforeach (GCHandle handle in handleArray) handle.Free();
For Each handle As GCHandle In handleArray
handle.Free()
Next
When I Call the DLL function, the process operates normally (no exception appears) but DLL function not executes correctly.
Below you can see the code at EncenderLeds function.
I'm getting the Ubound and Lbound of array to verify that this is passed good.
The return of SafeArrayGetLBound is DISP_E_BADINDEX 8002000B
The return of SafeArrayGetUBound is DISP_E_BADINDEX 8002000B
So execution is failed.
NOMANGLE short CCONV EncenderLEDs(LPSAFEARRAY *CBLeds, bool Estado)
{
CBTipo HUGEP *Leds;
long LBound, UBound;
DWORD BytesWritten;
DATA Adat[256];
short ActAdat=0;
short nLed;
int j;
USHORT ErrorCnt;
char Cadena[200];
for(unsigned char i=0;i<128;++i)
{
Adat[i].Address = 0;
Adat[i].Data = 0;
Adat[128+i].Address = 0;
Adat[128+i].Data = 0;
}
int k,l;
k=SafeArrayGetLBound(*CBLeds,1,&LBound);
l=SafeArrayGetUBound(*CBLeds,1,&UBound);
sprintf(Cadena,"Valores %x %x %d %d",k,l,LBound,UBound);
MessageBox(NULL,Cadena,"Titol",0);
return 0;
}
Any Idea what is happen?
|
|
|
|
|
The fact that you do not get a runtime exception while running it makes me think that the function is correctly imported, and the IntPtr array along with all the other stuff regarding the GCHandle structure is fine as well. However, looking at the documentation for SafeArrayGetLBound function, I think we were missing something important. It says the array descriptor must have been created with SafeArrayCreate function. I am not used to manage this kind of pointers so I cannot be sure of this, but maybe we should also import SafeArrayCreate function and use it to create the array descriptor before passing it to the EncenderLEDs function. Does it make sense?
|
|
|
|
|
May be logic, but calling DLL from VB6 no safearray creation is needed.
I will continue investigating. If I find a solution, I tell you.
Regards.
|
|
|
|
|
Yes, you are right, but remember arrays in VB6 were allocated as SAFEARRAY under the covers, and that is quite a different thing than .NET arrays, and it seems you are using VB.NET.
|
|
|
|
|
Sure.
But the DLL is now compiled on VS2008.
Reading about safearrays and thinking about your suggest, I've find an assembly named system.visualstudio.ole.interop on VS2008 help that implements Safearray struct.
I'll try to use it, but from now, I can't load the assembly.
It doesn't appear on Net list references, but it is present on Windows\assembly.
If I achieve to load it, I tell you about.
Regards.
|
|
|
|
|
Hi,
I wonder if anyone can help me.
I am setting a VB.Net (2008) with Crystal Reports (ver 10) deployment to go onto other PCs.
I have done this before but for some reason, getting a CrystalDecisions.Shared problem when I try and view a report on another PC. I have included in the project
Crystal_database_access2003.msm
Crystal_database_access2003_enu.msm
Crystal_managed2003.msm
Crystal_regwiz2003.msm
I have also made sure I have the correct licence key. This has got me baffled. I have properly missed something simple out or done something wrong this time.
|
|
|
|
|
Hi All,
I have a program where I dynamically create some Textboxes within a Panel on my form using this code
Panel1.Controls.AddRange(New System.Windows.Forms.Control() {TextBoxes(num - 1)})
These textboxes are automatically labeled Layer1, Layer2 etc etc.. Everything works fine.
I also have a listbox that contains the names of these dynamically created "Layers". What I want to do is when I click on the name in the listbox I want to "select" (or set the focus) on that particular dynamic control.. but I don't know how to reference it, as it's dynamic lol.
Any help would be MUCH appreciated, thanks!
|
|
|
|
|
Use its name as you have it:
Dim c as Control = Panel1.Controls[name];
Where "name" would be a string variable containing the name of the control.
Edit: Sorry, my first reply was written in C#, not VB.
|
|
|
|
|
Thanks heaps for that Erik, it worked!! Top job
|
|
|
|
|
I have problems with transparent form, can anyone help?
problem is that its too slow
example if i click on button where it should just switch another panel control it takes 3-4 secconds because of redrawing
Class: http://pastesite.com/22086[^]
On Form: http://pastesite.com/22087[^]
so at form load is called redraw() and if i click on a button and panel is switched i again call redraw()
form load 6 second
switching panels 3-4 seconds
thank you
|
|
|
|
|
I am writing Windows service with FileSystemWatcher.
Protected Overrides Sub OnStart(ByVal args() As String)
fw = New StreamWriter(LogPathFile)
fsw = New FileSystemWatcher
If args.Length > 0 Then
' the path to monitor has been specified in the argument passed in at Start
fsw.Path = args(0)
Else
fsw.Path = My.Settings.PathToWatch
End If
fsw.IncludeSubdirectories = False
fsw.Filter = "*.*"
AddHandler fsw.Created, New FileSystemEventHandler(AddressOf File_Created)...
Public Sub File_Created(ByVal obj As Object, ByVal e As FileSystemEventArgs)...
How can I check on start if My.Settings.PathToWatch had any files and then call for each file File_Created event?
|
|
|
|
|
Please do not ask the same question in more than one forum. Very naughty.
Decide where it fits best and just ask there.
Henry Minute
Do not read medical books! You could die of a misprint. - Mark Twain
Girl: (staring) "Why do you need an icy cucumber?"
“I want to report a fraud. The government is lying to us all.”
I wouldn't let CG touch my Abacus!
When you're wrestling a gorilla, you don't stop when you're tired, you stop when the gorilla is.
|
|
|
|
|
Because your turning on filesystemwatcher after the fact, you will need to handle the startup manually by getting the list of files in the directory and calling the routine for each file. Then start the filesystemwatcher.
'Never argue with an idiot; they'll drag you down to their level and beat you with experience.' ~ anonymous
'Life's real failure is when you do not realize how close you were to success when you gave up.' ~ anonymous
|
|
|
|
|
Is there anybody who knows how to use google map in vb.net application for route optimization?
Thanks in advance
|
|
|
|
|
Google Directions API[^]
Have a look at that it might help you. You end up get through HTTP a XML Data string and have to build up from there
As barmey as a sack of badgers
Dude, if I knew what I was doing in life, I'd be rich, retired, dating a supermodel and laughing at the rest of you from the sidelines.
|
|
|
|
|
ejaz_pk wrote: Is there anybody who knows how to use google map in vb.net application for route optimization?
As a sidenote, you might want to work through their terms;
5.2 Account Key. After supplying Google with your account information and the URL of your Maps API Implementation, and accepting the Terms, you will be issued an alphanumeric key assigned to you by Google that is uniquely associated with your Google Account and the URL of your Maps API Implementation. Your Maps API Implementation must import the Google Maps APIs using this key as described in the Maps APIs Documentation, and Google will block requests with an invalid key or invalid URL. You may only obtain and use a key in accordance with these Terms and the Maps APIs Documentation.
Point 9 and 10 could be important too, depending on the circumstances.
I are Troll
|
|
|
|
|
Thanks for your reply.
Actually my next step is how to put marks on different location on the map?
Thanks in advance
Ejaz
|
|
|
|
|
ejaz_pk wrote: Actually my next step is how to put marks on different location on the map?
No, your next step is research. Markers are described here[^].
I are Troll
|
|
|
|
|
Thanks for the reply.
Is there a way to calculate the fastest route between multiple routes?
Thanks in advance
Regards,
Ejaz
|
|
|
|
|
Yup, multiple. I took the simple approach, and let the computer calculate each distance for all possible routes - assuming that the shortest one would be the fastest. Worked quite reasonably. You can find more advanced solutions by Googling for "Travelling Salesman Problem".
Good luck
I are Troll
|
|
|
|
|
Can you please give me any sample code to get any idea to get the distance and fastest route?
Thanks in advance
|
|
|
|
|
ejaz_pk wrote: Can you please give me any sample code to get any idea to get the distance and fastest route?
I'm sorry, but the code is copyrighted and not mine to give. I'd have turned it into an article if it wasn't Would also have been too much to post as a copy&paste sample.
Simplest solution is to measure all possible distances. That requires you to build a tree with all possible routes. The root would be your startingpoint, and if you can move to two new points from there, you'd add those as children - recursively.
Once you have all possible routes, you'd have to measure how long it is, or request it's length over some third-party. If need be free, you can use the database from Geonames.org, and calculate the length of a straight line connecting each point. You'd have to account for the earth being a big round ball, but there are formulas[^] out there that return you a length of a line on a ball. Once you have written all lengths into the tree, you find the one that gives the shortest value.
That's a simplistic algorithm that'll generate relatively satisfying results. A more complicated algorithm like Dijkstra's would be an improvement. You can also improve on this by getting "real" distances from Google for the distance between two points - but that's going to cost money if you're going to do it in bulk.
Good luck
I are Troll
|
|
|
|