I'm testing and trying to understand how to create a DLL and call a function from it in my Silverlight project. I'm getting an exception: Unable to find an entry point named 'WriteTextFile' in DLL 'C:\temp\TestDLL.dll'. So I'm doing something wrong.
Here is my code for the very simple DLL:
Imports System.IO
Public Class Class1
Private Shared dir As String = "C:\TEMP"
Private Shared file As String = "TestDLL.txt"
Public Shared Sub WriteTextFile()
Using wr As New StreamWriter(System.IO.Path.Combine(dir, file))
wr.WriteLine("Call to function WriteTextFile()")
End Using
End Sub
End Class
And this is what I'm doing in my Silverlight:
Imports System.Runtime.InteropServices
Partial Public Class MainPage
Inherits UserControl
<DllImport("C:\temp\TestDLL.dll")> _
<AllowReversePInvokeCalls()> _
Friend Shared Sub WriteTextFile()
End Sub
Public Sub New()
InitializeComponent()
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click
WriteTextFile()
End Sub
End Class
I need some pointing to the right direction here :)
The AllowReversePInvokeCalls part is just something I tried out after doing some reading around the web but it didn't change anything. Also I've tried to set the EntryPoint in the DLLImport but that doesn't do anything either.
Edit:
I tried this DLL and pinvoke in regular WPF application and I get the same error so this is not related to Silverligth. Maybe in my DLL then?
Ok, so it looks like this can't be done simply because using pinvoke requires a standard dll and I can't do those with VB .NET. So I'll need to try something else :)
If anyone has more information about this and like to share it I would appreciate that. Or correct me if I've understood the issue wrong.
Related
I have a few modules and classes that I need to init themselves once added to the project.
I'm looking for a method mechanism to call a routine(or something) during startup, without explicitly calling it.
I tried the following, with the hope that being MyInit public, will be initialized upon start.
Optimization is preventing creation of MyInit until the first reference.
Partial Public Module InitModule
public MyInit As New MyStart()
Public Class MyStart
Public Sub New()
Debug.Writeline("Yes, init is executed")
End Sub
End Class
End Module
I have a few modules that can be added/linked to multiple projects; when included they provide trace, code verification, version control etc. The idea is that to add or remove, the main code need no changes.
It doesn't matter is if it's a class, sub or function: I want this to run without explicit call.
Thanks #Jimi for his hint
On each module I can add this partial snippet, extending MyApplication class and using the Startup event to do the initialization.
This can be repeated multiple times and me.Startup will be cascaded as needed.
The drawback: MyApplication is available on windows forms only.
#if TARGET="winexe" then
Namespace My
Partial Friend Class MyApplication
Private Sub MyApplication_Startup(ByVal sender As Object, ByVal e As ApplicationServices.StartupEventArgs) Handles Me.Startup
My.Application.Log.WriteEntry($"Application start {My.Computer.Clock.ToString}")
' init module stuff
'...
End Sub
End Class
End Namespace
#end if
Update
I found a very easy and straightforward code that works with all targets and not just winexe (forms)
The idea is to force the creation of the class at initialization:
friend _startup_init as new startup_init with {.name="test"}
friend class startup_init
public name as string
public sub new()
'... do here your init,
' in my case a few addhandler to hook the master process
end sub
end class
I have created a "Empty Project(.NET Framework) Visual Basic"
I then added an empty Class object
Next I added the reference to System.Windows.Forms
And put the following code in the Class to make it an ApplicationContext
Imports System.Windows.forms
Public Class Class1
Inherits ApplicationContext
End Class
Lastly I tried setting the Startup Object to my Class1
However that is not an option ?
I tried adding a Sub Main to my Class1
but this had no effect
Imports System.Windows.forms
Public Class Class1
Inherits ApplicationContext
Sub main()
End Sub
End Class
At this point, hitting start fails with this error
Error BC30737 No accessible 'Main' method with an appropriate signature was found in 'Project4'.
At this point I could add a module with the following code
and that would compile without errors and run
Module Module1
Sub main()
End Sub
End Module
But that runs for an instant and terminates
In another similar program I have made, I know I could put the following code in a module instead
Module Module1
Public myClass1 As Class1
Sub main()
myClass1 = New Class1
Application.Run(myClass1)
End Sub
End Module
And that would run until I called Application.Exit()
However in this specific case, the Application Framework is disabled so this solution does not work.
So another solution I have found is to use Sleep(50) in a while loop
Imports System.Threading
Module Module1
Public myClass1 As Class1
Sub main()
While True : Thread.Sleep(50) : End While
End Sub
End Module
While I cannot find anything explicitly wrong with this, it strikes me as very inelegant.
It doesn't consume noticeable cpu time or memory
I just wonder if there isn't an equivalent way to do that using just ApplicationContext and dispose of the module entirely ?
If you have any suggestion I would love to hear them at this point.
I wrote this hoping to find a solution as I write the question but I am stuck at this point.
Where does the code go after Application.Run(myClass1)
It's probably looping something inoffensive while waiting for something to happen but what ?
thanks
Here is how to make the barest bone (console or non-console) application using the ApplicationContext Class.
In Visual Studio create a "Empty Project(.NET Framework) Visual Basic"
then add an empty class
Add the following reference by right-clicking on Reference in the Solution Explorer
System.Windows.Forms
Now paste the following code in your class
Imports System.Windows.Forms
Public Class Class1
Inherits ApplicationContext
Shared Sub Main()
Dim myClass1 As Class1
myClass1 = New Class1
System.Windows.Forms.Application.Run(myClass1)
End Sub
End Class
Now hit start and you've got a perfectly working useless application that does nothing with least amount of stuff that I could manage.
If you are here, I suspect that you also would like to manually compile this project from anywhere without having visual studio installed.
Very easy ! In your project folder, create a text file and rename it compile.bat
Paste this code in compile.bat
path=%path%;c:\windows\microsoft.net\framework\v4.0.30319
VBC /OUT:bin\Debug\app.exe /imports:System.Windows.Forms /T:winexe *.vb
pause
BONUS ROUND
This app does nothing, how do you know the events even work ?
Let's add, a tray icon, a resource file to add the tray icon and some events
First add a new reference to system.drawing
Go to project properties
Create a new resource file
Add some random *.ico file
Now replace the following code in the class
Imports System.Windows.Forms
Public Class Class1
Inherits ApplicationContext
Shared Sub Main()
Dim myClass1 As Class1
myClass1 = New Class1
System.Windows.Forms.Application.Run(myClass1)
End Sub
Private WithEvents Tray As NotifyIcon
Public Sub New()
Tray = New NotifyIcon
Tray.Icon = My.Resources.appico
Tray.Text = "Formless tray application"
Tray.Visible = True
End Sub
Private Sub AppContext_ThreadExit(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles Me.ThreadExit
'Guarantees that the icon will not linger.
Tray.Visible = False
End Sub
Private Sub Tray_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles Tray.Click
Console.WriteLine("Tray_Click")
End Sub
Private Sub Tray_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles Tray.DoubleClick
Console.WriteLine("Tray_DoubleClick")
System.Windows.Forms.Application.Exit()
End Sub
End Class
And now, to compile this manually
First, find resgen.exe somewhere on your harddrive
and copy it in your "My Project" folder, you can probably download it from somewhere
Make sure you've got version 4 or above of resgen though
And overwrite the compile.bat with this new code
path=%path%;c:\windows\microsoft.net\framework\v4.0.30319
cd "My Project"
resgen /usesourcepath "Resources.resx" "..\bin\debug\Resources.resources"
cd ..
VBC /OUT:bin\Debug\app.exe /resource:"bin\debug\Resources.resources" /imports:System.Drawing,System.Windows.Forms /T:winexe *.vb "My Project\*.vb"
pause
Unfortunately, this last compile.bat doesn't work for me, it might work for you.
Mine compiles just fine, but the app crashes on start.
This worked in another project where I made the Resource files by hand but something is wrong with
I tried adding the root namespace to the build with /rootnamespace:Project5 but this had no effect
Still good enough for now, this last bit will be edited if a fix is ever found
Is it possible to create a subroutine in a VB.Net exe that is callable from another program(not VB.Net)? I am aware that you can do this with an assembly(dll), but can you do this in an exe as well?
[Edit]This VB.Net exe will already be running when called.
[Edit2] VB.Net program, these compile to become BA_SyncNet.exe - Form1.vb
Public Class Form1
...
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
...
End Sub
End Class
VB.Net program - Helloworld.vb
Namespace MapInfoBA.MiProBA.SamplesBA
Public Class HelloWorld
Public Shared Sub SayHello(ByVal s As String)
System.Windows.Forms.MessageBox.Show("Hello, " + s)
End Sub
End Class
End Namespace
Calling program ba.mbx uses:
Declare Method SayHello Class "MapInfoBA.MiProBA.SamplesBA.HelloWorld" Lib "BA_SyncNet.exe" (ByVal strName As String)
Sub Main()
Call SayHello("World")
End Sub
Kind Regards
I am aware that you can do this with an assembly
An .exe is a kind of assembly. So, yes.
Create a file (let's say, DoThisVBNet.txt) using MapBasic program.
Then your vb.net program checks the file from time to time.
The vb.net program will do a task (in your case, call a subroutine) based on the DoThisVBNet.txt file.
However,
Problem may occur on accessing the file since two programs are using it,
to fix this, use Registry instead of File.
I hope this isn't a stupid question, I can't find a reasonable answer on google.
I'm starting a project which only contains one class file. I will be turning the class file into a dll at the end. I understand that another app normally makes calls to the dll once it's referenced in the project. I need the dll to run a sub inside of it on load like a normal mybase.load sub. This sub needs to execute only once on load to populate some variables. I don't want to have to call the sub from the main app. The rest of the functions/subs in the dll will be called from the main app when needed. Please don't respond with register them globally under the class, I need a sub or function.
If there isn't such a sub how would I go about creating a function/sub that preforms an onload?
Thanks. :)
Hope I'm making sense. Thanks for your response.
Shared Sub New()
on your class.
Another option is to have a private class inside your class and initialise it with a member variable:
Public Class MyLibraryClass
Private mobjSettings As New SettingsClass
Public Function SampleLibraryFunction() As String
Return mobjSettings.SettingsProperty
End Function
Private Class SettingsClass
Friend SettingsProperty As String
Sub New()
'initialise
SettingsProperty = "This is a test"
End Sub
End Class
End Class
I've created an add-in for outlook 2010. I have a ribbon that has a button on it. When you click that button, I want it to call a procedure in the ThisAddIn.vb.
There are two files: ThisAddin.vb and Ribbon.vb.
I've tried several things to no avail. I've also set all the procedures to public.
Call Testing123()
Call ThisAddIn.Testing123()
Etc
How do I properly call this procedure?
****Ribbon1.vb****
Imports Microsoft.Office.Tools.Ribbon
Public Class MyOutlookTab
Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs) Handles Button1.Click
Call Testing123()
End Sub
End Class
***ThisAddIn.vb***
Public Class ThisAddIn
Public Sub Testing123()
System.Windows.Forms.MessageBox.Show("It Works!")
End Sub
End Class
The problem is that you are trying to reference class methods without creating a class.
You have three options to make this work:
1) Convert ThisAddIn to a Module. Then there won't be any issues accessing the Testing123 method as you currently have it.
2) Convert ThisAddin.Testing123 to a Shared method, i.e.:
Public Shared Sub Testing123()
Then you would access as follows:
Call ThisAddin.Testing123()
3) Create an instance of the ThisAddIn class prior to using its methods:
Dim oAddIn As New ThisAddIn
Call oAddIn.Testing123()
Update
It appears that addins are treated differently that standard classes.
This MSDN article contains specific implementation guidance for accessing AddIn functionality from other types of solutions.
Based on this article, you need to take a couple of additional steps:
1) Create an interface to expose the functionality from your AddIn:
<ComVisible(True)> _
Public Interface IAddInUtilities
Sub Testing123()
End Interface
2) Add a utilities class to your addin project:
<ComVisible(True)> _
<ClassInterface(ClassInterfaceType.None)> _
Public Class AddInUtilities
Implements IAddInUtilities
Public Sub Testing123() Implements IAddInUtilities.Testing123
System.Windows.Forms.MessageBox.Show("It Works!")
End Sub
End Class
3) Add the following to ThisAddIn to expose the utilities to external callers:
Private utilities As AddInUtilities
Protected Overrides Function RequestComAddInAutomationService() As Object
If utilities Is Nothing Then
utilities = New AddInUtilities()
End If
Return utilities
End Function
4) I am a little unclear on the exact syntax needed for the last step since I don't have automation installed in office, but you will need to do something along these lines:
' OutlookTest should be changed to the name of the project ThisAddIn is in
Dim addIn As Office.COMAddIn = Globals.ThisAddIn.Application.COMAddIns.Item("OutlookTest")
Dim utilities As OutlookTest.IAddInUtilities = TryCast( _
addIn.Object, OutlookTest.IAddInUtilities)
utilities.Testing123()
Thanks for everyones comments but I found the solution in an example here: http://msdn.microsoft.com/en-us/library/ee620548.aspx where they talk about adding a ribbon to the meeting request (2/3's of the way down).
It's actually quite simple. You call the procedure using the "Global"
Globals.ThisAddIn.Testing123()
Nothing else is needed.
You have to create a new instance of the class before you can call it in vb.net!
So something like should allow you to call it..
Public Class MyOutlookTab
Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs) Handles Button1.Click
Dim testing As New ThisAddIn()
Call testing.Testing123()
End Sub
End Class