How to implement Interface to an abstract class which is constraint? - c#

A few days ago I've tried to use (reference) a QRCode library .net with no interface in ms access vba unsuccesfully. So I did some research and people here guided me.
So I decided to make the interface I followed this steps
https://whoisburiedhere.wordpress.com/2011/07/12/creating-a-com-object-from-scratch-with-c/
I've been able to see the intellisense and create some of the objects and variables of other classess but I'm trouble with a class in which I see the Dispose() but I can't use the New in ms access:
[Dim QRCD as New QRCode]
I get an error the use of New is not valid but I can declare with the line:
Dim QRCD as QRCode
[I think that's not an object{ If I try to make it equals to QRData "That is no permited" error kicks in}] that class implements an abstract class which has constraints I've tried to put the interface in the abstract class and I get the error "Does not implement the method" if I put it in the Child class I can't create an object neither see any of the methods with the late binding.
The QRCoder library can be found here.
https://github.com/codebude/QRCoder
This is the abstract class as it's provided.
{
using System;
public abstract class AbstractQRCode<T>
{
protected QRCodeData qrCodeData;
protected AbstractQRCode(QRCodeData data)
{
qrCodeData = data;
}
public abstract T GetGraphic(int pixelsPerModule);
}
}
This is the child class that implements it; it's already modified with the interface. Is not all the code but down are several methods all called GetGraphic(something as something) which are different from one another.
[ComVisible(true)]
[Guid("It's filled in the program"), InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface neker
{
Bitmap GetGraphic(int pixelsPerModule);
}
[ComVisible(true)]
[Guid(""), ClassInterface(ClassInterfaceType.AutoDual)]
public class QRCode :AbstractQRCode<Bitmap>, IDisposable, neker
{
public QRCode(QRCodeData data) : base(data) {}
public override Bitmap GetGraphic(int pixelsPerModule)
{
return GetGraphic(pixelsPerModule, Color.Black, Color.White, true);
}
public Bitmap GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, bool drawQuietZones = true)
{
return GetGraphic(pixelsPerModule, ColorTranslator.FromHtml(darkColorHtmlHex), ColorTranslator.FromHtml(lightColorHtmlHex), true);
}
This is the sample code (also provided)
QRCodeGenerator qrGenerator = new QRCodeGenerator();
QRCodeData qrCodeData = qrGenerator.CreateQrCode("The text which should be encoded.", QRCodeGenerator.ECCLevel.Q);
QRCode qrCode = new QRCode(qrCodeData);
Bitmap qrCodeImage = qrCode.GetGraphic(20);
This is my code in VBA [This is in a Module]
Public Sub QRCreator(QRtext As String)
Dim QRCG As QRCoder.QRCodeGenerator
Set QRCG = New QRCoder.QRCodeGenerator
Dim QRCD As QRCodeData
Set QRCD = QRCG.CreateQRCode(QRtext, ECCLevel_Q, False)
Dim QRCO As QRCode
Set QRCO = Factory.CreateQRCode(QRCD)
Forms!Formulario1.[Oleobject].Picture = QRCO.GetGraphic(5)
End Sub
Public Sub InitiateProperties(Data As QRCodeData)
//I declared it as Variant since QRCode is not avaliable
Dim m_data As Variant
m_data = Data
End Sub
This is in another module[I use this modules to create the object with parameters] Pass arguments to Constructor in VBA
Public Function CreateQRCode(Data As QRCodeData) As QRCode
//you see the word new is missing If I run it it says "An object is required"
Set CreateQRCode = QRCode
CreateQRCode.InitiateProperties Data:=Data
End Function
How could I modify it to be usable from microsoft access 2013?
Is another way to do it with no interfaces?
Does access supports bitmaps in vba?
I'm very new with all this stuff so thank you so much.
EDIT:
THE REASON WHY I COULD'T MAKE IT WORK WAS COM VISIBLE DOESN´T SUPPORT CONSTRUCTORS WITH PARAMETERS, AND METHODS WITH OVERRIDES. THE ANSWER THEN IS HOW I WAS ABLE TO CREATE THE IMAGES ANYWAY.

Your COM object can't be created because the class doesn't have a default constructor. Rather than trying to expose the original API, you should create a single class with the methods matching your needs:
VBA usage:
Public Sub QRCreator(text As String)
Dim qrc As New QRCoder.QRCodeGenerator
Forms!Formulario1.[Oleobject].Picture = qrc.Create(text, CCLevel_Q, 5)
End Sub
.Net :
[Guid("C7CC4CA0-813A-431E-B92C-842A07735E72")]
[ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface _QRCodeGenerator {
public IStdPicture Create(string text, int cclevel, int pixelsPerModule);
}
[ProgId("QRCoder.QRCodeGenerator")]
[Guid("4DC2C1F8-2727-4120-80E1-8475650D8547")]
[ComVisible(true), ClassInterface(ClassInterfaceType.None)]
[Description("...")]
public class QRCodeGenerator : _QRCodeGenerator, IDisposable {
private QRCoder.QRCodeGenerator instance;
public QRCodeGenerator() {
instance = new QRCoder.QRCodeGenerator();
}
public IStdPicture Create(string text, int cclevel, int pixelsPerModule){
var qrCodeData = instance.CreateQrCode(text, cclevel);
var qrCode = new QRCoder.QRCode(qrCodeData);
var bitmap = qrCode.GetGraphic(pixelsPerModule);
return ImageToPicture(bitmap);
}
public void Dispose() {
instance.Dispose();
}
private static IStdPicture ImageToPicture(Bitmap bitmap) {
...
}
}

Well After checking, trying and failing I decided to change my perspective. So I did this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Interop;
using System.Runtime.InteropServices;
using stdole;
namespace QRCoder
{
[Guid("52724C82-F18C-460B-B48D-1F19E016F86E")]
[ComVisible (true) , InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IQRCodeGene
{
string Create(string text, QRCodeGenerator.ECCLevel value, int pixelsPerModule);
}
[Guid("4F445AA5-D642-438B-A69A-429D621A3CB0")]
[ComVisible (true), ClassInterface(ClassInterfaceType.None)]
public class QRCodeGene: IQRCodeGene, IDisposable
{
private QRCodeGenerator Instance;
public QRCodeGene()
{
Instance = new QRCodeGenerator();
}
public string Create(string text, QRCodeGenerator.ECCLevel value, int pixelsPerModule)
{
var qrCodeData = Instance.CreateQrCode(text, value);
var qrCode = new QRCode(qrCodeData);
var bitmap = qrCode.GetGraphic(pixelsPerModule);
// This line is the only modified by the provided in the code above.
bitmap.Save("C:\\"+text+".bmp", System.Drawing.Imaging.ImageFormat.Bmp);
//I return this string for testing. I guess If removed the text wouldn't work.
return ("Hello");
}
public void Dispose()
{
Instance.Dispose();
}
}
}
The code above generates the QRCode of anything I would send trough this function in access VBA:
Public Sub QR(Text As String)
Dim QRC As New QRCodeGene
Dim x As String
x = QRC.Create(Text, ECCLevel_Q, 5)
End Sub
After that I just load the picture generated with and access.image control source.
Thanks Florent B. for providing this code.

Related

Is there a better way in C# to reserve long variable name?

var test = Class1.Subclass1.Subclass2.PropertyNameWhichIsBigName
I have to use above in many places. How to avoid typing or save few key stroke? is there any shortcut in C#
Yes, you can use Namespace aliases:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/namespaces/using-namespaces
using ShortName = Class1.Subclass1.Subclass2;
And then
var test = ShortName.PropertyNameWhichIsBigName;
How about a function:
Func<typeOfProperty> someName = () => Class1.Subclass1.Subclass2.PropertyNameWhichIsBigName;
if you now call
var test = someName();
you would get your desired value without having to type the long chain of properties all the time.
Edit:
Just to be clear, if PropertyNameWhichIsBigName changes, someName() will return the new value.
You can use namespace aliasing and just call it in namespaces section in your code, and you can effectively use objects and functions all over the body #canton7 has already written example for that.
or you can use code blocks statements but you have to implement IDisposable, but this can limit your object calling section but you can get benefit fit automatic dispose.
class Class1
{
public class Subclass1
{
public class Subclass2 : IDisposable
{
public string PropertyNameWhichIsBigName { get; set; }
public void Dispose()
{
throw new NotImplementedException();
}
}
}
}
class Program
{
static void Main(string[] args)
{
using (Class1.Subclass1.Subclass2 obj = new Class1.Subclass1.Subclass2())
{
string propertiesValue = obj.PropertyNameWhichIsBigName;
}
}
}

Creating a callable function in a VSTO office addin - COMAddIns.Object is always Nothing

I want to be able to call a function in a VSTO addin from an Excel VBA macro. To test the principle I have the following C# code.
namespace ExcelAddIn1
{
[ComVisible(true)]
public interface IThisAddIn
{
String GetText();
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public partial class ThisAddIn : IThisAddIn
{
public String GetText()
{
return "Now is the winter of dicontent made glorius summer by this son of York";
}
}
}
And I have the following VBA script
Public Sub RunTest()
Dim txt As String
Dim AddInList As Object
Dim ExcelAddIn1 As COMAddIn
Dim ThisAddIn As Object
Set ExcelAddIn1 = Application.COMAddIns("ExcelAddIn1")
txt = ExcelAddIn1.Object.GetText()
Sheets(1).Cells(2, 1).Value = txt
End Sub
ExcelAddIn1.Object = Nothing
The Microsoft walkthrough at https://learn.microsoft.com/en-gb/visualstudio/vsto/walkthrough-calling-code-in-a-vsto-add-in-from-vba seems to be a bit muddled.
I think I might need to add RequestComAddInAutomationService but it doesn't work as described in the walkthrough. When I try to instantiate an instance of my class within RequestComAddInAutomationService I get the error basically telling me I need to supply an ApplicationFactory and IServiceProvider as parameters.
private ThisAddIn utilities;
protected override object RequestComAddInAutomationService()
{
if (utilities == null)
utilities = new ThisAddIn();
return utilities;
}
The class derived from IThisAddIn must be different of the main vsto class (as in the microsoft example) so just replace your code with:
[ComVisible(true)]
public interface IComAddIn
{
String GetText();
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class AddInUtilities : IComAddIn
{
public String GetText()
{
return "Now is the winter of dicontent made glorius summer by this son of York";
}
}
in vsto:
public partial class ThisAddIn
{
private AddInUtilities utilities;
protected override object RequestComAddInAutomationService()
{
if (utilities == null)
utilities = new AddInUtilities();
return utilities;
}
....
Also when you call Application.COMAddIns in VBA, be sure that the string you give as argument correspond to the AssemblyTitle of your vsto project.
PS there is no need to "register for com interop".

c# access to central data

my Situation:
I've got a lot of Data which i need in every corner of my program. Something like Data Paths and so on. I need those informations in various classes.
What is the best way to implement that?
Sample:
class A
{
public string GetPath()
{
return "C:\\";
}
}
class B
{
private void sample()
{
A ab = new A();
string path = ab.GetPath();
}
}
class C
{
private void sample()
{
A ab = new A();
string path = ab.GetPath();
}
}
So in my case i always need to initiate A and A always need to work inside the function "GetPath".
I want to prevent that the "GetPath"-Function always will be processed.
Sounds like dependency injection may be a relevant concept to look into. There are lots of tools and frameworks to help you with advanced versions of this, but the core principle is as follows:
Simplified example:
An interface do declare what you need, without specifying how it will be provided:
interface IDataProvider {
string GetPath();
}
An implementing class to provide it (could be completely different, so long as it implements the interface correctly):
public class DataProvider : IDataProvider(){
private string _path = "";
public GetPath()
{
// Load only first time
if (string.IsNullOrEmpty(_path))
{
// You could return a hard-coded value, like this, or fetch
// data in a more flexible way (config? DB? Web-service? ...?)
_path = #"C:\...";
}
return _path;
}
}
Now pass the implementation in as an instance of the interface wherever you need it:
class C {
IDataProvider _dataProvider;
public C(IDataProvider provider)
{
// This has no knowledge about DataProvider, it only cares
// about this being an instance of an object that implements
// the signature "GetPath()":
_dataProvider = provider;
}
private void Sample()
{
string path = _dataProvider.GetPath();
}
}
Now, from wherever you start up your project:
public class StartApp
{
IDataprovider prov = new DataProvider();
C myC = new C(prov);
myC.Sample();
// ..and similarly for other components,
// use the same Provider-instance:
D yourD = new D(prov);
ED yourE = new E(prov);
}
You could also read config-values from files or a database, or whatever you like in DataProvider. The point here is to fetch the data once, and then use it everywhere via a shared instance.
As BWA says in comments, you should be using a static class for A. In example:
static class A
{
public static string GetPath()
{
return "C:\\";
}
}
A static class, function or variable is one where there is only one within the program, so can be accessed from anywhere. You cannot, however, declare instances of a static class. To access this function, use the following:
string path = A.GetPath();
If you need to declare instances of this class, use a static function or variable to store the path variable instead.
What About encapsulate it before for more secure against sof exception.
not tested code
private string getPath;
public string GetPath
{
get => getPath; set => getPath=value;
}

Inheritance in c# and object creation in c#

I have classes as follow one is SuperClass which is inherited by ChildClass and Child1Class
public class SuperClass
{
public new int Superclassprop = 2;
public virtual void play()
{
Console.WriteLine("SuperClass");
}
}
public class ChildClass : SuperClass
{
public new int Childclassprop = 2;
public override void play()
{
Console.WriteLine("ChildClass");
}
}
public class Child1Class : SuperClass
{
public new int Childclassprop = 3;
public override void play()
{
Console.WriteLine("Child1Class");
}
}
Now when i create an object something like below i don't understand what is the difference between these. i had read a huge bunch of blogs related to this but i didn't find any justifiable answer please help me to understand what actually is happening here or suggest me a good blog or article including on SO where i can understand a whole concept behind this why we need this where the actual real time use of these concept?
SuperClass obj = new SuperClass();
SuperClass obj1 = new ChildClass();
I have attached screenshot of watch which is generating on Run-Time why there is a obj1 consisting all properties but i can access only SuperClassprop?
Thanks in advance any help will be really appreciated.
Here is the more practical example of your topic:
using System;
public class Music
{
public virtual string play()
{
return "Play Music";
}
}
public class Drum : Music
{
public override string play()
{
return "Play Drums";
}
}
public class Piano : Music
{
public override string play()
{
return "Play Piano";
}
}
public class PlayMusicService
{
private readonly Music _musicContext;
public PlayMusicService(Music musicContext)
{
this._musicContext = musicContext;
}
public string PlayAlbum()
{
return _musicContext.play();
}
}
public class Program
{
public static void Main()
{
string whatPlayed = "";
Drum drums = new Drum();
PlayMusicService music1 = new PlayMusicService(new Drum());
whatPlayed = music1.PlayAlbum();
Console.WriteLine(whatPlayed);
Piano piano = new Piano();
PlayMusicService music2 = new PlayMusicService(new Piano());
whatPlayed = music2.PlayAlbum();
Console.WriteLine(whatPlayed);
}
}
Output:
Play Drums
Play Piano
i don't understand what is the difference between these.
One of the main differences is the constructor call
SuperClass obj = new SuperClass();
SuperClass obj1 = new ChildClass();
In the case of obj1 the ChildClass constructor is called after the SuperClass constructor and the field and property initialisation is done also for the property Childclassprop
consisting all properties but i can access only SuperClassprop?
The variable obj1 is still of type SuperClassprop so at compile time you are only allowed to see and use those variables that belong to this class. If you want to actually access the variables of ChildClass you will have to cast it to the proper type:
var r = (obj1 as ChildClass).Childclassproput;
why we need this where the actual real time use of these concept?
One scenario that comes to my mind is : it might be that at compile time it is not clear which class has to be instantiated. But this is decided at runtime. But you need already a variable to write the call of the specific play() method. At runtime it will be decided which method is called in the end.
SuperClass obj = new SuperClass();
bool condition = false;
if (condition)
{
obj = new ChildClass();
}
else
{
obj = new ChildClass1();
}
// now just call the method and the proper method will be called
obj.play();

Exposing C# Code to VBA GetAutomationMethod Error

I am a relatively new coder and have never worked with C# or VBA before. I am currently trying to expose my C# code to VBA. I have been following the MSDN guide on how to do that.
I am running into an error when it comes to overriding my method:
public class AsynchronousClient : IAsynchronousClient {
protected override object GetAutomationObject(){
return this;
}
}
The error is:
'AsynchronousClient.GetAutomationObject()': no suitable method found to override.
I have been able to extract the interface and added the COMVisibleAttributes to my interface.
Any help or additional guidance on how to amend the code would be appreciated.
As mentioned by others, the steps you're following are specific to the VSTO technology, not for creating a DLL to use with VBA. Quite honestly, if you've never coded in either language before, this is probably not the best thing to start with...
Start with a Class project. You need GUIDs. You need an Interface, which your class needs to implement. And you need to specify how the class should work with the Interface. It needs to be set to the Type "None" for the Intellisense, etc. to work. The DLL needs to be COM-registered, as well.
Here's some test code I use, to give you an idea how the code part looks
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using vbForm = Microsoft.Vbe.Interop.Forms;
using office = Microsoft.Office.Core;
//[assembly: Guid("B5C4D7F5-C9B2-491e-91BA-63C208959190")]
namespace COM_ClassLib_CS
{
[Guid("BF78EB64-F59B-4086-9FC5-B87AA2002F4F")]
[ComVisible(true)]
public interface IVBAExtensions
{
string getTest(object app);
void formData(object formControl);
void passWordDoc(object doc);
object[,] returnArray();
string returnString();
}
[Guid("EC0B623E-E8A0-4564-84FB-2D8D149C8BA7")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
public class VBAExtensions : IVBAExtensions
{
public VBAExtensions()
{
}
//test using late-binding
public string getTest(object app)
{
object xlApp = app.GetType().InvokeMember("Application", System.Reflection.BindingFlags.GetProperty, null,
app, null);
object nm = xlApp.GetType().InvokeMember("Name", System.Reflection.BindingFlags.GetProperty, null,
xlApp, null);
string appName = nm.ToString();
object isReady = xlApp.GetType().InvokeMember("Ready", System.Reflection.BindingFlags.GetProperty, null,
xlApp, null);
string sReady = isReady.ToString();
return sReady;
}
//test calling from a UserForm, passing control as argument
public void formData(object formControl)
{
//string data = "";
vbForm.TextBox t = formControl as vbForm.TextBox;
t.Text = "test";
//return data;
}
//test passing doc object and accessing its Window
public void passWordDoc(object doc)
{
Microsoft.Office.Interop.Word.Document WordDoc = doc as Microsoft.Office.Interop.Word.Document;
WordDoc.ActiveWindow.Caption = "Tested!";
}
//test returning an array to VBA calling procedure
public object[,] returnArray()
{
//object[] array = new object[2] {"a", "b"};
object[,] array = new object[2, 2];
array[0, 0] = "a";
array[0, 1] = "1";
array[1, 0] = "b";
array[1, 1] = "2";
return array;
}
//test returning a string to VBA calling procedure
public string returnString()
{
return "AbC";
}
}
}
For more information you can reference https://msdn.microsoft.com/en-us/library/c3fd4a20.aspx and https://msdn.microsoft.com/en-us/library/ms973802.aspx
Your AsynchronousClient class is implementing the IAsynchronousClient interface, which I presume looks like this:
public interface IAsynchronousClient
{
object GetAutomationObject();
}
You would implement it like this:
public class AsynchronousClient : IAsynchronousClient
{
public object GetAutomationObject()
{
return this;
}
}
The error message says exactly what the problem is: there's nothing to override there. You use the override method when you're implementing abstract or virtual methods, not interface members.
Remove the override keyword and you'll be good. Below snippets show situations where override would be applicable:
public abstract class AsynchronousClientBase
{
public abstract object GetAutomationObject();
public virtual object GetFoo()
{
return null;
}
}
public class AsynchronousClient : AsynchronousClientBase
{
public override object GetAutomationObject()
{
return this;
}
public override object GetFoo()
{
return new Foo();
}
}
The MSDN article you linked to says to "Override the GetAutomationObject method of a host item class in your project" - this implies your type should be derived from a base class that defines a virtual or abstract GetAutomationObject method.

Categories