Ok so I have an assembly, written in C#, using Visual Studio 2010.
This Assembly contains one class, which contains one method which returns the word Result, the code is below:
using System.Runtime.InteropServices;
namespace TestDLL
{
public class Class1
{
[ComVisible(true)]
public string TestMethod()
{
return "Result";
}
}
}
The output section in the Build tab on the properties window looks like so:
When I click on Build, I get a DLL file and a TLB file. I can add this TLB file to Microsoft Access simply by browsing to it.
Now, in Access I have a button and a label. I want to make the Caption property of my label equal to the result of testMethod. I'm thinking I need to do something similar to below but I'm not sure, any help would be much appreciated:
Private Sub btnMain_Click()
Dim tm As TestDLL
Dim foo As String
foo = tm.testMethod
lblBarr.Caption = foo
End Sub
Thankyou
Maybe next will work:
Private Sub btnMain_Click()
Dim tm As TestDLL.Class1
Dim foo As String
Set tm = New TestDLL.Class1
foo = tm.testMethod
lblBarr.Caption = foo
End Sub
Related
I looked at other posts and couldn't find the solution.
I am trying to use C# dll I created in VBA code without having to add reference.
In my VBA code, I declared:
Public Declare Function message Lib "path_to_my_dll" _
(ByVal message As String) As String
Sub Test()
Dim hello As String
hello = message("hi!!")
Debug.Print hello
End Sub
I get an error saying entry point for my dll couldn't be found.
The C# Code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace DLLImport
{
public class Class1
{
[DllImport("DLLImport", EntryPoint = "Run")]
extern string Run(string message)
{
return message;
}
}
}
Thank you in advance for your help!!
You might want to use InteropServices to make a COM Visible DLL
using System.Runtime.InteropServices;
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("your-GUID-1")]
public interface _Visible_Methods
{
//--------< _Visible_Methods >--------
//*visible COM Methods of this Control under Office,Excel, Word
string get_Hello();
//--------</ _Visible_Methods >--------
}
Source: https://codedocu.com/Net-Framework/Controls/COM-ActiveX/Create-C_hash_-COM-Control-for-Office?2382
I have inherited a VB6 app that launches Excel, opens a workbook, and runs a macro on an interval. This macro returns values though its parameters. In my attempts to convert this to C# using interop, I can successfully run the macro, but these parameter values do not get returned.
Is there something missing/incorrect in the code below, or is this simply not supported?
VBA macro:
Sub Foo(bar As Long)
bar = 5
End Sub
C# code:
void CallFoo()
{
// Declared as an object to avoid losing the value in auto-boxing
// The result is the same if declared as int
Object bar = 0;
m_application.Run(m_fooCommand, a);
Console.WriteLine(a); // a is always 0
}
This (roughly) equivalent VB6 code gets the return value just fine.
Dim bar as Long
bar = 0
xlApp.Run "Test.xlsm!Foo", bar
MsgBox bar // prints 5
So as best as I can tell, no, you cannot return values through parameters from VBA to C# in this way. The next best thing is to simply create a type in .NET, make it COM visible, regasm it and then reference that in the VBA script.
So, for completeness...
A return type:
[ComVisible(true)]
[Guid("097B5B52-C73B-4BD0-A540-802D0BC7C49F")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IFooResult
{
int Value { get; set; }
}
[ComVisible(true)]
[Guid("76B6BCBD-6F4D-4457-8A85-CDC48F4A7613")]
[ClassInterface(ClassInterfaceType.None)]
public class FooResult : IFooResult
{
[DispId(1)]
public byte[] Buffer { get; set; }
}
Generate strong name (required by regasm)
sn -k FooLib.snk
Register the assembly
regasm FooLib.dll /tlb:FooLib.tlb /codebase
Then simply reference the library in the VBA project. It can now be passed as an argument and populated in the macro or created in and returned from the macro (I believe this would require cleanup on the .NET side, Marshal.ReleaseComObject()).
So, I'm working on converting this code from VB.NET to C#:
Public Class Form1
Const filesplit As String = "|split|"
Dim stub, opt() As String
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
On Error Resume Next
FileOpen(1, Application.ExecutablePath, OpenMode.Binary, OpenAccess.Read, OpenShare.Shared)
stub = Space(LOF(1))
FileGet(1, stub)
FileClose(1)
opt = Split(stub, filesplit)
End Sub
End Class
I've used a series of online converters, and they don't really work for me.
How do I do it? I'm trying to understand VB.NET source code so I can use it in.
Those methods are in the Microsoft.VisualBasic Namespace.
So you could just add a reference to that in your project and then use virtually the exact same code with a small amount of extra qualification on the methods used:
using Microsoft.VisualBasic; //add this statement
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
string filesplit = "|split|";
string stub;
string[] opt;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
FileSystem.FileOpen(1, Application.ExecutablePath, OpenMode.Binary, OpenAccess.Read, OpenShare.Shared);
stub = Strings.Space(Convert.ToInt32(FileSystem.LOF(1)));
FileSystem.FileGet(1, ref stub);
FileSystem.FileClose(1);
opt = Strings.Split(stub, filesplit);
}
}
}
However you should really look into using the File.xxx methods in the System.IO namespace in both your VB.NET and C# code going forward, but this will get it working for you.
Use File.Open. That should get you what you want.
Your VB code is essentially doing this:
// The using clause ensures the StreamReader is properly disposed after the closing block.
using (StreamReader sr = File.OpenText(Application.ExecutablePath))
{
stub = sr.ReadToEnd();
opt = stub.Split(filesplit).ToArray();
}
This assumes filesplit is a char, string or something like Environment.NewLine
Basically you would use :
Dim content = File.ReadAllText("c:\temp\MyTest.txt")
However it would be more correct to use:
Dim path As String = "c:\temp\MyTest.txt"
If File.Exists(path) Then
Dim content = File.ReadAllText(path)
Rem do something with content
End If
I have an application that uses Process.Start to execute an exe. It works fine for all the .exe that I have tested except when the .exe has a configuration file where it gets a connectionstring, when this happens I get a System.NullReferenceException. this is my code.
to execute the exe:
string eucApp = #"C:\Temp\app.exe"
startInfo = new ProcessStartInfo(eucApp);
using (Process execProcess = Process.Start(startInfo))
{
execProcess.WaitForExit();
}
then the exe starts and the first thing that does is get the a connection string with this code line
strCadena = ConfigurationManager.ConnectionStrings("ConnectionString")
If I replace this with the connectionstring like this, it works fine
strCadena = "Data Source=HostName;Initial Catalog=MyDB;Integrated security=True"
I would remove the config file and put its values into the .exe code but the trouble is that I have more than 500 .exe's that uses config files so if any one knows a way to avoide this please tell me!
thanks for your help. I figured out the problem. Somehow the .exe was pointing to the app.config of the aplication that start's the process. I added this class to the .exe that is developed in VB .Net
Imports System.Configuration
Imports System.Reflection
Public Class AppConfig
Implements IDisposable
Public Shared Function Change(ByVal path As String) As AppConfig
Return New ChangeAppConfig(path)
End Function
Public Overridable Sub Dispose() Implements IDisposable.Dispose
End Sub
Private Class ChangeAppConfig
Inherits AppConfig
Private ReadOnly oldConfig As String = AppDomain.CurrentDomain.GetData("APP_CONFIG_FILE").ToString
Private disposedValue As Boolean
Public Sub New(ByVal path As String)
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", path)
ResetConfigMechanism()
End Sub
Public Overrides Sub Dispose()
If (Not disposedValue) Then
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", oldConfig)
ResetConfigMechanism()
disposedValue = True
End If
GC.SuppressFinalize(Me)
End Sub
Private Shared Sub ResetConfigMechanism()
GetType(ConfigurationManager).GetField("s_initState", BindingFlags.NonPublic Or BindingFlags.Static).SetValue(Nothing, 0)
GetType(ConfigurationManager).GetField("s_configSystem", BindingFlags.NonPublic Or BindingFlags.Static).SetValue(Nothing, Nothing)
Dim assemblies() As Type = GetType(ConfigurationManager).Assembly.GetTypes()
For Each assembly As Type In assemblies
If (assembly.FullName = "System.Configuration.ClientConfigPaths") Then
assembly.GetField("s_current", BindingFlags.NonPublic Or BindingFlags.Static).SetValue(Nothing, Nothing)
Exit For
End If
Next
End Sub
End Class
End Class
I call Change function at the begining of the program
AppConfig.Change(Application.StartupPath & "\app.exe.Config")
This way it take the right config file
I have a class library that is nested two+ layers under a main GUI application, within that nested class library I want to be able to access the main applications name.
Under .Net 3.5 you could call Application.ProductName to retrieve the value from the Assembly.cs file, but I cannot identify an equivalent in WPF. If I use reflection and GetExecutingAssembly then it returns the class libraries details?
Thanks
You can use Assembly.GetEntryAssembly() to get the EXE assembly, and can then use Reflection to get the AssemblyProductAttribute from that.
This assumes that the product name has been set on the EXE assembly. The WinForms Application.ProductName property actually looked in the assembly containing the main form, so it works even if the GUI is built in a DLL. To replicate this in WPF you would use Application.Current.MainWindow.GetType().Assembly (and again use Reflection to get the attribute).
Here is another solution that I am using to get the Product Name
Public Shared Function ProductName() As String
If Windows.Application.ResourceAssembly Is Nothing Then
Return Nothing
End If
Return Windows.Application.ResourceAssembly.GetName().Name
End Sub
in wpf there are many way to do this ,
here you can find two of this.
using System;`
using System.Windows;
String applicationName = String.Empty;
//one way
applicationName = AppDomain.CurrentDomain.FriendlyName.Split('.')[0];
//other way
applicationName = Application.ResourceAssembly.GetName().Name;
If you need to get the descriptive product name as I did, then this solution may be useful:
// Get the Product Name from the Assembly information
string productName = String.Empty;
var list = Application.Current.MainWindow.GetType().Assembly.GetCustomAttributes(typeof(AssemblyProductAttribute), true);
if (list != null)
{
if (list.Length > 0)
{
productName = (list[0] as AssemblyProductAttribute).Product;
}
}
It returns whatever you've set for the 'AssemblyProduct' attribute in the AssemblyInfo.cs file, e.g. something like "Widget Engine Professional".
Based on the answers above, this works just great immediately:
var productName = Assembly.GetEntryAssembly()
.GetCustomAttributes(typeof(AssemblyProductAttribute))
.OfType<AssemblyProductAttribute>()
.FirstOrDefault().Product;
If you are looking for the values provided by the assembly information, e.g. the title...
... then you have to get the custom attributes like this:
using System.Linq;
using System.Reflection;
using System.Windows;
namespace WpfApp1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Title = (Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute)).SingleOrDefault() as AssemblyTitleAttribute)?.Title;
}
}
}
The answer you require is:
Path.GetFileName(Assembly.GetEntryAssembly().GetName().Name)