I'm assigned a task to use a DLL file in C#. I have created the DLL file (Prog1210.dll) and have added it as a reference into the Solution explorer in C#. The DLL file has a variable txtNumber1 which is trying to be accessed in this main class.
Just wondering why it recognizes ValidateTextbox in the DLL in this class form, but says it doesn't recognize Prog1210 in the using statement, and doesn't recognize txtNumber1.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Prog1210;
namespace StaticClass
{
class Class1
{
private void btnValidate_Click(object sender, EventArgs e)
{
// Use the ValidateTexbox class that has been added to this project
if (ValidateTextbox.IsPresent(txtNumber1) &&
ValidateTextbox.IsDouble(txtNumber1) &&
ValidateTextbox.IsWithinRange(txtNumber1, 1.0, 100.0))
{
MessageBox.Show("Textbox value is valid!", "Good Data");
}
else
{
// The ValidateTexbox methods assigns an error message to the Tag
// property of the textbox.
string display = (string)txtNumber1.Tag;
MessageBox.Show(display, "Bad Data");
txtNumber1.Focus();
}
}
}
}
My DLL File:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms; // required to work with Textboxes
public static class ValidateTextbox
{
// A class of static methods that will validate data in a textbox.
// An error message is assigned to the Tag property of the textbox.
//******** Empty Textbox Check ****************//
public static bool IsPresent(TextBox textbox)
{
if (textbox.Text == "")
{
textbox.Tag = "A value is required...";
return false;
}
return true;
}
// ******* Valid Data Type Check ***********//
public static bool IsInt(TextBox textbox)
{
try
{
Convert.ToInt32(textbox.Text);
return true;
}
catch (Exception)
{
textbox.Tag = "The value must be an integer...";
return false;
}
}
public static bool IsDouble(TextBox textbox)
{
try
{
Convert.ToDouble(textbox.Text);
return true;
}
catch (Exception)
{
textbox.Tag = "The value must be a double...";
return false;
}
}
public static bool IsDecimal(TextBox textbox)
{
try
{
Convert.ToDecimal(textbox.Text);
return true;
}
catch (Exception)
{
textbox.Tag = "The value must be a decimal...";
return false;
}
}
//*********** Valid Range Check - Overloaded Methods *************//
Just wondering why it recognizes ValidateTextbox in the DLL in this class form, but says it doesn't recognize Prog1210 in the using statement,
This is because your Prog1210.dll didn't use a namespace. If you had specified everything to be in the Prog1210 namespace, it would have worked as you expected.
If you wish to change this, change your DLL code to:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms; // required to work with Textboxes
namespace Prog1210
{
public static class ValidateTextbox
{
// .. your code
}
} // Add closing brace for namespace
and doesn't recognize txtNumber1.
There is no txtNumber1 variable within Class1. You can only validate a TextBox variable which exists in the scope where you call the method.
I guess your DLL was built with C++ or with some other native language. You can't use these kinds of DLLs from a managed assembly/dll.
To work, it would need to be a .NET Assembly/DLL or managed C++/CLI DLL.
If you really can't change that DLL you could wrap it with a C++/CLI DLL. For more information:
Using .NET class from native C++ using C++/CLI as a 'middleware'
You need a namespace in the prog dll and you need to mark the class in your first piece of code as public for txtnumber1. And ensure you have txtnumber1 as the id of a textbox in your form
Related
So I have this DLL and this other thing which I think is refered to as a Injector / loader? It basically loads my DLL into the process of itself so it takes my DLL and loads it into the process of "Injector.exe"
In the example down below it doesnt load it from resources but instead from the desktop, the same thing applies here.
Now sicne it's being loaded it doesnt really call any functions and this is where my problem comes in.
I would like to call some the Messagebox function when the DLL is being loaded.
As far as I know and the most logical way would be to do this in the btnAssemblyLoad_Click event so when the event happens it calls the functions in the DLL.
The issue is I have no idea what this would be called, I read something about "Reflection" but im not sure this is what I would need.
How should I go on about this?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AssemblyLoader
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnBrowse_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
if(ofd.ShowDialog() == DialogResult.OK)
{
tbAssemblyLocation.Text = ofd.FileName;
}
}
private void btnAssemblyLoad_Click(object sender, EventArgs e)
{
AssemblyName an = AssemblyName.GetAssemblyName(tbAssemblyLocation.Text);
Assembly.Load(an);
}
}
}
DLL
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MSgBOxDllCS
{
public class Funcs
{
public void CallMessageBox()
{
MessageBox.Show("Hello");
}
}
}
You would need to call instance method of the non-static class, see below.
// Step 1: load assembly to memory
var an = AssemblyName.GetAssemblyName(tbAssemblyLocation.Text);
var assembly = Assembly.Load(an);
// Step 2: get type from the assembly by name
var type = assembly.GetType("MSgBOxDllCS.Funcs");
// Step 3: get method of the type
var method = type.GetMethod("CallMessageBox");
// Step 4: create instance of the type
var funcs = Activator.CreateInstance(type);
// Step 5: invoke the instance method
method.Invoke(funcs, null);
Generally speaking what you are building is called Plug-In Framework and there is plenty of examples on internet of how it can be done, you may be able to leverage existing frameworks too depending on your requirements.
There are several ways how you can accomplish that.
Load an assembly, create an instance of a class, find the required method using Reflection and invoke it.
var assembly = Assembly.LoadFrom(DllFilePath);
var funcs = assembly.CreateInstance("MSgBOxDllCS.Funcs");
var method = funcs.GetType().GetMethod("CallMessageBox");
method.Invoke(funcs, null);
The same but use a dynamic object, gives less control over reflected members but looks better:
var assembly = Assembly.LoadFrom(DllFilePath);
dynamic funcs = assembly.CreateInstance("MSgBOxDllCS.Funcs");
funcs.CallMessageBox();
And the last but not least, is to extract an interface and put it in a separate shared DLL. This approach would help to get rid of reflection calls and by it's nature is the most reliable:
Common shared DLL:
namespace Shared
{
public interface IFuncs
{
void CallMessageBox();
}
}
DLL to be loaded:
namespace MSgBOxDllCS
{
public class Funcs : Shared.IFuncs
{
public void CallMessageBox()
{
MessageBox.Show("Hello");
}
}
}
Loader:
var assembly = Assembly.LoadFrom(DllFilePath);
var funcs = (Shared.IFuncs)assembly.CreateInstance("MSgBOxDllCS.Funcs");
funcs.CallMessageBox();
I am trying to create a generics in c# web application and using silverlight-5. This i have already implemented in c# console application.
I am trying to do same in webdevelopment using asp.net,c# and silverlight (and GUI using xaml) in Vs-2010. Whose GUI is displayed on internet explorer on running the code (by button click events).
In console application i do so by following code : (The code is to read a binary file as sole argument on console application and read the symbol in that file, These symbol could be int32/int16/int64/UInt32 etc.). So have to make this Symbol variable as "generic"(<T>). And in console application this code works fine.
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace check
{
LINE:1 public class Huffman < T > where T: struct,IComparable < T >,IEquatable < T >
{
public int data_size, length, i, is_there;
public class Node
{
public Node next;
line:2 public T symbol; // This symbol is of generic type.
public int freq;
}
public Node front, rear;
LINE:3 public Huffman(string[] args, Func < byte[], int, T > converter)
{
front = null;
rear = null;
int size = Marshal.SizeOf(typeof (T));
using(var stream = new BinaryReader(System.IO.File.OpenRead(args[0])))
{
long length = stream.BaseStream.Length;
for (long position = 0; position + size < length; position += size)
{
byte[] bytes = stream.ReadBytes(size);
LINE:4 T processingValue = converter(bytes, 0); //**Here I read that symbol and store in processing value which is of type <T>**
//Then further i use this processingValue and "next" varible(which is on Node type)
}
}
}
}
public class MyClass
{
public static void Main(string[] args)
{
line:5 Huffman < long > ObjSym = new Huffman < long > (args, BitConverter.ToInt64);
// It could be "ToInt32"/"ToInt16"/"UInt16"/"UInt32"/"UInt64" with respective
//change in <int>/<short> etc.
//Then i further use this ObjSym object to call function(Like Print_tree() here and there are many more function calls)
ObjSym.Print_tree(ObjSym.front);
}
}
}
The same thing i have to achieve in C# silverlight(web application) with a difference that i have already uploaded and stored the file by button click (By Browsing it)(whereas i was uploading/reading file as sole argument in console application), This file upload part i have already done.
The problem now is how to make this "symbol" variable generic(<T>) here because i am not able to see any Object creation (In main(string[] args) method) where i could pass parameter BitConverter.ToInt32/64/16 (as i am doing in console application, please see code).
NOTE: please see that i have used in LINE 1,2,3,4,5 in my code (so that the same(or different if you have other approach) has to be achieved in the code below to make "symbol" of type )
Because in c# i get body of code like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace check
{
public partial class MainPage : UserControl
{
public class Node
{
public Node next;
public long symbol; // This symbol is of generic type.
public int freq;
}
public Node front, rear;
public MainPage()
{
InitializeComponent();
}
}
}
Could some one please help me in changing the code of this web application exactly similar to that console application code (I mean making "Symbol variable as generic(<T>)")
EDIT: When i do this:
(1) public partial class MainPage <T> : UserControl, IComparable < T > where T: struct,IEquatable < T >
(2) public T symbol; (In Node class)
(3) And all the buttons and boxes i created are given not existing in current context.
then it gives error
Error :The name 'InitializeComponent' does not exist in the current context
Could some one please help me in achieving the same in c# silverlight web application ? Would be a big help,thanks.
Here is a Example.
namespace check
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
// Use the generic type Test with an int type parameter.
Test<int> Test1 = new Test<int>(5);
// Call the Write method.
Test1.Write();
// Use the generic type Test with a string type parameter.
Test<string> Test2 = new Test<string>("cat");
Test2.Write();
}
}
class Test<T>
{
T _value;
public Test(T t)
{
// The field has the same type as the parameter.
this._value = t;
}
public void Write()
{
MessageBox.Show(this._value);
}
}
}
I think you asking this kind of example.
You can use generic as if you don’t use XAML. But if you want to use XAML to define your control, you can’t use generic. That's why the problem is occurs.
Create a another class and use it. I think It's help you.
I have written a class library. To execute methods that I wrote in my class library, I created a console application. In my console application, I added the class library that I wrote as a reference. I then added the appropriate using statement to my console application. My methods from this library are inaccessible currently. Why?
Here's my class library with a basic method. It was created in .NET framework 3.5.
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.DataSourcesGDB;
using ESRI.ArcGIS.Geometry;
namespace RelateTablesValidation
{
[Guid("e1058544-0d84-49be-a406-b4e65707f95b")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("RelateTablesValidation.Validate")]
[ComVisible(true)]
public class Validate : ESRI.ArcGIS.Geodatabase.IClassExtension, ESRI.ArcGIS.Geodatabase.IObjectClassExtension, ESRI.ArcGIS.Geodatabase.IRelatedObjectClassEvents2
{
public void ChangeClassExtension(IObjectClass objectClass, String extensionUID, IPropertySet extensionProperties)
{
ISchemaLock schemaLock = (ISchemaLock)objectClass;
try
{
// Attempt to get an exclusive schema lock.
schemaLock.ChangeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock);
// Cast the object class to the IClassSchemaEdit2 interface.
IClassSchemaEdit2 classSchemaEdit = (IClassSchemaEdit2)objectClass;
if (!String.IsNullOrEmpty(extensionUID))
{
// Create a unique identifier (UID) object and change the extension.
UID extUID = new UIDClass();
extUID.Value = extensionUID;
classSchemaEdit.AlterClassExtensionCLSID(extUID, extensionProperties);
}
else
{
// Clear the class extension.
classSchemaEdit.AlterClassExtensionCLSID(null, null);
}
}
catch (COMException comExc)
{
throw new Exception("Could not change class extension.", comExc);
}
finally
{
schemaLock.ChangeSchemaLock(esriSchemaLock.esriSharedSchemaLock);
}
}
}
Here's my console app. RelateTablesValidation is the class library. Also created in .NET Framework 3.5
using System;
using System.Collections.Generic;
using System.Text;
using RelateTablesValidation;
using Esri.ArcGIS.Geodatabase;
using ESRI.ArcGIS.DatasourcesGDB;
namespace ApplyClassExtension
{
class Program
{
[STAThread()]
static void Main(string[] args)
{
//system sees objects from this namespace OK
IWorkspaceFactory workspaceFactory = new FileGDBWorkspaceFactory();
//now when i try to call my method, it doesn't even show up in Intellisense
ChangeClassExtension(method params would go here);
}
}
}
You can't do what you're trying to do.
All methods in C# are inside of objects. You must either make the method static and call it like this:
Validate.ChangeClassExtension(...);
Or don't make it static and instantiate an instance of Validate:
var val = new Validate();
val.ChangeClassExtension(...);
I'm trying to use a precompiled DLL with reflection, to instantiate an interface for my class that is in the DLL. I tried by the book, but it won't work. It throws InvalidCastException when I try to do something like:
ICompute iCompute = (ICompute)Activator.CreateInstance(type);
Where type of course is my class that implements ICompute interface. I'm stuck and don't know what to do. The complete code follows:
This is the DLL content:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication18
{
public class ClassThatImplementsICompute : ICompute
{
public int sumInts(int term1, int term2)
{
return term1 + term2;
}
public int diffInts(int term1, int term2)
{
return term1 - term2;
}
}
}
The actual program:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace ConsoleApplication18
{
public interface ICompute
{
int sumInts(int term1, int term2);
int diffInts(int term1, int term2);
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Loading dll...");
Assembly assembly = Assembly.LoadFrom("mylib.dll");
Console.WriteLine("Getting type...");
Type type = assembly.GetType("ConsoleApplication18.ClassThatImplementsICompute");
if (type == null) Console.WriteLine("Could not find class type");
Console.WriteLine("Instantiating with activator...");
//my problem!!!
ICompute iCompute = (ICompute)Activator.CreateInstance(type);
//code that uses those functions...
}
}
}
Can anyone help me? Thanks!
The problem is to do with how you load the assembly with Assembly.LoadFrom().
LoadFrom() load the assembly into different context compared to context of the ICompute interface you are trying to cast to. Try to use Assembly.Load() instead if possible. i.e. put the assembly into the bin / probing path folder and load by the full strong name.
Some references:
http://msdn.microsoft.com/en-us/library/dd153782.aspx
http://blogs.msdn.com/b/suzcook/archive/2003/05/29/57143.aspx (see the disadvantage bit for LoadFrom)
I thought I knew how to do this, but obviously not so I'd appreciate some help!
I can't get my dll to register so I can instantiate it in a VBS, or elsewhere.
I wrote the following sample class, checked "Make assembly COM Visible", checked "Register for COM Interop", then built it.
When I try to instantiate it from VBS I get the "Activex component can't create object" error.
This is the class code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Smurf
{
public class Pants
{
public string Explode(bool Loud)
{
string result;
if (Loud)
result = "BANG";
else
result = "pop";
return result;
}
}
}
...and this is the VBS:
Dim a
Set a = CreateObject("Smurf.Pants")
msgbox("ok")
What else do I need to do?
Thanks :)
[edit]
Forgot to mention, after the first failure I tried REGSVR32 and REGASM - no help!
[/edit]
Note that when I try REGSVR32, I get this message:
The Module "C:...\Smurf.dll" was loaded but the entry-point DllRegisterServer was not found.
Make sure that "C:...\Smurf.dll" is a valid DLL or OCX file and then try again.
How helpful is that??
This is the latest version of the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace Smurf
{
[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
public interface IPants
{
[DispId(1)]
string Explode(bool Loud);
}
[Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA71"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IPantsEvents
{
string Explode(bool Loud);
}
[ComVisible(true)]
[Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938"),
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces(typeof(IPantsEvents))]
public class Pants : IPants
{
public Pants() { }
[ComVisible(true)]
[ComRegisterFunction()]
public static void DllRegisterServer(string key) { }
[ComVisible(true)]
[ComUnregisterFunction()]
public static void DllUnregisterServer(string key) { }
[ComVisible(true)]
public string Explode(bool Loud)
{
string result;
if (Loud)
result = "BANG";
else
result = "pop";
return result;
}
}
}
There could be a few different things at play here. First, you'll want to use the regasm tool with the /codebase /tlb switch from an elevated command prompt (assuming Windows Vista, 7 or Windows Server 2008). Something like:
regasm "Path to Smurf.dll" /codebase /tlb
Once you have registered the dll using regasm you should be able to invoke it using VBS, VBA or VB6.
I was able to use early binding and late binding from VBA to call the Explode method. However, when I tried from VBScript I received the "ActiveX can't create object error as you did."
I'm running on Windows 7 64 bit, and I recalled that this can cause problems when compiling to 32 bit dlls and running them on 64 bit operating systems. On a whim, I fired up a command prompt and entered:
C:\Windows\SysWow64\CScript.exe "Path to VBScript"
The result was that the script ran correctly and displayed "Pop" on screen.
Here's the somewhat simplified C# code I used as well as the contents of the VBScript file.
namespace Smurf
{
[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
public interface IPants
{
string Explode(bool Loud);
}
[Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA71"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IPantsEvents
{
string Explode(bool Loud);
}
[ComVisible(true)]
[Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938")]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IPantsEvents))]
public class Pants : IPants
{
[ComVisible(true)]
public string Explode(bool Loud)
{
string result;
if (Loud)
result = "BANG";
else
result = "pop";
return result;
}
}
}
VBScript:
Dim x
Set x = CreateObject("Smurf.Pants")
MsgBox (x.Explode(False))
Set x = Nothing